33 */
44import cpp
55private import semmle.code.cpp.dataflow.internal.FlowVar
6+ private import semmle.code.cpp.models.interfaces.DataFlow
67
78private newtype TNode =
89 TExprNode ( Expr e ) or
910 TParameterNode ( Parameter p ) { exists ( p .getFunction ( ) .getBlock ( ) ) } or
11+ TDefinitionByReferenceNode ( VariableAccess va , Expr argument ) {
12+ definitionByReference ( va , argument )
13+ } or
1014 TUninitializedNode ( LocalVariable v ) {
1115 not v .hasInitializer ( )
1216 }
@@ -20,13 +24,7 @@ private newtype TNode =
2024*/
2125class Node extends TNode {
2226 /** Gets the function to which this node belongs. */
23- Function getFunction ( ) {
24- result = this .asExpr ( ) .getEnclosingFunction ( )
25- or
26- result = this .asParameter ( ) .getFunction ( )
27- or
28- result = this .asUninitialized ( ) .getFunction ( )
29- }
27+ Function getFunction ( ) { none ( ) } // overridden in subclasses
3028
3129 /**
3230 * INTERNAL: Do not use. Alternative name for `getFunction`.
@@ -36,18 +34,17 @@ class Node extends TNode {
3634 }
3735
3836 /** Gets the type of this node. */
39- Type getType ( ) {
40- result = this .asExpr ( ) .getType ( )
41- or
42- result = asVariable ( this ) .getType ( )
43- }
37+ Type getType ( ) { none ( ) } // overridden in subclasses
4438
4539 /** Gets the expression corresponding to this node, if any. */
4640 Expr asExpr ( ) { result = this .( ExprNode ) .getExpr ( ) }
4741
4842 /** Gets the parameter corresponding to this node, if any. */
4943 Parameter asParameter ( ) { result = this .( ParameterNode ) .getParameter ( ) }
5044
45+ /** Gets the argument that defines this `DefinitionByReferenceNode`, if any. */
46+ Expr asDefiningArgument ( ) { result = this .( DefinitionByReferenceNode ) .getArgument ( ) }
47+
5148 /**
5249 * Gets the uninitialized local variable corresponding to this node, if
5350 * any.
@@ -74,6 +71,8 @@ class Node extends TNode {
7471class ExprNode extends Node , TExprNode {
7572 Expr expr ;
7673 ExprNode ( ) { this = TExprNode ( expr ) }
74+ override Function getFunction ( ) { result = expr .getEnclosingFunction ( ) }
75+ override Type getType ( ) { result = expr .getType ( ) }
7776 override string toString ( ) { result = expr .toString ( ) }
7877 override Location getLocation ( ) { result = expr .getLocation ( ) }
7978 /** Gets the expression corresponding to this node. */
@@ -87,6 +86,8 @@ class ExprNode extends Node, TExprNode {
8786class ParameterNode extends Node , TParameterNode {
8887 Parameter param ;
8988 ParameterNode ( ) { this = TParameterNode ( param ) }
89+ override Function getFunction ( ) { result = param .getFunction ( ) }
90+ override Type getType ( ) { result = param .getType ( ) }
9091 override string toString ( ) { result = param .toString ( ) }
9192 override Location getLocation ( ) { result = param .getLocation ( ) }
9293 /** Gets the parameter corresponding to this node. */
@@ -100,13 +101,44 @@ class ParameterNode extends Node, TParameterNode {
100101 }
101102}
102103
104+ /**
105+ * A node that represents the value of a variable after a function call that
106+ * may have changed the variable because it's passed by reference.
107+ *
108+ * A typical example would be a call `f(&x)`. Firstly, there will be flow into
109+ * `x` from previous definitions of `x`. Secondly, there will be a
110+ * `DefinitionByReferenceNode` to represent the value of `x` after the call has
111+ * returned. This node will have its `getArgument()` equal to `&x`.
112+ */
113+ class DefinitionByReferenceNode extends Node , TDefinitionByReferenceNode {
114+ VariableAccess va ;
115+ Expr argument ;
116+
117+ DefinitionByReferenceNode ( ) { this = TDefinitionByReferenceNode ( va , argument ) }
118+ override Function getFunction ( ) { result = va .getEnclosingFunction ( ) }
119+ override Type getType ( ) { result = va .getType ( ) }
120+ override string toString ( ) { result = "ref arg " + argument .toString ( ) }
121+ override Location getLocation ( ) { result = argument .getLocation ( ) }
122+ /** Gets the argument corresponding to this node. */
123+ Expr getArgument ( ) { result = argument }
124+ /** Gets the parameter through which this value is assigned. */
125+ Parameter getParameter ( ) {
126+ exists ( FunctionCall call , int i |
127+ argument = call .getArgument ( i ) and
128+ result = call .getTarget ( ) .getParameter ( i )
129+ )
130+ }
131+ }
132+
103133/**
104134 * The value of an uninitialized local variable, viewed as a node in a data
105135 * flow graph.
106136 */
107137class UninitializedNode extends Node , TUninitializedNode {
108138 LocalVariable v ;
109139 UninitializedNode ( ) { this = TUninitializedNode ( v ) }
140+ override Function getFunction ( ) { result = v .getFunction ( ) }
141+ override Type getType ( ) { result = v .getType ( ) }
110142 override string toString ( ) { result = v .toString ( ) }
111143 override Location getLocation ( ) { result = v .getLocation ( ) }
112144 /** Gets the uninitialized local variable corresponding to this node. */
@@ -143,6 +175,14 @@ ExprNode exprNode(Expr e) { result.getExpr() = e }
143175 */
144176ParameterNode parameterNode ( Parameter p ) { result .getParameter ( ) = p }
145177
178+ /**
179+ * Gets the `Node` corresponding to a definition by reference of the variable
180+ * that is passed as `argument` of a call.
181+ */
182+ DefinitionByReferenceNode definitionByReferenceNodeFromArgument ( Expr argument ) {
183+ result .getArgument ( ) = argument
184+ }
185+
146186/**
147187 * Gets the `Node` corresponding to the value of an uninitialized local
148188 * variable `v`.
@@ -151,12 +191,6 @@ UninitializedNode uninitializedNode(LocalVariable v) {
151191 result .getLocalVariable ( ) = v
152192}
153193
154- private Variable asVariable ( Node node ) {
155- result = node .asParameter ( )
156- or
157- result = node .asUninitialized ( )
158- }
159-
160194/**
161195 * Holds if data flows from `nodeFrom` to `nodeTo` in exactly one local
162196 * (intra-procedural) step.
@@ -170,10 +204,17 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) {
170204 (
171205 exprToVarStep ( nodeFrom .asExpr ( ) , var )
172206 or
173- varSourceBaseCase ( var , asVariable ( nodeFrom ) )
207+ varSourceBaseCase ( var , nodeFrom .asParameter ( ) )
208+ or
209+ varSourceBaseCase ( var , nodeFrom .asUninitialized ( ) )
210+ or
211+ var .definedByReference ( nodeFrom .asDefiningArgument ( ) )
174212 ) and
175213 varToExprStep ( var , nodeTo .asExpr ( ) )
176214 )
215+ or
216+ // Expr -> DefinitionByReferenceNode
217+ exprToDefinitionByReferenceStep ( nodeFrom .asExpr ( ) , nodeTo .asDefiningArgument ( ) )
177218}
178219
179220/**
@@ -232,10 +273,31 @@ private predicate exprToExprStep_nocfg(Expr fromExpr, Expr toExpr) {
232273 fromExpr = op .getOperand ( )
233274 )
234275 or
235- toExpr = any ( FunctionCall moveCall |
236- moveCall .getTarget ( ) .getNamespace ( ) .getName ( ) = "std" and
237- moveCall .getTarget ( ) .getName ( ) = "move" and
238- fromExpr = moveCall .getArgument ( 0 )
276+ toExpr = any ( Call call |
277+ exists ( DataFlowFunction f , FunctionInput inModel , FunctionOutput outModel , int iIn |
278+ call .getTarget ( ) = f and
279+ f .hasDataFlow ( inModel , outModel ) and
280+ outModel .isOutReturnValue ( ) and
281+ inModel .isInParameter ( iIn ) and
282+ fromExpr = call .getArgument ( iIn )
283+ )
284+ )
285+ }
286+
287+ private predicate exprToDefinitionByReferenceStep ( Expr exprIn , Expr argOut ) {
288+ exists ( DataFlowFunction f , Call call , FunctionOutput outModel , int argOutIndex |
289+ call .getTarget ( ) = f and
290+ argOut = call .getArgument ( argOutIndex ) and
291+ outModel .isOutParameterPointer ( argOutIndex ) and
292+ exists ( int argInIndex , FunctionInput inModel |
293+ f .hasDataFlow ( inModel , outModel )
294+ |
295+ inModel .isInParameterPointer ( argInIndex ) and
296+ call .passesByReference ( argInIndex , exprIn )
297+ or
298+ inModel .isInParameter ( argInIndex ) and
299+ exprIn = call .getArgument ( argInIndex )
300+ )
239301 )
240302}
241303
0 commit comments