@@ -8,12 +8,9 @@ private import semmle.code.cpp.controlflow.IRGuards
88private import semmle.code.cpp.ir.ValueNumbering
99private import semmle.code.cpp.models.interfaces.DataFlow
1010
11- /**
12- * A newtype wrapper to prevent accidental casts between `Node` and
13- * `Instruction`. This ensures we can add `Node`s that are not `Instruction`s
14- * in the future.
15- */
16- private newtype TIRDataFlowNode = MkIRDataFlowNode ( Instruction i )
11+ private newtype TIRDataFlowNode =
12+ TInstructionNode ( Instruction i ) or
13+ TVariableNode ( Variable var )
1714
1815/**
1916 * A node in a data flow graph.
@@ -23,44 +20,45 @@ private newtype TIRDataFlowNode = MkIRDataFlowNode(Instruction i)
2320 * `DataFlow::parameterNode`, and `DataFlow::uninitializedNode` respectively.
2421 */
2522class Node extends TIRDataFlowNode {
26- Instruction instr ;
27-
28- Node ( ) { this = MkIRDataFlowNode ( instr ) }
29-
3023 /**
31- * INTERNAL: Do not use. Alternative name for `getFunction`.
24+ * INTERNAL: Do not use.
3225 */
33- Function getEnclosingCallable ( ) { result = this . getFunction ( ) }
26+ Declaration getEnclosingCallable ( ) { none ( ) } // overridden in subclasses
3427
35- Function getFunction ( ) { result = instr .getEnclosingFunction ( ) }
28+ /** Gets the function to which this node belongs, if any. */
29+ Function getFunction ( ) { none ( ) } // overridden in subclasses
3630
3731 /** Gets the type of this node. */
38- Type getType ( ) { result = instr . getResultType ( ) }
32+ Type getType ( ) { none ( ) } // overridden in subclasses
3933
40- Instruction asInstruction ( ) { this = MkIRDataFlowNode ( result ) }
34+ /** Gets the instruction corresponding to this node, if any. */
35+ Instruction asInstruction ( ) { result = this .( InstructionNode ) .getInstruction ( ) }
4136
4237 /**
4338 * Gets the non-conversion expression corresponding to this node, if any. If
4439 * this node strictly (in the sense of `asConvertedExpr`) corresponds to a
4540 * `Conversion`, then the result is that `Conversion`'s non-`Conversion` base
4641 * expression.
4742 */
48- Expr asExpr ( ) {
49- result .getConversion * ( ) = instr .getConvertedResultExpression ( ) and
50- not result instanceof Conversion
51- }
43+ Expr asExpr ( ) { result = this .( ExprNode ) .getExpr ( ) }
5244
5345 /**
5446 * Gets the expression corresponding to this node, if any. The returned
5547 * expression may be a `Conversion`.
5648 */
57- Expr asConvertedExpr ( ) { result = instr . getConvertedResultExpression ( ) }
49+ Expr asConvertedExpr ( ) { result = this . ( ExprNode ) . getConvertedExpr ( ) }
5850
5951 /** Gets the argument that defines this `DefinitionByReferenceNode`, if any. */
6052 Expr asDefiningArgument ( ) { result = this .( DefinitionByReferenceNode ) .getArgument ( ) }
6153
6254 /** Gets the parameter corresponding to this node, if any. */
63- Parameter asParameter ( ) { result = instr .( InitializeParameterInstruction ) .getParameter ( ) }
55+ Parameter asParameter ( ) { result = this .( ParameterNode ) .getParameter ( ) }
56+
57+ /**
58+ * Gets the variable corresponding to this node, if any. This can be used for
59+ * modelling flow in and out of global variables.
60+ */
61+ Variable asVariable ( ) { result = this .( VariableNode ) .getVariable ( ) }
6462
6563 /**
6664 * DEPRECATED: See UninitializedNode.
@@ -76,7 +74,7 @@ class Node extends TIRDataFlowNode {
7674 Type getTypeBound ( ) { result = getType ( ) }
7775
7876 /** Gets the location of this element. */
79- Location getLocation ( ) { result = instr . getLocation ( ) }
77+ Location getLocation ( ) { none ( ) } // overridden by subclasses
8078
8179 /**
8280 * Holds if this element is at the specified location.
@@ -91,32 +89,55 @@ class Node extends TIRDataFlowNode {
9189 this .getLocation ( ) .hasLocationInfo ( filepath , startline , startcolumn , endline , endcolumn )
9290 }
9391
94- string toString ( ) {
92+ /** Gets a textual representation of this element. */
93+ string toString ( ) { none ( ) } // overridden by subclasses
94+ }
95+
96+ class InstructionNode extends Node , TInstructionNode {
97+ Instruction instr ;
98+
99+ InstructionNode ( ) { this = TInstructionNode ( instr ) }
100+
101+ /** Gets the instruction corresponding to this node. */
102+ Instruction getInstruction ( ) { result = instr }
103+
104+ override Declaration getEnclosingCallable ( ) { result = this .getFunction ( ) }
105+
106+ override Function getFunction ( ) { result = instr .getEnclosingFunction ( ) }
107+
108+ override Type getType ( ) { result = instr .getResultType ( ) }
109+
110+ override Location getLocation ( ) { result = instr .getLocation ( ) }
111+
112+ override string toString ( ) {
95113 // This predicate is overridden in subclasses. This default implementation
96114 // does not use `Instruction.toString` because that's expensive to compute.
97- result = this .asInstruction ( ) .getOpcode ( ) .toString ( )
115+ result = this .getInstruction ( ) .getOpcode ( ) .toString ( )
98116 }
99117}
100118
101119/**
102120 * An expression, viewed as a node in a data flow graph.
103121 */
104- class ExprNode extends Node {
105- ExprNode ( ) { exists ( this . asExpr ( ) ) }
122+ class ExprNode extends InstructionNode {
123+ ExprNode ( ) { exists ( instr . getConvertedResultExpression ( ) ) }
106124
107125 /**
108126 * Gets the non-conversion expression corresponding to this node, if any. If
109127 * this node strictly (in the sense of `getConvertedExpr`) corresponds to a
110128 * `Conversion`, then the result is that `Conversion`'s non-`Conversion` base
111129 * expression.
112130 */
113- Expr getExpr ( ) { result = this .asExpr ( ) }
131+ Expr getExpr ( ) {
132+ result .getConversion * ( ) = instr .getConvertedResultExpression ( ) and
133+ not result instanceof Conversion
134+ }
114135
115136 /**
116137 * Gets the expression corresponding to this node, if any. The returned
117138 * expression may be a `Conversion`.
118139 */
119- Expr getConvertedExpr ( ) { result = this . asConvertedExpr ( ) }
140+ Expr getConvertedExpr ( ) { result = instr . getConvertedResultExpression ( ) }
120141
121142 override string toString ( ) { result = this .asConvertedExpr ( ) .toString ( ) }
122143}
@@ -125,7 +146,7 @@ class ExprNode extends Node {
125146 * The value of a parameter at function entry, viewed as a node in a data
126147 * flow graph.
127148 */
128- class ParameterNode extends Node {
149+ class ParameterNode extends InstructionNode {
129150 override InitializeParameterInstruction instr ;
130151
131152 /**
@@ -139,7 +160,7 @@ class ParameterNode extends Node {
139160 override string toString ( ) { result = instr .getParameter ( ) .toString ( ) }
140161}
141162
142- private class ThisParameterNode extends Node {
163+ private class ThisParameterNode extends InstructionNode {
143164 override InitializeThisInstruction instr ;
144165
145166 override string toString ( ) { result = "this" }
@@ -176,7 +197,7 @@ deprecated class UninitializedNode extends Node {
176197 * This class exists to match the interface used by Java. There are currently no non-abstract
177198 * classes that extend it. When we implement field flow, we can revisit this.
178199 */
179- abstract class PostUpdateNode extends Node {
200+ abstract class PostUpdateNode extends InstructionNode {
180201 /**
181202 * Gets the node before the state update.
182203 */
@@ -193,7 +214,7 @@ abstract class PostUpdateNode extends Node {
193214 * returned. This node will have its `getArgument()` equal to `&x` and its
194215 * `getVariableAccess()` equal to `x`.
195216 */
196- class DefinitionByReferenceNode extends Node {
217+ class DefinitionByReferenceNode extends InstructionNode {
197218 override WriteSideEffectInstruction instr ;
198219
199220 /** Gets the argument corresponding to this node. */
@@ -220,10 +241,41 @@ class DefinitionByReferenceNode extends Node {
220241 }
221242}
222243
244+ /**
245+ * A `Node` corresponding to a variable in the program, as opposed to the
246+ * value of that variable at some particular point. This can be used for
247+ * modelling flow in and out of global variables.
248+ */
249+ class VariableNode extends Node , TVariableNode {
250+ Variable v ;
251+
252+ VariableNode ( ) { this = TVariableNode ( v ) }
253+
254+ /** Gets the variable corresponding to this node. */
255+ Variable getVariable ( ) { result = v }
256+
257+ override Function getFunction ( ) { none ( ) }
258+
259+ override Declaration getEnclosingCallable ( ) {
260+ // When flow crosses from one _enclosing callable_ to another, the
261+ // interprocedural data-flow library discards call contexts and inserts a
262+ // node in the big-step relation used for human-readable path explanations.
263+ // Therefore we want a distinct enclosing callable for each `VariableNode`,
264+ // and that can be the `Variable` itself.
265+ result = v
266+ }
267+
268+ override Type getType ( ) { result = v .getType ( ) }
269+
270+ override Location getLocation ( ) { result = v .getLocation ( ) }
271+
272+ override string toString ( ) { result = v .toString ( ) }
273+ }
274+
223275/**
224276 * Gets the node corresponding to `instr`.
225277 */
226- Node instructionNode ( Instruction instr ) { result .asInstruction ( ) = instr }
278+ InstructionNode instructionNode ( Instruction instr ) { result .getInstruction ( ) = instr }
227279
228280DefinitionByReferenceNode definitionByReferenceNode ( Expr e ) { result .getArgument ( ) = e }
229281
@@ -244,6 +296,9 @@ ExprNode convertedExprNode(Expr e) { result.getExpr() = e }
244296 */
245297ParameterNode parameterNode ( Parameter p ) { result .getParameter ( ) = p }
246298
299+ /** Gets the `VariableNode` corresponding to the variable `v`. */
300+ VariableNode variableNode ( Variable v ) { result .getVariable ( ) = v }
301+
247302/**
248303 * Gets the `Node` corresponding to the value of an uninitialized local
249304 * variable `v`.
0 commit comments