@@ -10,19 +10,37 @@ private import semmle.code.cpp.ir.ValueNumbering
1010private import semmle.code.cpp.ir.IR
1111private import semmle.code.cpp.controlflow.IRGuards
1212private import semmle.code.cpp.models.interfaces.DataFlow
13+ private import DataFlowPrivate
14+ private import Ssa as Ssa
1315
1416cached
1517private module Cached {
1618 cached
1719 newtype TIRDataFlowNode =
1820 TInstructionNode ( Instruction i ) or
1921 TOperandNode ( Operand op ) or
20- TVariableNode ( Variable var )
22+ TVariableNode ( Variable var ) or
23+ TStoreNodeInstr ( Instruction i ) { Ssa:: explicitWrite ( _, _, i ) } or
24+ TStoreNodeOperand ( ArgumentOperand op ) { Ssa:: explicitWrite ( _, _, op .getDef ( ) ) }
2125
2226 cached
2327 predicate localFlowStepCached ( Node nodeFrom , Node nodeTo ) {
2428 simpleLocalFlowStep ( nodeFrom , nodeTo )
2529 }
30+
31+ private predicate needsPostReadNode ( Instruction iFrom ) {
32+ // If the instruction generates an address that flows to a load.
33+ Ssa:: addressFlowTC ( iFrom , Ssa:: getSourceAddress ( _) ) and
34+ (
35+ // And it is either a field address
36+ iFrom instanceof FieldAddressInstruction
37+ or
38+ // Or it is instruction that either uses or is used for an address that needs a post read node.
39+ exists ( Instruction mid | needsPostReadNode ( mid ) |
40+ Ssa:: addressFlow ( mid , iFrom ) or Ssa:: addressFlow ( iFrom , mid )
41+ )
42+ )
43+ }
2644}
2745
2846private import Cached
@@ -180,6 +198,99 @@ class OperandNode extends Node, TOperandNode {
180198 override string toString ( ) { result = this .getOperand ( ) .toString ( ) }
181199}
182200
201+ /**
202+ * INTERNAL: do not use.
203+ *
204+ * A `StoreNode` is a node that has been (or is about to be) the
205+ * source or target of a `storeStep`.
206+ */
207+ abstract class StoreNode extends Node {
208+ /** Gets the underlying instruction, if any. */
209+ Instruction getInstruction ( ) { none ( ) }
210+
211+ /** Gets the underlying operand, if any. */
212+ Operand getOperand ( ) { none ( ) }
213+
214+ /** Holds if this node should receive flow from `addr`. */
215+ abstract predicate flowInto ( Instruction addr ) ;
216+
217+ override Declaration getEnclosingCallable ( ) { result = this .getFunction ( ) }
218+
219+ /** Holds if this `StoreNode` is the root of the address computation used by a store operation. */
220+ predicate isTerminal ( ) {
221+ not exists ( this .getAPredecessor ( ) ) and
222+ not storeStep ( this , _, _)
223+ }
224+
225+ /** Gets the store operation that uses the address computed by this `StoreNode`. */
226+ abstract Instruction getStoreInstruction ( ) ;
227+
228+ /** Holds if the store operation associated with this `StoreNode` overwrites the entire variable. */
229+ final predicate isCertain ( ) { Ssa:: explicitWrite ( true , this .getStoreInstruction ( ) , _) }
230+
231+ /**
232+ * Gets the `StoreNode` that computes the address used by this `StoreNode`.
233+ * The boolean `readEffect` is `true` if the predecessor is accessed through the
234+ * address of a `ReadSideEffectInstruction`.
235+ */
236+ abstract StoreNode getAPredecessor ( ) ;
237+
238+ /** The inverse of `StoreNode.getAPredecessor`. */
239+ final StoreNode getASuccessor ( ) { result .getAPredecessor ( ) = this }
240+ }
241+
242+ private class StoreNodeInstr extends StoreNode , TStoreNodeInstr {
243+ Instruction instr ;
244+
245+ StoreNodeInstr ( ) { this = TStoreNodeInstr ( instr ) }
246+
247+ override predicate flowInto ( Instruction addr ) { this .getInstruction ( ) = addr }
248+
249+ override Instruction getInstruction ( ) { result = instr }
250+
251+ override Function getFunction ( ) { result = this .getInstruction ( ) .getEnclosingFunction ( ) }
252+
253+ override IRType getType ( ) { result = this .getInstruction ( ) .getResultIRType ( ) }
254+
255+ override Location getLocation ( ) { result = this .getInstruction ( ) .getLocation ( ) }
256+
257+ override string toString ( ) {
258+ result = instructionNode ( this .getInstruction ( ) ) .toString ( ) + " [store]"
259+ }
260+
261+ override Instruction getStoreInstruction ( ) {
262+ Ssa:: explicitWrite ( _, result , this .getInstruction ( ) )
263+ }
264+
265+ override StoreNode getAPredecessor ( ) {
266+ Ssa:: addressFlow ( result .getInstruction ( ) , this .getInstruction ( ) )
267+ }
268+ }
269+
270+ private class StoreNodeOperand extends StoreNode , TStoreNodeOperand {
271+ ArgumentOperand operand ;
272+
273+ StoreNodeOperand ( ) { this = TStoreNodeOperand ( operand ) }
274+
275+ override predicate flowInto ( Instruction addr ) { this .getOperand ( ) .getDef ( ) = addr }
276+
277+ override Operand getOperand ( ) { result = operand }
278+
279+ override Function getFunction ( ) { result = operand .getDef ( ) .getEnclosingFunction ( ) }
280+
281+ override IRType getType ( ) { result = operand .getIRType ( ) }
282+
283+ override Location getLocation ( ) { result = operand .getLocation ( ) }
284+
285+ override string toString ( ) { result = operandNode ( this .getOperand ( ) ) .toString ( ) + " [store]" }
286+
287+ override WriteSideEffectInstruction getStoreInstruction ( ) {
288+ Ssa:: explicitWrite ( _, result , operand .getDef ( ) )
289+ }
290+
291+ override StoreNode getAPredecessor ( ) { operand .getDef ( ) = result .getInstruction ( ) }
292+ }
293+
183294/**
184295 * An expression, viewed as a node in a data flow graph.
185296 */
@@ -313,15 +424,14 @@ deprecated class UninitializedNode extends Node {
313424 * Nodes corresponding to AST elements, for example `ExprNode`, usually refer
314425 * to the value before the update with the exception of `ClassInstanceExpr`,
315426 * which represents the value after the constructor has run.
316- *
317- * This class exists to match the interface used by Java. There are currently no non-abstract
318- * classes that extend it. When we implement field flow, we can revisit this.
319427 */
320- abstract class PostUpdateNode extends InstructionNode {
428+ abstract class PostUpdateNode extends Node {
321429 /**
322430 * Gets the node before the state update.
323431 */
324432 abstract Node getPreUpdateNode ( ) ;
433+
434+ override string toString ( ) { result = this .getPreUpdateNode ( ) + " [post update]" }
325435}
326436
327437/**
@@ -614,6 +724,13 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
614724 or
615725 // Instruction -> Operand flow
616726 simpleOperandLocalFlowStep ( nodeFrom .asInstruction ( ) , nodeTo .asOperand ( ) )
727+ or
728+ // Flow into, through, and out of store nodes
729+ StoreNodeFlow:: flowInto ( nodeFrom , nodeTo )
730+ or
731+ StoreNodeFlow:: flowThrough ( nodeFrom , nodeTo )
732+ or
733+ StoreNodeFlow:: flowOutOf ( nodeFrom , nodeTo )
617734}
618735
619736pragma [ noinline]
@@ -631,6 +748,28 @@ private predicate isSingleFieldClass(Type type, Operand op) {
631748 c .getSize ( ) = size and
632749 getFieldSizeOfClass ( c , type , size )
633750 )
751+ private module StoreNodeFlow {
752+ /** Holds if the store node `nodeTo` should receive flow from `nodeFrom`. */
753+ predicate flowInto( Node nodeFrom, StoreNode nodeTo) {
754+ nodeTo .flowInto ( Ssa:: getDestinationAddress ( nodeFrom .asInstruction ( ) ) )
755+ }
756+
757+ /** Holds if the store node `nodeTo` should receive flow from `nodeFom`. */
758+ predicate flowThrough ( StoreNode nFrom , StoreNode nodeTo ) {
759+ // Flow through a post update node that doesn't need a store step.
760+ not storeStep ( nFrom , _, _) and
761+ nodeTo .getASuccessor ( ) = nFrom
762+ }
763+
764+ /**
765+ * Holds if flow should leave the store node `nodeFrom` and enter the node `nodeTo`.
766+ * This happens because we have traversed an entire chain of field dereferences
767+ * after a store operation.
768+ */
769+ predicate flowOutOf ( StoreNode nFrom , Node nodeTo ) {
770+ nFrom .isTerminal ( ) and
771+ Ssa:: ssaFlow ( nFrom , nodeTo )
772+ }
634773}
635774
636775private predicate simpleOperandLocalFlowStep ( Instruction iFrom , Operand opTo ) {
@@ -788,25 +927,10 @@ predicate localInstructionFlow(Instruction e1, Instruction e2) {
788927 */
789928predicate localExprFlow ( Expr e1 , Expr e2 ) { localFlow ( exprNode ( e1 ) , exprNode ( e2 ) ) }
790929
791- /**
792- * Gets a field corresponding to the bit range `[startBit..endBit)` of class `c`, if any.
793- */
794- private Field getAField ( Class c , int startBit , int endBit ) {
795- result .getDeclaringType ( ) = c and
796- startBit = 8 * result .getByteOffset ( ) and
797- endBit = 8 * result .getType ( ) .getSize ( ) + startBit
798- or
799- exists ( Field f , Class cInner |
800- f = c .getAField ( ) and
801- cInner = f .getUnderlyingType ( ) and
802- result = getAField ( cInner , startBit - 8 * f .getByteOffset ( ) , endBit - 8 * f .getByteOffset ( ) )
803- )
804- }
805-
806930private newtype TContent =
807- TFieldContent ( Class c , int startBit , int endBit ) { exists ( getAField ( c , startBit , endBit ) ) } or
808- TCollectionContent ( ) or
809- TArrayContent ( )
931+ TFieldContent ( Field f ) or
932+ TCollectionContent ( ) or // Not used in C/C++
933+ TArrayContent ( ) // Not used in C/C++.
810934
811935/**
812936 * A description of the way data may be stored inside an object. Examples
@@ -824,18 +948,13 @@ class Content extends TContent {
824948
825949/** A reference through an instance field. */
826950class FieldContent extends Content , TFieldContent {
827- Class c ;
828- int startBit ;
829- int endBit ;
830-
831- FieldContent ( ) { this = TFieldContent ( c , startBit , endBit ) }
951+ Field f ;
832952
833- // Ensure that there's just 1 result for `toString`.
834- override string toString ( ) { result = min ( Field f | f = getAField ( ) | f .toString ( ) ) }
953+ FieldContent ( ) { this = TFieldContent ( f ) }
835954
836- predicate hasOffset ( Class cl , int start , int end ) { cl = c and start = startBit and end = endBit }
955+ override string toString ( ) { result = f . toString ( ) }
837956
838- Field getAField ( ) { result = getAField ( c , startBit , endBit ) }
957+ Field getField ( ) { result = f }
839958}
840959
841960/** A reference through an array. */
0 commit comments