Skip to content

Commit 7e298cf

Browse files
authored
Merge pull request #900 from esben-semmle/js/defuse-default
Approved by xiemaisi
2 parents a48594a + 5ad8336 commit 7e298cf

File tree

17 files changed

+146
-11
lines changed

17 files changed

+146
-11
lines changed

javascript/ql/src/Declarations/DeadStoreOfLocal.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import DeadStore
1919
*/
2020
predicate deadStoreOfLocal(VarDef vd, PurelyLocalVariable v) {
2121
v = vd.getAVariable() and
22-
exists(vd.getSource()) and
22+
(exists(vd.getSource()) or exists(vd.getDestructuringSource())) and
2323
// the definition is not in dead code
2424
exists(ReachableBasicBlock rbb | vd = rbb.getANode()) and
2525
// but it has no associated SSA definition, that is, it is dead

javascript/ql/src/semmle/javascript/DefUse.qll

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import javascript
1212
* <tr><td><code>x = y</code><td><code>x = y</code><td><code>x</code><td><code>y</code></tr>
1313
* <tr><td><code>var a = b</code><td><code>var a = b</code><td><code>a</code><td><code>b</code></tr>
1414
* <tr><td><code>function f { ... }</code><td><code>f</code><td><code>f</code><td><code>function f { ... }</code></tr>
15+
* <tr><td><code>function f ( x = y ){ ... }</code><td><code>x</code><td><code>x</code><td><code>y</code></tr>
1516
* <tr><td><code>class C { ... }</code><td><code>C</code><td><code>C</code><td><code>class C { ... }</code></tr>
1617
* <tr><td><code>namespace N { ... }</code><td><code>N</code><td><code>N</code><td><code>namespace N { ... }</code></tr>
1718
* <tr><td><code>enum E { ... }</code><td><code>E</code><td><code>E</code><td><code>enum E { ... }</code></tr>
@@ -42,6 +43,8 @@ private predicate defn(ControlFlowNode def, Expr lhs, AST::ValueNode rhs) {
4243
exists(EnumMember member | def = member.getIdentifier() |
4344
lhs = def and rhs = member.getInitializer()
4445
)
46+
or
47+
lhs = def and def.(Parameter).getDefault() = rhs
4548
}
4649

4750
/**
@@ -187,9 +190,23 @@ class VarDef extends ControlFlowNode {
187190
* the value that this definition assigns to its target.
188191
*
189192
* This predicate is not defined for `VarDef`s where the source is implicit,
190-
* such as `for-in` loops or parameters.
193+
* such as `for-in` loops, parameters or destructuring assignments.
194+
*/
195+
AST::ValueNode getSource() {
196+
exists(Expr target |
197+
not target instanceof DestructuringPattern and defn(this, target, result)
198+
)
199+
}
200+
201+
/**
202+
* Gets the source that this definition destructs, that is, the
203+
* right hand side of a destructuring assignment.
191204
*/
192-
AST::ValueNode getSource() { defn(this, _, result) }
205+
AST::ValueNode getDestructuringSource() {
206+
exists(Expr target |
207+
target instanceof DestructuringPattern and defn(this, target, result)
208+
)
209+
}
193210

194211
/**
195212
* Holds if this definition of `v` is overwritten by another definition, that is,

javascript/ql/src/semmle/javascript/RangeAnalysis.qll

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,12 @@ module RangeAnalysis {
104104
pragma[noinline]
105105
private predicate hasUniquePredecessor(DataFlow::Node node) {
106106
isRelevant(node) and
107-
strictcount(node.getAPredecessor()) = 1
107+
strictcount(node.getAPredecessor()) = 1 and
108+
// exclude parameters with default values
109+
not exists (Parameter p |
110+
DataFlow::parameterNode(p) = node and
111+
exists(p.getDefault())
112+
)
108113
}
109114

110115
/**

javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -992,7 +992,9 @@ module DataFlow {
992992
* flow through IIFE calls into account.
993993
*/
994994
private AST::ValueNode defSourceNode(VarDef def) {
995-
result = def.getSource() or localArgumentPassing(result, def)
995+
result = def.getSource() or
996+
result = def.getDestructuringSource() or
997+
localArgumentPassing(result, def)
996998
}
997999

9981000
/**
@@ -1002,15 +1004,19 @@ module DataFlow {
10021004
private Node defSourceNode(VarDef def, SsaSourceVariable v) {
10031005
exists(BindingPattern lhs, VarRef r |
10041006
lhs = def.getTarget() and r = lhs.getABindingVarRef() and r.getVariable() = v
1005-
|
1007+
|
10061008
// follow one step of the def-use chain if the lhs is a simple variable reference
10071009
lhs = r and
10081010
result = TValueNode(defSourceNode(def))
10091011
or
10101012
// handle destructuring assignments
1011-
exists(PropertyPattern pp | r = pp.getValuePattern() | result = TPropNode(pp))
1013+
exists(PropertyPattern pp | r = pp.getValuePattern() |
1014+
result = TPropNode(pp) or result = pp.getDefault().flow()
1015+
)
10121016
or
10131017
result = TElementPatternNode(_, r)
1018+
or
1019+
exists(ArrayPattern ap, int i | ap.getElement(i) = r and result = ap.getDefault(i).flow())
10141020
)
10151021
}
10161022

javascript/ql/src/semmle/javascript/dataflow/internal/VariableTypeInference.qll

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,7 @@ private class SsaVarAccessWithNonLocalAnalysis extends SsaVarAccessAnalysis {
5353
exists(VarDef varDef |
5454
varDef = def.(SsaExplicitDefinition).getDef() and
5555
varDef.getSource().flow() = src and
56-
src instanceof CallWithNonLocalAnalyzedReturnFlow and
57-
// avoid relating `v` and `f()` in `var {v} = f();`
58-
not varDef.getTarget() instanceof DestructuringPattern
56+
src instanceof CallWithNonLocalAnalyzedReturnFlow
5957
)
6058
}
6159

@@ -145,7 +143,7 @@ private class AnalyzedParameter extends AnalyzedVarDef, @vardecl {
145143

146144
override DataFlow::AnalyzedNode getRhs() {
147145
getFunction().argumentPassing(this, result.asExpr()) or
148-
result = this.(Parameter).getDefault().analyze()
146+
result = AnalyzedVarDef.super.getRhs()
149147
}
150148

151149
override AbstractValue getAnRhsValue() {

javascript/ql/test/library-tests/DataFlow/flowStep.expected

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,25 @@
121121
| tst.js:103:4:103:16 | [ 19, 23, 0 ] | tst.js:98:11:98:24 | [ x, ...rest ] |
122122
| tst.js:105:1:105:1 | x | tst.js:105:1:105:6 | x ?? y |
123123
| tst.js:105:6:105:6 | y | tst.js:105:1:105:6 | x ?? y |
124+
| tst.js:107:2:113:1 | functio ... v2c;\\n} | tst.js:107:1:113:2 | (functi ... v2c;\\n}) |
125+
| tst.js:108:6:108:38 | v1a | tst.js:109:2:109:4 | v1a |
126+
| tst.js:108:6:108:38 | v1b | tst.js:109:8:109:10 | v1b |
127+
| tst.js:108:6:108:38 | v1c | tst.js:109:14:109:16 | v1c |
128+
| tst.js:108:7:108:9 | v1a | tst.js:108:6:108:38 | v1a |
129+
| tst.js:108:12:108:20 | v1b = o1b | tst.js:108:6:108:38 | v1b |
130+
| tst.js:108:18:108:20 | o1b | tst.js:108:6:108:38 | v1b |
131+
| tst.js:108:23:108:31 | v1c = o1c | tst.js:108:6:108:38 | v1c |
132+
| tst.js:108:29:108:31 | o1c | tst.js:108:6:108:38 | v1c |
133+
| tst.js:108:36:108:38 | o1d | tst.js:108:6:108:32 | {v1a, v ... = o1c} |
134+
| tst.js:111:6:111:38 | v2a | tst.js:112:2:112:4 | v2a |
135+
| tst.js:111:6:111:38 | v2b | tst.js:112:8:112:10 | v2b |
136+
| tst.js:111:6:111:38 | v2c | tst.js:112:14:112:16 | v2c |
137+
| tst.js:111:7:111:9 | v2a | tst.js:111:6:111:38 | v2a |
138+
| tst.js:111:12:111:14 | v2b | tst.js:111:6:111:38 | v2b |
139+
| tst.js:111:18:111:20 | o2b | tst.js:111:6:111:38 | v2b |
140+
| tst.js:111:23:111:25 | v2c | tst.js:111:6:111:38 | v2c |
141+
| tst.js:111:29:111:31 | o2c | tst.js:111:6:111:38 | v2c |
142+
| tst.js:111:36:111:38 | o2d | tst.js:111:6:111:32 | [v2a, v ... = o2c] |
124143
| tst.ts:1:1:1:1 | A | tst.ts:1:11:1:11 | A |
125144
| tst.ts:1:1:1:1 | A | tst.ts:7:1:7:0 | A |
126145
| tst.ts:1:1:5:1 | A | tst.ts:7:1:7:0 | A |

javascript/ql/test/library-tests/DataFlow/incomplete.expected

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,18 @@
4444
| tst.js:98:11:98:24 | x | heap |
4545
| tst.js:99:7:99:18 | y | heap |
4646
| tst.js:101:3:101:16 | z | heap |
47+
| tst.js:108:6:108:38 | v1a | heap |
48+
| tst.js:108:6:108:38 | v1b | heap |
49+
| tst.js:108:6:108:38 | v1c | heap |
50+
| tst.js:108:18:108:20 | o1b | global |
51+
| tst.js:108:29:108:31 | o1c | global |
52+
| tst.js:108:36:108:38 | o1d | global |
53+
| tst.js:111:6:111:38 | v2a | heap |
54+
| tst.js:111:6:111:38 | v2b | heap |
55+
| tst.js:111:6:111:38 | v2c | heap |
56+
| tst.js:111:18:111:20 | o2b | global |
57+
| tst.js:111:29:111:31 | o2c | global |
58+
| tst.js:111:36:111:38 | o2d | global |
4759
| tst.ts:2:14:2:19 | x | namespace |
4860
| tst.ts:3:3:3:8 | setX() | call |
4961
| tst.ts:8:3:8:5 | A.x | heap |

javascript/ql/test/library-tests/DataFlow/sources.expected

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,20 @@
6969
| tst.js:99:9:99:9 | y |
7070
| tst.js:101:7:101:7 | z |
7171
| tst.js:103:4:103:16 | [ 19, 23, 0 ] |
72+
| tst.js:107:2:107:1 | this |
73+
| tst.js:107:2:113:1 | functio ... v2c;\\n} |
74+
| tst.js:108:7:108:9 | v1a |
75+
| tst.js:108:12:108:20 | v1b = o1b |
76+
| tst.js:108:18:108:20 | o1b |
77+
| tst.js:108:23:108:31 | v1c = o1c |
78+
| tst.js:108:29:108:31 | o1c |
79+
| tst.js:108:36:108:38 | o1d |
80+
| tst.js:111:7:111:9 | v2a |
81+
| tst.js:111:12:111:14 | v2b |
82+
| tst.js:111:18:111:20 | o2b |
83+
| tst.js:111:23:111:25 | v2c |
84+
| tst.js:111:29:111:31 | o2c |
85+
| tst.js:111:36:111:38 | o2d |
7286
| tst.ts:1:1:1:0 | this |
7387
| tst.ts:3:3:3:8 | setX() |
7488
| tst.ts:7:1:7:0 | this |

javascript/ql/test/library-tests/DataFlow/tst.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,4 +103,12 @@ var vs2 = ( for (v of o) v ); // generator comprehensions are not analysed
103103
})([ 19, 23, 0 ]);
104104

105105
x ?? y; // flow through short-circuiting operator
106+
107+
(function(){
108+
var {v1a, v1b = o1b, v1c = o1c} = o1d;
109+
v1a + v1b + v1c;
110+
111+
var [v2a, v2b = o2b, v2c = o2c] = o2d;
112+
v2a + v2b + v2c;
113+
});
106114
// semmle-extractor-options: --experimental

javascript/ql/test/library-tests/DefUse/DefUsePair.expected

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,6 @@
3030
| tst.js:7:4:7:6 | --i | tst.js:7:6:7:6 | i |
3131
| tst.js:12:2:12:7 | x = 42 | tst.js:14:9:14:9 | x |
3232
| tst.js:19:11:19:11 | x | tst.js:18:9:18:9 | x |
33+
| tst.js:23:6:23:23 | {a = b, c = d} = e | tst.js:24:2:24:2 | a |
34+
| tst.js:23:6:23:23 | {a = b, c = d} = e | tst.js:24:6:24:6 | c |
35+
| tst.js:26:11:26:11 | a | tst.js:27:2:27:2 | a |

0 commit comments

Comments
 (0)