JS: Add test for flow summaries

This commit is contained in:
Asger F
2023-10-05 14:54:41 +02:00
parent af05789cbf
commit 92812eee78
8 changed files with 593 additions and 0 deletions

View File

@@ -0,0 +1,17 @@
uniqueToString
uniqueEnclosingCallable
uniqueDominator
localDominator
localSuccessor
uniqueDefiningScope
variableIsCaptured
uniqueLocation
uniqueCfgNode
uniqueWriteTarget
uniqueWriteCfgNode
uniqueReadVariable
closureMustHaveBody
closureAliasMustBeInSameScope
variableAccessAstNesting
uniqueCallableLocation
consistencyOverview

View File

@@ -0,0 +1 @@
import semmle.javascript.dataflow.internal.VariableCapture::VariableCaptureOutput::ConsistencyChecks

View File

@@ -0,0 +1,230 @@
uniqueEnclosingCallable
uniqueCallEnclosingCallable
uniqueType
uniqueNodeLocation
missingLocation
uniqueNodeToString
| file://:0:0:0:0 | (no string representation) | Node should have one toString but has 0. |
| file://:0:0:0:0 | (no string representation) | Node should have one toString but has 0. |
| file://:0:0:0:0 | (no string representation) | Node should have one toString but has 0. |
| file://:0:0:0:0 | (no string representation) | Node should have one toString but has 0. |
| file://:0:0:0:0 | (no string representation) | Node should have one toString but has 0. |
| file://:0:0:0:0 | (no string representation) | Node should have one toString but has 0. |
| file://:0:0:0:0 | (no string representation) | Node should have one toString but has 0. |
| file://:0:0:0:0 | (no string representation) | Node should have one toString but has 0. |
| file://:0:0:0:0 | (no string representation) | Node should have one toString but has 0. |
| file://:0:0:0:0 | (no string representation) | Node should have one toString but has 0. |
| file://:0:0:0:0 | (no string representation) | Node should have one toString but has 0. |
| file://:0:0:0:0 | (no string representation) | Node should have one toString but has 0. |
| file://:0:0:0:0 | (no string representation) | Node should have one toString but has 0. |
| file://:0:0:0:0 | (no string representation) | Node should have one toString but has 0. |
| file://:0:0:0:0 | (no string representation) | Node should have one toString but has 0. |
| file://:0:0:0:0 | (no string representation) | Node should have one toString but has 0. |
| file://:0:0:0:0 | (no string representation) | Node should have one toString but has 0. |
| file://:0:0:0:0 | (no string representation) | Node should have one toString but has 0. |
| file://:0:0:0:0 | (no string representation) | Node should have one toString but has 0. |
| file://:0:0:0:0 | (no string representation) | Node should have one toString but has 0. |
| file://:0:0:0:0 | (no string representation) | Node should have one toString but has 0. |
| file://:0:0:0:0 | (no string representation) | Node should have one toString but has 0. |
parameterCallable
localFlowIsLocal
readStepIsLocal
storeStepIsLocal
compatibleTypesReflexive
unreachableNodeCCtx
localCallNodes
postIsNotPre
postHasUniquePre
uniquePostUpdate
postIsInSameCallable
reverseRead
| tst.js:109:11:113:3 | 'arguments' object of anonymous function | Origin of readStep is missing a PostUpdateNode. |
| tst.js:267:28:267:31 | map3 | Origin of readStep is missing a PostUpdateNode. |
argHasPostUpdate
| tst.js:219:18:219:27 | [source()] | ArgumentNode is missing PostUpdateNode. |
postWithInFlow
| file://:0:0:0:0 | [summary] to write: Argument[1] in Array method with flow into callback | PostUpdateNode should not be the target of local flow. |
| file://:0:0:0:0 | [summary] to write: Argument[1] in Array#filter | PostUpdateNode should not be the target of local flow. |
| file://:0:0:0:0 | [summary] to write: Argument[1] in Array#find / Array#findLast | PostUpdateNode should not be the target of local flow. |
| file://:0:0:0:0 | [summary] to write: Argument[1] in Array#flatMap | PostUpdateNode should not be the target of local flow. |
| file://:0:0:0:0 | [summary] to write: Argument[1] in Array#forEach / Map#forEach / Set#forEach | PostUpdateNode should not be the target of local flow. |
| file://:0:0:0:0 | [summary] to write: Argument[1] in Array#map | PostUpdateNode should not be the target of local flow. |
| file://:0:0:0:0 | [summary] to write: Argument[1] in Array#reduce / Array#reduceRight | PostUpdateNode should not be the target of local flow. |
| file://:0:0:0:0 | [summary] to write: Argument[2] in 'array.prototype.find' / 'array-find' | PostUpdateNode should not be the target of local flow. |
| file://:0:0:0:0 | [summary] to write: Argument[2] in Array.from(arg, callback, [thisArg]) | PostUpdateNode should not be the target of local flow. |
| file://:0:0:0:0 | [summary] to write: Argument[this] in Array#flatMap | PostUpdateNode should not be the target of local flow. |
| file://:0:0:0:0 | [summary] to write: Argument[this] in Array#forEach / Map#forEach / Set#forEach | PostUpdateNode should not be the target of local flow. |
| file://:0:0:0:0 | [summary] to write: Argument[this] in Array#map | PostUpdateNode should not be the target of local flow. |
| file://:0:0:0:0 | [summary] to write: Argument[this] in Array#reduce / Array#reduceRight | PostUpdateNode should not be the target of local flow. |
| tst.js:97:24:97:74 | new Pro ... rce())) | PostUpdateNode should not be the target of local flow. |
| tst.js:100:3:100:53 | new Pro ... rce())) | PostUpdateNode should not be the target of local flow. |
| tst.js:101:3:101:53 | new Pro ... rce())) | PostUpdateNode should not be the target of local flow. |
| tst.js:102:3:102:52 | new Pro ... rce())) | PostUpdateNode should not be the target of local flow. |
| tst.js:103:3:103:52 | new Pro ... rce())) | PostUpdateNode should not be the target of local flow. |
| tst.js:250:15:250:23 | new Map() | PostUpdateNode should not be the target of local flow. |
| tst.js:258:16:258:24 | new Map() | PostUpdateNode should not be the target of local flow. |
| tst.js:264:16:264:24 | new Map() | PostUpdateNode should not be the target of local flow. |
viableImplInCallContextTooLarge
uniqueParameterNodeAtPosition
uniqueParameterNodePosition
uniqueContentApprox
identityLocalStep
missingArgumentCall
multipleArgumentCall
| tst.js:30:8:30:37 | flowInt ... urce()) | tst.js:30:8:30:41 | flowInt ... ()).pop (as accessor call) | Multiple calls for argument node. |
| tst.js:30:8:30:37 | flowInt ... urce()) | tst.js:30:8:30:43 | flowInt ... ).pop() | Multiple calls for argument node. |
| tst.js:32:39:32:42 | Math | tst.js:32:39:32:49 | Math.random (as accessor call) | Multiple calls for argument node. |
| tst.js:32:39:32:42 | Math | tst.js:32:39:32:51 | Math.random() | Multiple calls for argument node. |
| tst.js:54:25:54:31 | Promise | tst.js:54:25:54:39 | Promise.resolve (as accessor call) | Multiple calls for argument node. |
| tst.js:54:25:54:31 | Promise | tst.js:54:25:54:49 | Promise ... urce()) | Multiple calls for argument node. |
| tst.js:55:25:55:31 | Promise | tst.js:55:25:55:39 | Promise.resolve (as accessor call) | Multiple calls for argument node. |
| tst.js:55:25:55:31 | Promise | tst.js:55:25:55:47 | Promise ... "safe") | Multiple calls for argument node. |
| tst.js:55:25:55:47 | Promise ... "safe") | tst.js:55:25:55:52 | Promise ... ").then (as accessor call) | Multiple calls for argument node. |
| tst.js:55:25:55:47 | Promise ... "safe") | tst.js:55:25:55:67 | Promise ... urce()) | Multiple calls for argument node. |
| tst.js:56:25:56:31 | Promise | tst.js:56:25:56:39 | Promise.resolve (as accessor call) | Multiple calls for argument node. |
| tst.js:56:25:56:31 | Promise | tst.js:56:25:56:47 | Promise ... "safe") | Multiple calls for argument node. |
| tst.js:56:25:56:47 | Promise ... "safe") | tst.js:56:25:56:52 | Promise ... ").then (as accessor call) | Multiple calls for argument node. |
| tst.js:56:25:56:47 | Promise ... "safe") | tst.js:56:25:56:65 | Promise ... "safe") | Multiple calls for argument node. |
| tst.js:57:25:57:31 | Promise | tst.js:57:25:57:39 | Promise.resolve (as accessor call) | Multiple calls for argument node. |
| tst.js:57:25:57:31 | Promise | tst.js:57:25:57:49 | Promise ... urce()) | Multiple calls for argument node. |
| tst.js:57:25:57:49 | Promise ... urce()) | tst.js:57:25:57:54 | Promise ... )).then (as accessor call) | Multiple calls for argument node. |
| tst.js:57:25:57:49 | Promise ... urce()) | tst.js:57:25:57:67 | Promise ... "safe") | Multiple calls for argument node. |
| tst.js:59:25:59:31 | Promise | tst.js:59:25:59:38 | Promise.reject (as accessor call) | Multiple calls for argument node. |
| tst.js:59:25:59:31 | Promise | tst.js:59:25:59:48 | Promise ... urce()) | Multiple calls for argument node. |
| tst.js:60:25:60:31 | Promise | tst.js:60:25:60:38 | Promise.reject (as accessor call) | Multiple calls for argument node. |
| tst.js:60:25:60:31 | Promise | tst.js:60:25:60:48 | Promise ... urce()) | Multiple calls for argument node. |
| tst.js:60:25:60:48 | Promise ... urce()) | tst.js:60:25:60:53 | Promise ... )).then (as accessor call) | Multiple calls for argument node. |
| tst.js:60:25:60:48 | Promise ... urce()) | tst.js:60:25:60:74 | Promise ... y => y) | Multiple calls for argument node. |
| tst.js:61:25:61:31 | Promise | tst.js:61:25:61:38 | Promise.reject (as accessor call) | Multiple calls for argument node. |
| tst.js:61:25:61:31 | Promise | tst.js:61:25:61:48 | Promise ... urce()) | Multiple calls for argument node. |
| tst.js:61:25:61:48 | Promise ... urce()) | tst.js:61:25:61:53 | Promise ... )).then (as accessor call) | Multiple calls for argument node. |
| tst.js:61:25:61:48 | Promise ... urce()) | tst.js:61:25:61:74 | Promise ... "safe") | Multiple calls for argument node. |
| tst.js:62:25:62:31 | Promise | tst.js:62:25:62:38 | Promise.reject (as accessor call) | Multiple calls for argument node. |
| tst.js:62:25:62:31 | Promise | tst.js:62:25:62:46 | Promise ... "safe") | Multiple calls for argument node. |
| tst.js:62:25:62:46 | Promise ... "safe") | tst.js:62:25:62:51 | Promise ... ").then (as accessor call) | Multiple calls for argument node. |
| tst.js:62:25:62:46 | Promise ... "safe") | tst.js:62:25:62:67 | Promise ... y => y) | Multiple calls for argument node. |
| tst.js:64:25:64:31 | Promise | tst.js:64:25:64:38 | Promise.reject (as accessor call) | Multiple calls for argument node. |
| tst.js:64:25:64:31 | Promise | tst.js:64:25:64:48 | Promise ... urce()) | Multiple calls for argument node. |
| tst.js:65:25:65:31 | Promise | tst.js:65:25:65:38 | Promise.reject (as accessor call) | Multiple calls for argument node. |
| tst.js:65:25:65:31 | Promise | tst.js:65:25:65:48 | Promise ... urce()) | Multiple calls for argument node. |
| tst.js:65:25:65:48 | Promise ... urce()) | tst.js:65:25:65:54 | Promise ... ).catch (as accessor call) | Multiple calls for argument node. |
| tst.js:65:25:65:48 | Promise ... urce()) | tst.js:65:25:65:66 | Promise ... => err) | Multiple calls for argument node. |
| tst.js:66:25:66:31 | Promise | tst.js:66:25:66:38 | Promise.reject (as accessor call) | Multiple calls for argument node. |
| tst.js:66:25:66:31 | Promise | tst.js:66:25:66:48 | Promise ... urce()) | Multiple calls for argument node. |
| tst.js:66:25:66:48 | Promise ... urce()) | tst.js:66:25:66:54 | Promise ... ).catch (as accessor call) | Multiple calls for argument node. |
| tst.js:66:25:66:48 | Promise ... urce()) | tst.js:66:25:66:69 | Promise ... "safe") | Multiple calls for argument node. |
| tst.js:67:25:67:31 | Promise | tst.js:67:25:67:38 | Promise.reject (as accessor call) | Multiple calls for argument node. |
| tst.js:67:25:67:31 | Promise | tst.js:67:25:67:46 | Promise ... "safe") | Multiple calls for argument node. |
| tst.js:67:25:67:46 | Promise ... "safe") | tst.js:67:25:67:52 | Promise ... ).catch (as accessor call) | Multiple calls for argument node. |
| tst.js:67:25:67:46 | Promise ... "safe") | tst.js:67:25:67:64 | Promise ... => err) | Multiple calls for argument node. |
| tst.js:69:25:69:31 | Promise | tst.js:69:25:69:38 | Promise.reject (as accessor call) | Multiple calls for argument node. |
| tst.js:69:25:69:31 | Promise | tst.js:69:25:69:48 | Promise ... urce()) | Multiple calls for argument node. |
| tst.js:69:25:69:48 | Promise ... urce()) | tst.js:69:25:69:53 | Promise ... )).then (as accessor call) | Multiple calls for argument node. |
| tst.js:69:25:69:48 | Promise ... urce()) | tst.js:69:25:69:66 | Promise ... "safe") | Multiple calls for argument node. |
| tst.js:69:25:69:66 | Promise ... "safe") | tst.js:69:25:69:72 | Promise ... ).catch (as accessor call) | Multiple calls for argument node. |
| tst.js:69:25:69:66 | Promise ... "safe") | tst.js:69:25:69:84 | Promise ... => err) | Multiple calls for argument node. |
| tst.js:71:25:71:31 | Promise | tst.js:71:25:71:38 | Promise.reject (as accessor call) | Multiple calls for argument node. |
| tst.js:71:25:71:31 | Promise | tst.js:71:25:71:48 | Promise ... urce()) | Multiple calls for argument node. |
| tst.js:71:25:71:48 | Promise ... urce()) | tst.js:71:25:71:56 | Promise ... finally (as accessor call) | Multiple calls for argument node. |
| tst.js:71:25:71:48 | Promise ... urce()) | tst.js:71:25:71:70 | Promise ... "safe") | Multiple calls for argument node. |
| tst.js:71:25:71:70 | Promise ... "safe") | tst.js:71:25:71:76 | Promise ... ).catch (as accessor call) | Multiple calls for argument node. |
| tst.js:71:25:71:70 | Promise ... "safe") | tst.js:71:25:71:88 | Promise ... => err) | Multiple calls for argument node. |
| tst.js:72:25:72:31 | Promise | tst.js:72:25:72:39 | Promise.resolve (as accessor call) | Multiple calls for argument node. |
| tst.js:72:25:72:31 | Promise | tst.js:72:25:72:49 | Promise ... urce()) | Multiple calls for argument node. |
| tst.js:72:25:72:49 | Promise ... urce()) | tst.js:72:25:72:57 | Promise ... finally (as accessor call) | Multiple calls for argument node. |
| tst.js:72:25:72:49 | Promise ... urce()) | tst.js:72:25:72:71 | Promise ... "safe") | Multiple calls for argument node. |
| tst.js:72:25:72:71 | Promise ... "safe") | tst.js:72:25:72:76 | Promise ... ").then (as accessor call) | Multiple calls for argument node. |
| tst.js:72:25:72:71 | Promise ... "safe") | tst.js:72:25:72:88 | Promise ... => err) | Multiple calls for argument node. |
| tst.js:73:25:73:31 | Promise | tst.js:73:25:73:38 | Promise.reject (as accessor call) | Multiple calls for argument node. |
| tst.js:73:25:73:31 | Promise | tst.js:73:25:73:46 | Promise ... "safe") | Multiple calls for argument node. |
| tst.js:73:25:73:46 | Promise ... "safe") | tst.js:73:25:73:54 | Promise ... finally (as accessor call) | Multiple calls for argument node. |
| tst.js:73:25:73:46 | Promise ... "safe") | tst.js:73:25:73:80 | Promise ... ce() }) | Multiple calls for argument node. |
| tst.js:73:25:73:80 | Promise ... ce() }) | tst.js:73:25:73:86 | Promise ... ).catch (as accessor call) | Multiple calls for argument node. |
| tst.js:73:25:73:80 | Promise ... ce() }) | tst.js:73:25:73:98 | Promise ... => err) | Multiple calls for argument node. |
| tst.js:75:3:75:9 | Promise | tst.js:75:3:75:17 | Promise.resolve (as accessor call) | Multiple calls for argument node. |
| tst.js:75:3:75:9 | Promise | tst.js:75:3:75:25 | Promise ... "safe") | Multiple calls for argument node. |
| tst.js:75:3:75:25 | Promise ... "safe") | tst.js:75:3:76:9 | Promise ... .then (as accessor call) | Multiple calls for argument node. |
| tst.js:75:3:75:25 | Promise ... "safe") | tst.js:75:3:76:35 | Promise ... e(); }) | Multiple calls for argument node. |
| tst.js:75:3:76:35 | Promise ... e(); }) | tst.js:75:3:77:10 | Promise ... .catch (as accessor call) | Multiple calls for argument node. |
| tst.js:75:3:76:35 | Promise ... e(); }) | tst.js:75:3:79:6 | Promise ... \\n }) | Multiple calls for argument node. |
| tst.js:81:3:81:9 | Promise | tst.js:81:3:81:17 | Promise.resolve (as accessor call) | Multiple calls for argument node. |
| tst.js:81:3:81:9 | Promise | tst.js:81:3:81:25 | Promise ... "safe") | Multiple calls for argument node. |
| tst.js:81:3:81:25 | Promise ... "safe") | tst.js:81:3:82:9 | Promise ... .then (as accessor call) | Multiple calls for argument node. |
| tst.js:81:3:81:25 | Promise ... "safe") | tst.js:81:3:82:35 | Promise ... e(); }) | Multiple calls for argument node. |
| tst.js:81:3:82:35 | Promise ... e(); }) | tst.js:81:3:83:9 | Promise ... .then (as accessor call) | Multiple calls for argument node. |
| tst.js:81:3:82:35 | Promise ... e(); }) | tst.js:81:3:83:22 | Promise ... "safe") | Multiple calls for argument node. |
| tst.js:81:3:83:22 | Promise ... "safe") | tst.js:81:3:84:10 | Promise ... .catch (as accessor call) | Multiple calls for argument node. |
| tst.js:81:3:83:22 | Promise ... "safe") | tst.js:81:3:86:6 | Promise ... \\n }) | Multiple calls for argument node. |
| tst.js:89:3:89:27 | flowInt ... urce()) | tst.js:89:3:89:32 | flowInt ... )).then (as accessor call) | Multiple calls for argument node. |
| tst.js:89:3:89:27 | flowInt ... urce()) | tst.js:89:3:89:54 | flowInt ... value)) | Multiple calls for argument node. |
| tst.js:100:3:100:53 | new Pro ... rce())) | tst.js:100:3:100:58 | new Pro ... )).then (as accessor call) | Multiple calls for argument node. |
| tst.js:100:3:100:53 | new Pro ... rce())) | tst.js:100:3:100:72 | new Pro ... ink(x)) | Multiple calls for argument node. |
| tst.js:101:3:101:53 | new Pro ... rce())) | tst.js:101:3:101:59 | new Pro ... ).catch (as accessor call) | Multiple calls for argument node. |
| tst.js:101:3:101:53 | new Pro ... rce())) | tst.js:101:3:101:77 | new Pro ... k(err)) | Multiple calls for argument node. |
| tst.js:102:3:102:52 | new Pro ... rce())) | tst.js:102:3:102:57 | new Pro ... )).then (as accessor call) | Multiple calls for argument node. |
| tst.js:102:3:102:52 | new Pro ... rce())) | tst.js:102:3:102:71 | new Pro ... ink(x)) | Multiple calls for argument node. |
| tst.js:103:3:103:52 | new Pro ... rce())) | tst.js:103:3:103:58 | new Pro ... ).catch (as accessor call) | Multiple calls for argument node. |
| tst.js:103:3:103:52 | new Pro ... rce())) | tst.js:103:3:103:76 | new Pro ... k(err)) | Multiple calls for argument node. |
| tst.js:105:3:105:9 | Promise | tst.js:105:3:105:13 | Promise.all (as accessor call) | Multiple calls for argument node. |
| tst.js:105:3:105:9 | Promise | tst.js:105:3:109:4 | Promise ... e"\\n ]) | Multiple calls for argument node. |
| tst.js:105:3:109:4 | Promise ... e"\\n ]) | tst.js:105:3:109:9 | Promise ... ]).then (as accessor call) | Multiple calls for argument node. |
| tst.js:105:3:109:4 | Promise ... e"\\n ]) | tst.js:105:3:113:4 | Promise ... OK\\n }) | Multiple calls for argument node. |
| tst.js:170:19:170:25 | Promise | tst.js:170:19:170:33 | Promise.resolve (as accessor call) | Multiple calls for argument node. |
| tst.js:170:19:170:25 | Promise | tst.js:170:19:170:38 | Promise.resolve(obj) | Multiple calls for argument node. |
| tst.js:209:3:209:7 | array | tst.js:209:3:209:12 | array.push (as accessor call) | Multiple calls for argument node. |
| tst.js:209:3:209:7 | array | tst.js:209:3:209:38 | array.p ... urce()) | Multiple calls for argument node. |
| tst.js:210:8:210:12 | array | tst.js:210:8:210:16 | array.pop (as accessor call) | Multiple calls for argument node. |
| tst.js:210:8:210:12 | array | tst.js:210:8:210:18 | array.pop() | Multiple calls for argument node. |
| tst.js:213:3:213:8 | array2 | tst.js:213:3:213:13 | array2.push (as accessor call) | Multiple calls for argument node. |
| tst.js:213:3:213:8 | array2 | tst.js:213:3:213:23 | array2. ... urce()) | Multiple calls for argument node. |
| tst.js:214:3:214:8 | array2 | tst.js:214:3:214:13 | array2.push (as accessor call) | Multiple calls for argument node. |
| tst.js:214:3:214:8 | array2 | tst.js:214:3:214:21 | array2.push("safe") | Multiple calls for argument node. |
| tst.js:215:3:215:8 | array2 | tst.js:215:3:215:13 | array2.push (as accessor call) | Multiple calls for argument node. |
| tst.js:215:3:215:8 | array2 | tst.js:215:3:215:21 | array2.push("safe") | Multiple calls for argument node. |
| tst.js:216:3:216:8 | array2 | tst.js:216:3:216:16 | array2.forEach (as accessor call) | Multiple calls for argument node. |
| tst.js:216:3:216:8 | array2 | tst.js:216:3:216:30 | array2. ... ink(x)) | Multiple calls for argument node. |
| tst.js:219:3:219:8 | array3 | tst.js:219:3:219:13 | array3.push (as accessor call) | Multiple calls for argument node. |
| tst.js:219:3:219:8 | array3 | tst.js:219:3:219:28 | array3. ... rce()]) | Multiple calls for argument node. |
| tst.js:220:3:220:8 | array3 | tst.js:220:3:220:16 | array3.forEach (as accessor call) | Multiple calls for argument node. |
| tst.js:220:3:220:8 | array3 | tst.js:220:3:220:30 | array3. ... ink(x)) | Multiple calls for argument node. |
| tst.js:223:12:223:32 | Array.p ... e.slice | tst.js:223:12:223:37 | Array.p ... ce.call (as accessor call) | Multiple calls for argument node. |
| tst.js:223:12:223:32 | Array.p ... e.slice | tst.js:223:12:223:45 | Array.p ... array4) | Multiple calls for argument node. |
| tst.js:223:12:223:32 | Array.p ... e.slice | tst.js:223:12:223:45 | reflective call | Multiple calls for argument node. |
| tst.js:223:39:223:44 | array4 | tst.js:223:12:223:45 | Array.p ... array4) | Multiple calls for argument node. |
| tst.js:223:39:223:44 | array4 | tst.js:223:12:223:45 | reflective call | Multiple calls for argument node. |
| tst.js:224:8:224:13 | array4 | tst.js:224:8:224:17 | array4.pop (as accessor call) | Multiple calls for argument node. |
| tst.js:224:8:224:13 | array4 | tst.js:224:8:224:19 | array4.pop() | Multiple calls for argument node. |
| tst.js:226:3:226:12 | [source()] | tst.js:226:3:226:20 | [source()].forEach (as accessor call) | Multiple calls for argument node. |
| tst.js:226:3:226:12 | [source()] | tst.js:226:3:226:68 | [source ... p()) }) | Multiple calls for argument node. |
| tst.js:226:54:226:58 | array | tst.js:226:54:226:62 | array.pop (as accessor call) | Multiple calls for argument node. |
| tst.js:226:54:226:58 | array | tst.js:226:54:226:64 | array.pop() | Multiple calls for argument node. |
| tst.js:228:3:228:8 | array5 | tst.js:228:3:228:16 | array5.forEach (as accessor call) | Multiple calls for argument node. |
| tst.js:228:3:228:8 | array5 | tst.js:228:3:228:64 | array5. ... p()) }) | Multiple calls for argument node. |
| tst.js:228:50:228:54 | array | tst.js:228:50:228:58 | array.pop (as accessor call) | Multiple calls for argument node. |
| tst.js:228:50:228:54 | array | tst.js:228:50:228:60 | array.pop() | Multiple calls for argument node. |
| tst.js:229:3:229:10 | ["safe"] | tst.js:229:3:229:18 | ["safe"].forEach (as accessor call) | Multiple calls for argument node. |
| tst.js:229:3:229:10 | ["safe"] | tst.js:229:3:229:66 | ["safe" ... p()) }) | Multiple calls for argument node. |
| tst.js:229:52:229:56 | array | tst.js:229:52:229:60 | array.pop (as accessor call) | Multiple calls for argument node. |
| tst.js:229:52:229:56 | array | tst.js:229:52:229:62 | array.pop() | Multiple calls for argument node. |
| tst.js:251:3:251:5 | map | tst.js:251:3:251:9 | map.set (as accessor call) | Multiple calls for argument node. |
| tst.js:251:3:251:5 | map | tst.js:251:3:251:26 | map.set ... urce()) | Multiple calls for argument node. |
| tst.js:252:3:252:5 | map | tst.js:252:3:252:9 | map.set (as accessor call) | Multiple calls for argument node. |
| tst.js:252:3:252:5 | map | tst.js:252:3:252:24 | map.set ... 'safe') | Multiple calls for argument node. |
| tst.js:254:8:254:10 | map | tst.js:254:8:254:14 | map.get (as accessor call) | Multiple calls for argument node. |
| tst.js:254:8:254:10 | map | tst.js:254:8:254:21 | map.get('foo') | Multiple calls for argument node. |
| tst.js:255:8:255:10 | map | tst.js:255:8:255:14 | map.get (as accessor call) | Multiple calls for argument node. |
| tst.js:255:8:255:10 | map | tst.js:255:8:255:21 | map.get('bar') | Multiple calls for argument node. |
| tst.js:256:8:256:10 | map | tst.js:256:8:256:14 | map.get (as accessor call) | Multiple calls for argument node. |
| tst.js:256:8:256:10 | map | tst.js:256:8:256:27 | map.get(getUnkown()) | Multiple calls for argument node. |
| tst.js:259:3:259:6 | map2 | tst.js:259:3:259:10 | map2.set (as accessor call) | Multiple calls for argument node. |
| tst.js:259:3:259:6 | map2 | tst.js:259:3:259:33 | map2.se ... urce()) | Multiple calls for argument node. |
| tst.js:260:8:260:11 | map2 | tst.js:260:8:260:15 | map2.get (as accessor call) | Multiple calls for argument node. |
| tst.js:260:8:260:11 | map2 | tst.js:260:8:260:22 | map2.get('foo') | Multiple calls for argument node. |
| tst.js:261:8:261:11 | map2 | tst.js:261:8:261:15 | map2.get (as accessor call) | Multiple calls for argument node. |
| tst.js:261:8:261:11 | map2 | tst.js:261:8:261:22 | map2.get('bar') | Multiple calls for argument node. |
| tst.js:262:8:262:11 | map2 | tst.js:262:8:262:15 | map2.get (as accessor call) | Multiple calls for argument node. |
| tst.js:262:8:262:11 | map2 | tst.js:262:8:262:28 | map2.ge ... kown()) | Multiple calls for argument node. |
| tst.js:265:3:265:6 | map3 | tst.js:265:3:265:10 | map3.set (as accessor call) | Multiple calls for argument node. |
| tst.js:265:3:265:6 | map3 | tst.js:265:3:265:27 | map3.se ... urce()) | Multiple calls for argument node. |
| tst.js:266:3:266:6 | map3 | tst.js:266:3:266:14 | map3.forEach (as accessor call) | Multiple calls for argument node. |
| tst.js:266:3:266:6 | map3 | tst.js:266:3:266:36 | map3.fo ... value)) | Multiple calls for argument node. |

