@@ -56,7 +56,7 @@ class Node extends TIRDataFlowNode {
5656 /** Gets the argument that defines this `DefinitionByReferenceNode`, if any. */
5757 Expr asDefiningArgument ( ) { result = this .( DefinitionByReferenceNode ) .getArgument ( ) }
5858
59- /** Gets the parameter corresponding to this node, if any. */
59+ /** Gets the positional parameter corresponding to this node, if any. */
6060 Parameter asParameter ( ) { result = this .( ExplicitParameterNode ) .getParameter ( ) }
6161
6262 /**
@@ -158,44 +158,90 @@ class ExprNode extends InstructionNode {
158158}
159159
160160/**
161- * A node representing a `Parameter`. This includes both explicit parameters such
162- * as `x` in `f(x)` and implicit parameters such as `this` in `x.f()`
161+ * INTERNAL: do not use. Translates a parameter/argument index into a negative
162+ * number that denotes the index of its side effect (pointer indirection).
163+ */
164+ bindingset [ index]
165+ int getArgumentPosOfSideEffect ( int index ) {
166+ // -1 -> -2
167+ // 0 -> -3
168+ // 1 -> -4
169+ // ...
170+ result = - 3 - index
171+ }
172+
173+ /**
174+ * The value of a parameter at function entry, viewed as a node in a data
175+ * flow graph. This includes both explicit parameters such as `x` in `f(x)`
176+ * and implicit parameters such as `this` in `x.f()`.
177+ *
178+ * To match a specific kind of parameter, consider using one of the subclasses
179+ * `ExplicitParameterNode`, `ThisParameterNode`, or
180+ * `ParameterIndirectionNode`.
163181 */
164182class ParameterNode extends InstructionNode {
165- override InitializeParameterInstruction instr ;
183+ ParameterNode ( ) {
184+ // To avoid making this class abstract, we enumerate its values here
185+ instr instanceof InitializeParameterInstruction
186+ or
187+ instr instanceof InitializeIndirectionInstruction
188+ }
166189
167190 /**
168- * Holds if this node is the parameter of `c` at the specified (zero-based)
169- * position. The implicit `this` parameter is considered to have index `-1`.
191+ * Holds if this node is the parameter of `f` at the specified position. The
192+ * implicit `this` parameter is considered to have position `-1`, and
193+ * pointer-indirection parameters are at further negative positions.
170194 */
171- predicate isParameterOf ( Function f , int i ) { none ( ) } // overriden by subclasses
195+ predicate isParameterOf ( Function f , int pos ) { none ( ) } // overridden by subclasses
172196}
173197
174- /**
175- * The value of a parameter at function entry, viewed as a node in a data
176- * flow graph.
177- */
198+ /** An explicit positional parameter, not including `this` or `...`. */
178199private class ExplicitParameterNode extends ParameterNode {
200+ override InitializeParameterInstruction instr ;
201+
179202 ExplicitParameterNode ( ) { exists ( instr .getParameter ( ) ) }
180203
181- override predicate isParameterOf ( Function f , int i ) { f .getParameter ( i ) = instr .getParameter ( ) }
204+ override predicate isParameterOf ( Function f , int pos ) {
205+ f .getParameter ( pos ) = instr .getParameter ( )
206+ }
182207
183- /** Gets the parameter corresponding to this node. */
208+ /** Gets the `Parameter` associated with this node. */
184209 Parameter getParameter ( ) { result = instr .getParameter ( ) }
185210
186211 override string toString ( ) { result = instr .getParameter ( ) .toString ( ) }
187212}
188213
189- private class ThisParameterNode extends ParameterNode {
214+ /** An implicit `this` parameter. */
215+ class ThisParameterNode extends ParameterNode {
216+ override InitializeParameterInstruction instr ;
217+
190218 ThisParameterNode ( ) { instr .getIRVariable ( ) instanceof IRThisVariable }
191219
192- override predicate isParameterOf ( Function f , int i ) {
193- i = - 1 and instr .getEnclosingFunction ( ) = f
220+ override predicate isParameterOf ( Function f , int pos ) {
221+ pos = - 1 and instr .getEnclosingFunction ( ) = f
194222 }
195223
196224 override string toString ( ) { result = "this" }
197225}
198226
227+ /** A synthetic parameter to model the pointed-to object of a pointer parameter. */
228+ class ParameterIndirectionNode extends ParameterNode {
229+ override InitializeIndirectionInstruction instr ;
230+
231+ override predicate isParameterOf ( Function f , int pos ) {
232+ exists ( int index |
233+ f .getParameter ( index ) = instr .getParameter ( )
234+ or
235+ index = - 1 and
236+ instr .getIRVariable ( ) .( IRThisVariable ) .getEnclosingFunction ( ) = f
237+ |
238+ pos = getArgumentPosOfSideEffect ( index )
239+ )
240+ }
241+
242+ override string toString ( ) { result = "*" + instr .getIRVariable ( ) .toString ( ) }
243+ }
244+
199245/**
200246 * DEPRECATED: Data flow was never an accurate way to determine what
201247 * expressions might be uninitialized. It errs on the side of saying that
@@ -299,6 +345,18 @@ class DefinitionByReferenceNode extends InstructionNode {
299345 }
300346}
301347
348+ /**
349+ * A node representing the memory pointed to by a function argument.
350+ *
351+ * This class exists only in order to override `toString`, which would
352+ * otherwise be the default implementation inherited from `InstructionNode`.
353+ */
354+ private class ArgumentIndirectionNode extends InstructionNode {
355+ override ReadSideEffectInstruction instr ;
356+
357+ override string toString ( ) { result = "Argument " + instr .getIndex ( ) + " indirection" }
358+ }
359+
302360/**
303361 * A `Node` corresponding to a variable in the program, as opposed to the
304362 * value of that variable at some particular point. This can be used for
@@ -809,6 +867,31 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction
809867 or
810868 iTo .( PhiInstruction ) .getAnOperand ( ) .getDef ( ) = iFrom
811869 or
870+ // A read side effect is almost never exact since we don't know exactly how
871+ // much memory the callee will read.
872+ iTo .( ReadSideEffectInstruction ) .getSideEffectOperand ( ) .getAnyDef ( ) = iFrom and
873+ not iFrom .isResultConflated ( )
874+ or
875+ // Loading a single `int` from an `int *` parameter is not an exact load since
876+ // the parameter may point to an entire array rather than a single `int`. The
877+ // following rule ensures that any flow going into the
878+ // `InitializeIndirectionInstruction`, even if it's for a different array
879+ // element, will propagate to a load of the first element.
880+ //
881+ // Since we're linking `InitializeIndirectionInstruction` and
882+ // `LoadInstruction` together directly, this rule will break if there's any
883+ // reassignment of the parameter indirection, including a conditional one that
884+ // leads to a phi node.
885+ exists ( InitializeIndirectionInstruction init |
886+ iFrom = init and
887+ iTo .( LoadInstruction ) .getSourceValueOperand ( ) .getAnyDef ( ) = init and
888+ // Check that the types match. Otherwise we can get flow from an object to
889+ // its fields, which leads to field conflation when there's flow from other
890+ // fields to the object elsewhere.
891+ init .getParameter ( ) .getType ( ) .getUnspecifiedType ( ) .( DerivedType ) .getBaseType ( ) =
892+ iTo .getResultType ( ) .getUnspecifiedType ( )
893+ )
894+ or
812895 // Treat all conversions as flow, even conversions between different numeric types.
813896 iTo .( ConvertInstruction ) .getUnary ( ) = iFrom
814897 or
0 commit comments