@@ -15,7 +15,10 @@ cached
1515private newtype TIRDataFlowNode =
1616 TInstructionNode ( Instruction i ) or
1717 TOperandNode ( Operand op ) or
18- TVariableNode ( Variable var )
18+ TVariableNode ( Variable var ) or
19+ // `FieldNodes` are used as targets of certain `storeStep`s to implement handling of stores to
20+ // nested structs.
21+ TFieldNode ( FieldAddressInstruction field )
1922
2023/**
2124 * A node in a data flow graph.
@@ -170,6 +173,91 @@ class OperandNode extends Node, TOperandNode {
170173 override string toString ( ) { result = this .getOperand ( ) .toString ( ) }
171174}
172175
176+ abstract private class SkippableInstruction extends Instruction {
177+ abstract Instruction getSourceInstruction ( ) ;
178+ }
179+
180+ private Instruction skipSkippableInstructionsRec ( SkippableInstruction skip ) {
181+ result = skip .getSourceInstruction ( ) and not result instanceof SkippableInstruction
182+ or
183+ result = skipSkippableInstructionsRec ( skip .getSourceInstruction ( ) )
184+ }
185+
186+ private Instruction skipSkippableInstructions ( Instruction instr ) {
187+ result = instr and not result instanceof SkippableInstruction
188+ or
189+ result = skipSkippableInstructionsRec ( instr )
190+ }
191+
192+ private class SkippableCopyValueInstruction extends SkippableInstruction , CopyValueInstruction {
193+ override Instruction getSourceInstruction ( ) { result = this .getSourceValue ( ) }
194+ }
195+
196+ private class SkippableConvertInstruction extends SkippableInstruction , ConvertInstruction {
197+ override Instruction getSourceInstruction ( ) { result = this .getUnary ( ) }
198+ }
199+
200+ private class SkippableCheckedConvertInstruction extends SkippableInstruction ,
201+ CheckedConvertOrNullInstruction {
202+ override Instruction getSourceInstruction ( ) { result = this .getUnary ( ) }
203+ }
204+
205+ private class SkippableInheritanceConversionInstruction extends SkippableInstruction ,
206+ InheritanceConversionInstruction {
207+ override Instruction getSourceInstruction ( ) { result = this .getUnary ( ) }
208+ }
209+
210+ /**
211+ * INTERNAL: do not use. Gets the `FieldNode` corresponding to `instr`, if
212+ * `instr` is an instruction that propagates an address of a `FieldAddressInstruction`.
213+ */
214+ FieldNode getFieldNodeForFieldInstruction ( Instruction instr ) {
215+ result .getFieldInstruction ( ) = skipSkippableInstructions ( instr )
216+ }
217+
218+ /**
219+ * INTERNAL: do not use. A `FieldNode` represents the state of an object after modifying one
220+ * of its fields.
221+ */
222+ class FieldNode extends Node , TFieldNode {
223+ FieldAddressInstruction field ;
224+
225+ FieldNode ( ) { this = TFieldNode ( field ) }
226+
227+ /** Gets the `Field` of this `FieldNode`. */
228+ Field getField ( ) { result = getFieldInstruction ( ) .getField ( ) }
229+
230+ /** Gets the `FieldAddressInstruction` of this `FieldNode`. */
231+ FieldAddressInstruction getFieldInstruction ( ) { result = field }
232+
233+ /**
234+ * Gets the `FieldNode` corresponding to the parent field of this `FieldNode`, if any.
235+ *
236+ * For example, if `f` is the `FieldNode` for `c` in the expression `a.b.c`, then `f.getObjectNode()`
237+ * gives the `FieldNode` of `b`, and `f.getObjectNode().getObjectNode()` has no result as `a` is
238+ * not a field.
239+ */
240+ FieldNode getObjectNode ( ) { result = getFieldNodeForFieldInstruction ( field .getObjectAddress ( ) ) }
241+
242+ /**
243+ * Gets the `FieldNode` that has this `FieldNode` as parent, if any.
244+ *
245+ * For example, if `f` is the `FieldNode` corresponding to `b` in `a.b.c`, then `f.getNextNode()`
246+ * gives the `FieldNode` corresponding to `c`, and `f.getNextNode().getNextNode()`.
247+ */
248+ FieldNode getNextNode ( ) { result .getObjectNode ( ) = this }
249+
250+ /** Gets the class where the field of this node is declared. */
251+ Class getDeclaringType ( ) { result = getField ( ) .getDeclaringType ( ) }
252+
253+ override Function getFunction ( ) { result = field .getEnclosingFunction ( ) }
254+
255+ override IRType getType ( ) { result = field .getResultIRType ( ) }
256+
257+ override Location getLocation ( ) { result = field .getLocation ( ) }
258+
259+ override string toString ( ) { result = this .getField ( ) .toString ( ) }
260+ }
173261/**
174262 * An expression, viewed as a node in a data flow graph.
175263 */
@@ -585,6 +673,33 @@ Node uninitializedNode(LocalVariable v) { none() }
585673 */
586674predicate localFlowStep ( Node nodeFrom , Node nodeTo ) { simpleLocalFlowStep ( nodeFrom , nodeTo ) }
587675
676+ private predicate flowIntoReadNode ( Node nodeFrom , Node nodeTo ) {
677+ // flow from the "innermost" field to the load of that field.
678+ exists ( FieldNode fieldNode | nodeTo = fieldNode |
679+ not exists ( fieldNode .getObjectNode ( ) ) and
680+ (
681+ exists ( LoadInstruction load |
682+ fieldNode .getNextNode * ( ) = getFieldNodeForFieldInstruction ( load .getSourceAddress ( ) ) and
683+ nodeFrom .asInstruction ( ) = load .getSourceValueOperand ( ) .getAnyDef ( )
684+ )
685+ or
686+ // We need this to make stores look like loads for the dataflow library. So when there's a store
687+ // of the form x->y = z we need to make the field node corresponding to y look like it's reading
688+ // from the memory of x.
689+ exists ( StoreInstruction store , ChiInstruction chi |
690+ chi .getPartial ( ) = store and
691+ fieldNode .getNextNode * ( ) = getFieldNodeForFieldInstruction ( store .getDestinationAddress ( ) ) and
692+ nodeFrom .asInstruction ( ) = chi .getTotal ( )
693+ )
694+ or
695+ exists ( ReadSideEffectInstruction read |
696+ fieldNode .getNextNode * ( ) = getFieldNodeForFieldInstruction ( read .getArgumentDef ( ) ) and
697+ nodeFrom .asOperand ( ) = read .getSideEffectOperand ( )
698+ )
699+ )
700+ )
701+ }
702+
588703/**
589704 * INTERNAL: do not use.
590705 *
@@ -598,6 +713,8 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
598713 or
599714 // Instruction -> Operand flow
600715 simpleOperandLocalFlowStep ( nodeFrom .asInstruction ( ) , nodeTo .asOperand ( ) )
716+ or
717+ flowIntoReadNode ( nodeFrom , nodeTo )
601718}
602719
603720pragma [ noinline]
0 commit comments