View File

@@ -0,0 +1,2 @@
import javascript
import semmle.javascript.dataflow.internal.DataFlowImplConsistency::Consistency

View File

@@ -0,0 +1,37 @@
import javascript
import semmle.javascript.dataflow.FlowSummary
class MkSummary extends SummarizedCallable {
private CallExpr mkSummary;
MkSummary() {
mkSummary.getCalleeName() = "mkSummary" and
this =
"mkSummary at " + mkSummary.getFile().getRelativePath() + ":" +
mkSummary.getLocation().getStartLine()
}
override DataFlow::InvokeNode getACall() {
result = mkSummary.flow().(DataFlow::CallNode).getAnInvocation()
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
preservesValue = true and
(
// mkSummary(input, output)
input = mkSummary.getArgument(0).getStringValue() and
output = mkSummary.getArgument(1).getStringValue()
or
// mkSummary([
// [input1, output1],
// [input2, output2],
// ...
// ])
exists(ArrayExpr pair |
pair = mkSummary.getArgument(0).(ArrayExpr).getAnElement() and
input = pair.getElement(0).getStringValue() and
output = pair.getElement(1).getStringValue()
)
)
}
}

View File

@@ -0,0 +1,36 @@
import javascript
import testUtilities.ConsistencyChecking
import Summaries
DataFlow::CallNode getACall(string name) {
result.getCalleeName() = name
or
result.getCalleeNode().getALocalSource() = DataFlow::globalVarRef(name)
}
module ConfigArg implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) { node = getACall("source") }
predicate isSink(DataFlow::Node node) { node = getACall("sink").getAnArgument() }
predicate isBarrier(DataFlow::Node node) {
node.(DataFlow::InvokeNode).getCalleeName().matches("sanitizer_%") or
node = DataFlow::MakeBarrierGuard<BasicBarrierGuard>::getABarrierNode()
}
}
module Configuration = DataFlow::Global<ConfigArg>;
class BasicBarrierGuard extends DataFlow::CallNode {
BasicBarrierGuard() { this = getACall("isSafe") }
predicate blocksExpr(boolean outcome, Expr e) {
outcome = true and e = this.getArgument(0).asExpr()
}
}
class ConsistencyConfig extends ConsistencyConfiguration {
ConsistencyConfig() { this = "ConsistencyConfig" }
override DataFlow::Node getAnAlert() { Configuration::flow(_, result) }
}

