@@ -54,7 +54,7 @@ class Node extends TIRDataFlowNode {
5454 /** Gets the argument that defines this `DefinitionByReferenceNode`, if any. */
5555 Expr asDefiningArgument ( ) { result = this .( DefinitionByReferenceNode ) .getArgument ( ) }
5656
57- /** Gets the parameter corresponding to this node, if any. */
57+ /** Gets the positional parameter corresponding to this node, if any. */
5858 Parameter asParameter ( ) { result = this .( ExplicitParameterNode ) .getParameter ( ) }
5959
6060 /**
@@ -156,44 +156,90 @@ class ExprNode extends InstructionNode {
156156}
157157
158158/**
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`.
161179 */
162180class 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+ }
164187
165188 /**
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.
168192 */
169- predicate isParameterOf ( Function f , int i ) { none ( ) } // overriden by subclasses
193+ predicate isParameterOf ( Function f , int pos ) { none ( ) } // overridden by subclasses
170194}
171195
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 `...`. */
176197private class ExplicitParameterNode extends ParameterNode {
198+ override InitializeParameterInstruction instr ;
199+
177200 ExplicitParameterNode ( ) { exists ( instr .getParameter ( ) ) }
178201
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+ }
180205
181- /** Gets the parameter corresponding to this node. */
206+ /** Gets the `Parameter` associated with this node. */
182207 Parameter getParameter ( ) { result = instr .getParameter ( ) }
183208
184209 override string toString ( ) { result = instr .getParameter ( ) .toString ( ) }
185210}
186211
187- private class ThisParameterNode extends ParameterNode {
212+ /** An implicit `this` parameter. */
213+ class ThisParameterNode extends ParameterNode {
214+ override InitializeParameterInstruction instr ;
215+
188216 ThisParameterNode ( ) { instr .getIRVariable ( ) instanceof IRThisVariable }
189217
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
192220 }
193221
194222 override string toString ( ) { result = "this" }
195223}
196224
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+
197243/**
198244 * DEPRECATED: Data flow was never an accurate way to determine what
199245 * expressions might be uninitialized. It errs on the side of saying that
@@ -341,6 +387,18 @@ class DefinitionByReferenceNode extends InstructionNode {
341387 }
342388}
343389
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+
344402/**
345403 * A `Node` corresponding to a variable in the program, as opposed to the
346404 * value of that variable at some particular point. This can be used for
@@ -442,6 +500,31 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction
442500 or
443501 iTo .( PhiInstruction ) .getAnOperand ( ) .getDef ( ) = iFrom
444502 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
445528 // Treat all conversions as flow, even conversions between different numeric types.
446529 iTo .( ConvertInstruction ) .getUnary ( ) = iFrom
447530 or
0 commit comments