@@ -54,7 +54,7 @@ class Node extends TIRDataFlowNode {
54
54
/** Gets the argument that defines this `DefinitionByReferenceNode`, if any. */
55
55
Expr asDefiningArgument ( ) { result = this .( DefinitionByReferenceNode ) .getArgument ( ) }
56
56
57
- /** Gets the parameter corresponding to this node, if any. */
57
+ /** Gets the positional parameter corresponding to this node, if any. */
58
58
Parameter asParameter ( ) { result = this .( ExplicitParameterNode ) .getParameter ( ) }
59
59
60
60
/**
@@ -156,44 +156,90 @@ class ExprNode extends InstructionNode {
156
156
}
157
157
158
158
/**
159
- * A node representing a `Parameter`. This includes both explicit parameters such
160
- * as `x` in `f(x)` and implicit parameters such as `this` in `x.f()`
159
+ * INTERNAL: do not use. Translates a parameter/argument index into a negative
160
+ * number that denotes the index of its side effect (pointer indirection).
161
+ */
162
+ bindingset [ index]
163
+ int getArgumentPosOfSideEffect ( int index ) {
164
+ // -1 -> -2
165
+ // 0 -> -3
166
+ // 1 -> -4
167
+ // ...
168
+ result = - 3 - index
169
+ }
170
+
171
+ /**
172
+ * The value of a parameter at function entry, viewed as a node in a data
173
+ * flow graph. This includes both explicit parameters such as `x` in `f(x)`
174
+ * and implicit parameters such as `this` in `x.f()`.
175
+ *
176
+ * To match a specific kind of parameter, consider using one of the subclasses
177
+ * `ExplicitParameterNode`, `ThisParameterNode`, or
178
+ * `ParameterIndirectionNode`.
161
179
*/
162
180
class ParameterNode extends InstructionNode {
163
- override InitializeParameterInstruction instr ;
181
+ ParameterNode ( ) {
182
+ // To avoid making this class abstract, we enumerate its values here
183
+ instr instanceof InitializeParameterInstruction
184
+ or
185
+ instr instanceof InitializeIndirectionInstruction
186
+ }
164
187
165
188
/**
166
- * Holds if this node is the parameter of `c` at the specified (zero-based)
167
- * position. The implicit `this` parameter is considered to have index `-1`.
189
+ * Holds if this node is the parameter of `f` at the specified position. The
190
+ * implicit `this` parameter is considered to have position `-1`, and
191
+ * pointer-indirection parameters are at further negative positions.
168
192
*/
169
- predicate isParameterOf ( Function f , int i ) { none ( ) } // overriden by subclasses
193
+ predicate isParameterOf ( Function f , int pos ) { none ( ) } // overridden by subclasses
170
194
}
171
195
172
- /**
173
- * The value of a parameter at function entry, viewed as a node in a data
174
- * flow graph.
175
- */
196
+ /** An explicit positional parameter, not including `this` or `...`. */
176
197
private class ExplicitParameterNode extends ParameterNode {
198
+ override InitializeParameterInstruction instr ;
199
+
177
200
ExplicitParameterNode ( ) { exists ( instr .getParameter ( ) ) }
178
201
179
- override predicate isParameterOf ( Function f , int i ) { f .getParameter ( i ) = instr .getParameter ( ) }
202
+ override predicate isParameterOf ( Function f , int pos ) {
203
+ f .getParameter ( pos ) = instr .getParameter ( )
204
+ }
180
205
181
- /** Gets the parameter corresponding to this node. */
206
+ /** Gets the `Parameter` associated with this node. */
182
207
Parameter getParameter ( ) { result = instr .getParameter ( ) }
183
208
184
209
override string toString ( ) { result = instr .getParameter ( ) .toString ( ) }
185
210
}
186
211
187
- private class ThisParameterNode extends ParameterNode {
212
+ /** An implicit `this` parameter. */
213
+ class ThisParameterNode extends ParameterNode {
214
+ override InitializeParameterInstruction instr ;
215
+
188
216
ThisParameterNode ( ) { instr .getIRVariable ( ) instanceof IRThisVariable }
189
217
190
- override predicate isParameterOf ( Function f , int i ) {
191
- i = - 1 and instr .getEnclosingFunction ( ) = f
218
+ override predicate isParameterOf ( Function f , int pos ) {
219
+ pos = - 1 and instr .getEnclosingFunction ( ) = f
192
220
}
193
221
194
222
override string toString ( ) { result = "this" }
195
223
}
196
224
225
+ /** A synthetic parameter to model the pointed-to object of a pointer parameter. */
226
+ class ParameterIndirectionNode extends ParameterNode {
227
+ override InitializeIndirectionInstruction instr ;
228
+
229
+ override predicate isParameterOf ( Function f , int pos ) {
230
+ exists ( int index |
231
+ f .getParameter ( index ) = instr .getParameter ( )
232
+ or
233
+ index = - 1 and
234
+ instr .getIRVariable ( ) .( IRThisVariable ) .getEnclosingFunction ( ) = f
235
+ |
236
+ pos = getArgumentPosOfSideEffect ( index )
237
+ )
238
+ }
239
+
240
+ override string toString ( ) { result = "*" + instr .getIRVariable ( ) .toString ( ) }
241
+ }
242
+
197
243
/**
198
244
* DEPRECATED: Data flow was never an accurate way to determine what
199
245
* expressions might be uninitialized. It errs on the side of saying that
@@ -341,6 +387,18 @@ class DefinitionByReferenceNode extends InstructionNode {
341
387
}
342
388
}
343
389
390
+ /**
391
+ * A node representing the memory pointed to by a function argument.
392
+ *
393
+ * This class exists only in order to override `toString`, which would
394
+ * otherwise be the default implementation inherited from `InstructionNode`.
395
+ */
396
+ private class ArgumentIndirectionNode extends InstructionNode {
397
+ override ReadSideEffectInstruction instr ;
398
+
399
+ override string toString ( ) { result = "Argument " + instr .getIndex ( ) + " indirection" }
400
+ }
401
+
344
402
/**
345
403
* A `Node` corresponding to a variable in the program, as opposed to the
346
404
* value of that variable at some particular point. This can be used for
@@ -442,6 +500,31 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction
442
500
or
443
501
iTo .( PhiInstruction ) .getAnOperand ( ) .getDef ( ) = iFrom
444
502
or
503
+ // A read side effect is almost never exact since we don't know exactly how
504
+ // much memory the callee will read.
505
+ iTo .( ReadSideEffectInstruction ) .getSideEffectOperand ( ) .getAnyDef ( ) = iFrom and
506
+ not iFrom .isResultConflated ( )
507
+ or
508
+ // Loading a single `int` from an `int *` parameter is not an exact load since
509
+ // the parameter may point to an entire array rather than a single `int`. The
510
+ // following rule ensures that any flow going into the
511
+ // `InitializeIndirectionInstruction`, even if it's for a different array
512
+ // element, will propagate to a load of the first element.
513
+ //
514
+ // Since we're linking `InitializeIndirectionInstruction` and
515
+ // `LoadInstruction` together directly, this rule will break if there's any
516
+ // reassignment of the parameter indirection, including a conditional one that
517
+ // leads to a phi node.
518
+ exists ( InitializeIndirectionInstruction init |
519
+ iFrom = init and
520
+ iTo .( LoadInstruction ) .getSourceValueOperand ( ) .getAnyDef ( ) = init and
521
+ // Check that the types match. Otherwise we can get flow from an object to
522
+ // its fields, which leads to field conflation when there's flow from other
523
+ // fields to the object elsewhere.
524
+ init .getParameter ( ) .getType ( ) .getUnspecifiedType ( ) .( DerivedType ) .getBaseType ( ) =
525
+ iTo .getResultType ( ) .getUnspecifiedType ( )
526
+ )
527
+ or
445
528
// Treat all conversions as flow, even conversions between different numeric types.
446
529
iTo .( ConvertInstruction ) .getUnary ( ) = iFrom
447
530
or
0 commit comments