View File

@@ -0,0 +1,270 @@
function m1() {
const flowThrough = mkSummary("Argument[0]", "ReturnValue");
sink(flowThrough(source())); // NOT OK
sink(flowThrough(source() + "x")); // OK - we are not tracking taint in this test
sink(flowThrough("x")); // OK
}
function m2() {
const flowIntoProp = mkSummary("Argument[0]", "ReturnValue.Member[prop]");
sink(flowIntoProp(source()).prop); // NOT OK
sink(flowIntoProp(source()).prop2); // OK
sink(flowIntoProp(source())); // OK
}
function m3() {
const flowOutOfProp = mkSummary("Argument[0].Member[prop]", "ReturnValue");
sink(flowOutOfProp({ prop: source() })); // NOT OK
sink(flowOutOfProp({ prop2: source() })); // OK
sink(flowOutOfProp(source())); // OK
const obj = {};
obj.prop = source();
sink(flowOutOfProp(obj)); // NOT OK
sink(obj); // OK
sink(obj.prop); // NOT OK
}
function m4() {
const flowIntoArrayElement = mkSummary("Argument[0]", "ReturnValue.ArrayElement");
sink(flowIntoArrayElement(source()).pop()); // NOT OK
sink(flowIntoArrayElement(source())[0]); // NOT OK [INCONSISTENCY]
sink(flowIntoArrayElement(source())[Math.random()]); // NOT OK
sink(flowIntoArrayElement(source()).prop); // OK
}
function m5() {
const flowOutOfInnerCallback = mkSummary("Argument[0].Parameter[0].Argument[0]", "ReturnValue");
sink(flowOutOfInnerCallback(cb => { cb(source()); })); // NOT OK [INCONSISTENCY]
}
async function m6() {
const flowOutOfPromise = mkSummary("Argument[0].Awaited", "ReturnValue");
const flowIntoPromise = mkSummary("Argument[0]", "ReturnValue.Awaited");
sink(flowOutOfPromise(flowIntoPromise(source()))); // NOT OK (although the synchronous flow is technically not possible)
let data = { prop: source() };
sink(flowOutOfPromise(flowIntoPromise(data)).prop); // NOT OK
sink(flowOutOfPromise(flowIntoPromise(flowIntoPromise(data))).prop); // NOT OK
sink(flowOutOfPromise(flowOutOfPromise(flowIntoPromise(data))).prop); // NOT OK
sink(flowOutOfPromise(data).prop); // NOT OK - because Awaited allows pass-through of a non-promise value
sink(flowIntoPromise(data).prop); // OK - promise object does not have the 'prop' property
sink(flowOutOfPromise(Promise.resolve(source()))); // NOT OK
sink(flowOutOfPromise(Promise.resolve("safe").then(x => source()))); // NOT OK
sink(flowOutOfPromise(Promise.resolve("safe").then(x => "safe"))); // OK
sink(flowOutOfPromise(Promise.resolve(source()).then(x => "safe"))); // OK
sink(flowOutOfPromise(Promise.reject(source()))); // OK
sink(flowOutOfPromise(Promise.reject(source()).then(x => "safe", y => y))); // NOT OK
sink(flowOutOfPromise(Promise.reject(source()).then(x => x, y => "safe"))); // OK
sink(flowOutOfPromise(Promise.reject("safe").then(x => x, y => y))); // OK
sink(flowOutOfPromise(Promise.reject(source()))); // OK
sink(flowOutOfPromise(Promise.reject(source()).catch(err => err))); // NOT OK
sink(flowOutOfPromise(Promise.reject(source()).catch(err => "safe"))); // OK
sink(flowOutOfPromise(Promise.reject("safe").catch(err => err))); // OK
sink(flowOutOfPromise(Promise.reject(source()).then(x => "safe").catch(err => err))); // NOT OK
sink(flowOutOfPromise(Promise.reject(source()).finally(() => "safe").catch(err => err))); // NOT OK
sink(flowOutOfPromise(Promise.resolve(source()).finally(() => "safe").then(err => err))); // NOT OK
sink(flowOutOfPromise(Promise.reject("safe").finally(() => { throw source() }).catch(err => err))); // NOT OK
Promise.resolve("safe")
.then(x => { throw source(); })
.catch(err => {
sink(err); // NOT OK
});
Promise.resolve("safe")
.then(x => { throw source(); })
.then(x => "safe")
.catch(err => {
sink(err); // NOT OK
});
sink(await flowIntoPromise(source())); // NOT OK
flowIntoPromise(source()).then(value => sink(value)); // NOT OK
sink(await flowIntoPromise(flowIntoPromise(source()))); // NOT OK
async function makePromise() {
return source();
}
sink(flowOutOfPromise(makePromise())); // NOT OK
let taintedPromise = new Promise((resolve, reject) => resolve(source()));
sink(flowOutOfPromise(taintedPromise)); // NOT OK
new Promise((resolve, reject) => resolve(source())).then(x => sink(x)); // NOT OK
new Promise((resolve, reject) => resolve(source())).catch(err => sink(err)); // OK
new Promise((resolve, reject) => reject(source())).then(x => sink(x)); // OK
new Promise((resolve, reject) => reject(source())).catch(err => sink(err)); // NOT OK
Promise.all([
flowIntoPromise(source()),
source(),
"safe"
]).then(([x1, x2, x3]) => {
sink(x1); // NOT OK
sink(x2); // NOT OK
sink(x3); // OK
});
}
function m8() {
const flowOutOfCallback = mkSummary("Argument[0].ReturnValue", "ReturnValue");
sink(flowOutOfCallback(() => source())); // NOT OK
sink(flowOutOfCallback((source))); // OK
function sourceCallback() {
return source();
}
sink(flowOutOfCallback(sourceCallback)); // NOT OK
}
function m9() {
const flowIntoCallback = mkSummary("Argument[0]", "Argument[1].Parameter[0]");
sink(flowIntoCallback(source(), x => sink(x))); // NOT OK
sink(flowIntoCallback("safe", x => sink(x))); // OK
sink(flowIntoCallback(source(), x => ignore(x))); // OK
sink(flowIntoCallback("safe", x => ignore(x))); // OK
}
function m10() {
const flowThroughCallback = mkSummary([
["Argument[0]", "Argument[1].Parameter[0]"],
["Argument[1].ReturnValue", "ReturnValue"]
]);
sink(flowThroughCallback(source(), x => x)); // NOT OK
sink(flowThroughCallback(source(), x => "safe")); // OK
sink(flowThroughCallback("safe", x => x)); // OK
sink(flowThroughCallback("safe", x => "safe")); // OK
}
function m11() {
const flowFromSideEffectOnParameter = mkSummary("Argument[0].Parameter[0].Member[prop]", "ReturnValue");
let data = flowFromSideEffectOnParameter(param => {
param.prop = source();
});
sink(data); // NOT OK
function manullyWritten(param) {
param.prop = source();
}
let obj = {};
manullyWritten(obj);
sink(obj.prop); // NOT OK
}
async function m13() {
async function testStoreBack(x) {
(await x).prop = source();
}
const obj = {};
const promise = Promise.resolve(obj);
testStoreBack(promise);
sink(obj.prop); // NOT OK [INCONSISTENCY]
sink(promise.prop); // OK [INCONSISTENCY]
sink((await promise).prop); // NOT OK
const obj2 = {};
testStoreBack(obj2);
sink(obj2.prop);; // NOT OK
}
function m14() {
const flowOutOfAnyArgument = mkSummary("Argument[0..]", "ReturnValue");
sink(flowOutOfAnyArgument(source())); // NOT OK
sink(flowOutOfAnyArgument(source(), "safe", "safe")); // NOT OK
sink(flowOutOfAnyArgument("safe", source(), "safe")); // NOT OK
sink(flowOutOfAnyArgument("safe", "safe", source())); // NOT OK
sink(flowOutOfAnyArgument("safe", "safe", "safe")); // OK
const flowOutOfAnyArgumentExceptFirst = mkSummary("Argument[1..]", "ReturnValue");
sink(flowOutOfAnyArgumentExceptFirst(source())); // OK
sink(flowOutOfAnyArgumentExceptFirst(source(), "safe", "safe")); // OK
sink(flowOutOfAnyArgumentExceptFirst("safe", source(), "safe")); // NOT OK
sink(flowOutOfAnyArgumentExceptFirst("safe", "safe", source())); // NOT OK
sink(flowOutOfAnyArgumentExceptFirst("safe", "safe", "safe")); // OK
const flowIntoAnyParameter = mkSummary("Argument[0]", "Argument[1].Parameter[0..]");
flowIntoAnyParameter(source(), (x1, x2, x3) => sink(x1)); // NOT OK
flowIntoAnyParameter(source(), (x1, x2, x3) => sink(x2)); // NOT OK
flowIntoAnyParameter(source(), (x1, x2, x3) => sink(x3)); // NOT OK
const flowIntoAnyParameterExceptFirst = mkSummary("Argument[0]", "Argument[1].Parameter[1..]");
flowIntoAnyParameterExceptFirst(source(), (x1, x2, x3) => sink(x1)); // OK
flowIntoAnyParameterExceptFirst(source(), (x1, x2, x3) => sink(x2)); // NOT OK
flowIntoAnyParameterExceptFirst(source(), (x1, x2, x3) => sink(x3)); // NOT OK
}
function m15() {
const array = [];
array.push("safe", "safe", source());
sink(array.pop()); // NOT OK
const array2 = [];
array2.push(source());
array2.push("safe");
array2.push("safe");
array2.forEach(x => sink(x)); // NOT OK
const array3 = [];
array3.push(...[source()]);
array3.forEach(x => sink(x)); // NOT OK
const array4 = [source()];
array4 = Array.prototype.slice.call(array4);
sink(array4.pop()); // NOT OK
[source()].forEach((value, index, array) => { sink(array.pop()) }); // NOT OK
const array5 = [source()];
array5.forEach((value, index, array) => { sink(array.pop()) }); // NOT OK
["safe"].forEach((value, index, array) => { sink(array.pop()) }); // OK
}
function m16() {
const array0 = [source(), 'safe', 'safe'];
sink(array0[0]); // NOT OK
sink(array0[1]); // OK
sink(array0[2]); // OK
const array1 = ['safe', source(), 'safe'];
sink(array1[0]); // OK
sink(array1[1]); // NOT OK
sink(array1[2]); // OK
const array2 = ['safe', 'safe', source()];
sink(array2[0]); // OK
sink(array2[1]); // OK
sink(array2[2]); // NOT OK
}
function m17() {
const map = new Map();
map.set('foo', source());
map.set('bar', 'safe');
sink(map.get('foo')); // NOT OK
sink(map.get('bar')); // OK
sink(map.get(getUnkown())); // NOT OK
const map2 = new Map();
map2.set(getUnkown(), source());
sink(map2.get('foo')); // NOT OK
sink(map2.get('bar')); // NOT OK
sink(map2.get(getUnkown())); // NOT OK
const map3 = new Map();
map3.set('foo', source());
map3.forEach(value => sink(value)); // NOT OK
for (let [key, value] of map3) {
sink(value); // NOT OK
}
}