forked from github/codeql
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDefUse.qll
More file actions
245 lines (227 loc) · 8.78 KB
/
Copy pathDefUse.qll
File metadata and controls
245 lines (227 loc) · 8.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
/** Provides classes and predicates for working with variable definitions and uses. */
import javascript
/**
* Holds if `def` is a CFG node that assigns the value of `rhs` to `lhs`.
*
* This predicate covers four kinds of definitions:
*
* <table border="1">
* <tr><th>Example</th><th><code>def</code></th><th><code>lhs</code></th><th><code>rhs</code></th></tr>
* <tr><td><code>x = y</code><td><code>x = y</code><td><code>x</code><td><code>y</code></tr>
* <tr><td><code>var a = b</code><td><code>var a = b</code><td><code>a</code><td><code>b</code></tr>
* <tr><td><code>function f { ... }</code><td><code>f</code><td><code>f</code><td><code>function f { ... }</code></tr>
* <tr><td><code>function f ( x = y ){ ... }</code><td><code>x</code><td><code>x</code><td><code>y</code></tr>
* <tr><td><code>class C { ... }</code><td><code>C</code><td><code>C</code><td><code>class C { ... }</code></tr>
* <tr><td><code>namespace N { ... }</code><td><code>N</code><td><code>N</code><td><code>namespace N { ... }</code></tr>
* <tr><td><code>enum E { ... }</code><td><code>E</code><td><code>E</code><td><code>enum E { ... }</code></tr>
* <tr><td><code>import x = y</code><td><code>x</code><td><code>x</code><td><code>y</code></tr>
* <tr><td><code>enum { x = y }</code><td><code>x</code><td><code>x</code><td><code>y</code></tr>
* </table>
*
* Note that `def` and `lhs` are not in general the same: the latter
* represents the point where `lhs` is evaluated to an assignable reference,
* the former the point where the value of `rhs` is actually assigned
* to that reference.
*/
private predicate defn(ControlFlowNode def, Expr lhs, AST::ValueNode rhs) {
exists(AssignExpr assgn | def = assgn | lhs = assgn.getTarget() and rhs = assgn.getRhs())
or
exists(VariableDeclarator vd | def = vd | lhs = vd.getBindingPattern() and rhs = vd.getInit())
or
exists(Function f | def = f.getIdentifier() | lhs = def and rhs = f)
or
exists(ClassDefinition c | lhs = c.getIdentifier() | def = c and rhs = c and not c.isAmbient())
or
exists(NamespaceDeclaration n | def = n | lhs = n.getIdentifier() and rhs = n)
or
exists(EnumDeclaration ed | def = ed.getIdentifier() | lhs = def and rhs = ed)
or
exists(ImportEqualsDeclaration i | def = i |
lhs = i.getIdentifier() and rhs = i.getImportedEntity()
)
or
exists(ImportSpecifier i | def = i and not i.isTypeOnly() | lhs = i.getLocal() and rhs = i)
or
exists(EnumMember member | def = member.getIdentifier() |
lhs = def and rhs = member.getInitializer()
)
}
/**
* Holds if `def` is a CFG node that assigns to `lhs`.
*
* This predicate extends the three-argument version of `defn` to also cover definitions
* where there is no explicit right hand side:
*
* <table border="1">
* <tr><th>Example</th><th><code>def</code></th><th><code>lhs</code></th></tr>
* <tr><td><code>x += y</code><td><code>x += y</code><td><code>x</code></tr>
* <tr><td><code>++z.q</code><td><code>++z.q</code><td><code>z.q</code></tr>
* <tr><td><code>import { a as b } from 'm'</code><td><code>a as b</code><td><code>b</code></tr>
* <tr><td><code>for (var p in o) ...</code><td><code>var p</code><td><code>p</code></tr>
* <tr><td><code>enum { x }</code><td><code>x</code><td><code>x</code></tr>
* </table>
*
* Additionally, parameters are also considered definitions, which are their own `lhs`.
*/
private predicate defn(ControlFlowNode def, Expr lhs) {
defn(def, lhs, _)
or
lhs = def.(CompoundAssignExpr).getTarget()
or
lhs = def.(UpdateExpr).getOperand().getUnderlyingReference()
or
exists(EnhancedForLoop efl | def = efl.getIteratorExpr() |
lhs = def.(Expr).stripParens() or
lhs = def.(VariableDeclarator).getBindingPattern()
)
or
lhs = def and
(
def instanceof Parameter or
def = any(ComprehensionBlock cb).getIterator()
)
or
exists(EnumMember member | def = member.getIdentifier() |
lhs = def and not exists(member.getInitializer())
)
}
/**
* Holds if `l` is one of the lvalues in the assignment `def`, or
* a destructuring pattern that contains some of the lvalues.
*
* For example, if `def` is `[{ x: y }] = e`, then `l` can be any
* of `y`, `{ x: y }` and `[{ x: y }]`.
*/
private predicate lvalAux(Expr l, ControlFlowNode def) {
defn(def, l)
or
exists(ArrayPattern ap | lvalAux(ap, def) | l = ap.getAnElement().stripParens())
or
exists(ObjectPattern op | lvalAux(op, def) |
l = op.getAPropertyPattern().getValuePattern().stripParens() or
l = op.getRest().stripParens()
)
}
/**
* An expression that can be evaluated to a reference, that is,
* a variable reference or a property access.
*/
class RefExpr extends Expr {
RefExpr() {
this instanceof VarRef or
this instanceof PropAccess
}
}
/**
* A variable reference or property access that is written to.
*
* For instance, in the assignment `x.p = x.q`, `x.p` is written to
* and `x.q` is not; in the expression `++i`, `i` is written to
* (and also read from).
*/
class LValue extends RefExpr {
LValue() { lvalAux(this, _) }
/** Gets the definition in which this lvalue occurs. */
ControlFlowNode getDefNode() { lvalAux(this, result) }
/** Gets the source of the assignment. */
AST::ValueNode getRhs() { defn(_, this, result) }
}
/**
* A variable reference or property access that is read from.
*
* For instance, in the assignment `x.p = x.q`, `x.q` is read from
* and `x.p` is not; in the expression `++i`, `i` is read from
* (and also written to).
*/
class RValue extends RefExpr {
RValue() {
not this instanceof LValue and not this instanceof VarDecl
or
// in `x++` and `x += 1`, `x` is both RValue and LValue
this = any(CompoundAssignExpr a).getTarget()
or
this = any(UpdateExpr u).getOperand().getUnderlyingReference()
or
this = any(NamespaceDeclaration decl).getIdentifier()
}
}
/**
* A ControlFlowNode that defines (that is, initializes or updates) variables or properties.
*
* The following program elements are definitions:
*
* - assignment expressions (`x = 42`)
* - update expressions (`++x`)
* - variable declarators with an initializer (`var x = 42`)
* - for-in and for-of statements (`for (x in o) { ... }`)
* - parameters of functions or catch clauses (`function (x) { ... }`)
* - named functions (`function x() { ... }`)
* - named classes (`class x { ... }`)
* - import specifiers (`import { x } from 'm'`)
*
* Note that due to destructuring, a single `VarDef` may define multiple
* variables and/or properties; for example, `{ x, y: z.p } = e` defines variable
* `x` as well as property `p` of `z`.
*/
class VarDef extends ControlFlowNode {
VarDef() { defn(this, _) }
/**
* Gets the target of this definition, which is either a simple variable
* reference, a destructuring pattern, or a property access.
*/
Expr getTarget() { defn(this, result) }
/** Gets a variable defined by this node, if any. */
Variable getAVariable() { result = this.getTarget().(BindingPattern).getAVariable() }
/**
* Gets the source of this definition, that is, the data flow node representing
* the value that this definition assigns to its target.
*
* This predicate is not defined for `VarDef`s where the source is implicit,
* such as `for-in` loops, parameters or destructuring assignments.
*/
AST::ValueNode getSource() {
exists(Expr target | not target instanceof DestructuringPattern and defn(this, target, result))
}
/**
* Gets the source that this definition destructs, that is, the
* right hand side of a destructuring assignment.
*/
AST::ValueNode getDestructuringSource() {
exists(Expr target | target instanceof DestructuringPattern and defn(this, target, result))
}
/**
* Holds if this definition of `v` is overwritten by another definition, that is,
* another definition of `v` is reachable from it in the CFG.
*/
predicate isOverwritten(Variable v) {
exists(BasicBlock bb, int i | bb.defAt(i, v, this) |
exists(int j | bb.defAt(j, v, _) and j > i)
or
bb.getASuccessor+().defAt(_, v, _)
)
}
}
/**
* A ControlFlowNode that uses (that is, reads from) a single variable.
*
* Some variable definitions are also uses, notably the operands of update expressions.
*/
class VarUse extends ControlFlowNode, @varref instanceof RValue {
/** Gets the variable this use refers to. */
Variable getVariable() { result = this.(VarRef).getVariable() }
/**
* Gets a definition that may reach this use.
*
* For global variables, each definition is considered to reach each use.
*/
VarDef getADef() {
result = this.getSsaVariable().getDefinition().getAContributingVarDef() or
result.getAVariable() = this.getVariable().(GlobalVariable)
}
/**
* Gets the unique SSA variable this use refers to.
*
* This predicate is only defined for variables that can be SSA-converted.
*/
SsaVariable getSsaVariable() { result.getAUse() = this }
}