Skip to content

Commit e4c9dd7

Browse files
committed
C++: Hide that IR DataFlow::Node is Instruction
We haven't come to a conclusion on whether these two types will remain identical forever. To make sure we're able to change it in the future, this change makes it impossible to cast between the two types. Callers must use the `asInstruction` member predicate to convert.
1 parent 94c625f commit e4c9dd7

File tree

3 files changed

+67
-23
lines changed

3 files changed

+67
-23
lines changed

cpp/ql/src/semmle/code/cpp/ir/dataflow/TaintTracking.qll

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,14 @@ module TaintTracking {
133133
// Taint can flow into using ordinary data flow.
134134
DataFlow::localFlowStep(nodeFrom, nodeTo)
135135
or
136+
localInstructionTaintStep(nodeFrom.asInstruction(), nodeTo.asInstruction())
137+
}
138+
139+
/**
140+
* Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local
141+
* (intra-procedural) step.
142+
*/
143+
private predicate localInstructionTaintStep(Instruction nodeFrom, Instruction nodeTo) {
136144
// Taint can flow through expressions that alter the value but preserve
137145
// more than one bit of it _or_ expressions that follow data through
138146
// pointer indirections.

cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,16 @@ private import DataFlowDispatch
88
* to the callable. Instance arguments (`this` pointer) are also included.
99
*/
1010
class ArgumentNode extends Node {
11-
ArgumentNode() { exists(CallInstruction call | this = call.getAnArgument()) }
11+
ArgumentNode() { exists(CallInstruction call | this.asInstruction() = call.getAnArgument()) }
1212

1313
/**
1414
* Holds if this argument occurs at the given position in the given call.
1515
* The instance argument is considered to have index `-1`.
1616
*/
1717
predicate argumentOf(DataFlowCall call, int pos) {
18-
this = call.getPositionalArgument(pos)
18+
this.asInstruction() = call.getPositionalArgument(pos)
1919
or
20-
this = call.getThisArgument() and pos = -1
20+
this.asInstruction() = call.getThisArgument() and pos = -1
2121
}
2222

2323
/** Gets the call in which this node is an argument. */
@@ -37,24 +37,26 @@ class ReturnKind extends TReturnKind {
3737

3838
/** A data flow node that occurs as the result of a `ReturnStmt`. */
3939
class ReturnNode extends Node {
40-
ReturnNode() { exists(ReturnValueInstruction ret | this = ret.getReturnValue()) }
40+
ReturnNode() { exists(ReturnValueInstruction ret | this.asInstruction() = ret.getReturnValue()) }
4141

4242
/** Gets the kind of this returned value. */
4343
ReturnKind getKind() { result = TNormalReturnKind() }
4444
}
4545

4646
/** A data flow node that represents the output of a call. */
47-
class OutNode extends Node, CallInstruction {
47+
class OutNode extends Node {
48+
override CallInstruction instr;
49+
4850
/** Gets the underlying call. */
49-
DataFlowCall getCall() { result = this }
51+
DataFlowCall getCall() { result = instr }
5052
}
5153

5254
/**
5355
* Gets a node that can read the value returned from `call` with return kind
5456
* `kind`.
5557
*/
5658
OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) {
57-
result = call and
59+
result.getCall() = call and
5860
kind = TNormalReturnKind()
5961
}
6062

@@ -192,11 +194,13 @@ class DataFlowType = Type;
192194
class DataFlowLocation = Location;
193195

194196
/** A function call relevant for data flow. */
195-
class DataFlowCall extends CallInstruction, Node {
197+
class DataFlowCall extends CallInstruction {
196198
/**
197199
* Gets the nth argument for this call.
198200
*
199201
* The range of `n` is from `0` to `getNumberOfArguments() - 1`.
200202
*/
201-
Node getArgument(int n) { result = this.getPositionalArgument(n) }
203+
Node getArgument(int n) { result.asInstruction() = this.getPositionalArgument(n) }
204+
205+
Function getEnclosingCallable() { result = this.getEnclosingFunction() }
202206
}

cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,36 @@ private import cpp
66
private import semmle.code.cpp.ir.IR
77
private import semmle.code.cpp.controlflow.IRGuards
88

9+
/**
10+
* A newtype wrapper to prevent accidental casts between `Node` and
11+
* `Instruction`. This ensures we can add `Node`s that are not `Instruction`s
12+
* in the future.
13+
*/
14+
private newtype TIRDataFlowNode = MkIRDataFlowNode(Instruction i)
15+
916
/**
1017
* A node in a data flow graph.
1118
*
1219
* A node can be either an expression, a parameter, or an uninitialized local
1320
* variable. Such nodes are created with `DataFlow::exprNode`,
1421
* `DataFlow::parameterNode`, and `DataFlow::uninitializedNode` respectively.
1522
*/
16-
class Node extends Instruction {
23+
class Node extends TIRDataFlowNode {
24+
Instruction instr;
25+
26+
Node() { this = MkIRDataFlowNode(instr) }
27+
1728
/**
1829
* INTERNAL: Do not use. Alternative name for `getFunction`.
1930
*/
20-
Function getEnclosingCallable() { result = this.getEnclosingFunction() }
31+
Function getEnclosingCallable() { result = this.getFunction() }
32+
33+
Function getFunction() { result = instr.getEnclosingFunction() }
2134

2235
/** Gets the type of this node. */
23-
Type getType() { result = this.getResultType() }
36+
Type getType() { result = instr.getResultType() }
37+
38+
Instruction asInstruction() { this = MkIRDataFlowNode(result) }
2439

2540
/**
2641
* Gets the non-conversion expression corresponding to this node, if any. If
@@ -29,30 +44,33 @@ class Node extends Instruction {
2944
* expression.
3045
*/
3146
Expr asExpr() {
32-
result.getConversion*() = this.getConvertedResultExpression() and
47+
result.getConversion*() = instr.getConvertedResultExpression() and
3348
not result instanceof Conversion
3449
}
3550

3651
/**
3752
* Gets the expression corresponding to this node, if any. The returned
3853
* expression may be a `Conversion`.
3954
*/
40-
Expr asConvertedExpr() { result = this.getConvertedResultExpression() }
55+
Expr asConvertedExpr() { result = instr.getConvertedResultExpression() }
4156

4257
/** Gets the parameter corresponding to this node, if any. */
43-
Parameter asParameter() { result = this.(InitializeParameterInstruction).getParameter() }
58+
Parameter asParameter() { result = instr.(InitializeParameterInstruction).getParameter() }
4459

4560
/**
4661
* Gets the uninitialized local variable corresponding to this node, if
4762
* any.
4863
*/
49-
LocalVariable asUninitialized() { result = this.(UninitializedInstruction).getLocalVariable() }
64+
LocalVariable asUninitialized() { result = instr.(UninitializedInstruction).getLocalVariable() }
5065

5166
/**
5267
* Gets an upper bound on the type of this node.
5368
*/
5469
Type getTypeBound() { result = getType() }
5570

71+
/** Gets the location of this element. */
72+
Location getLocation() { result = instr.getLocation() }
73+
5674
/**
5775
* Holds if this element is at the specified location.
5876
* The location spans column `startcolumn` of line `startline` to
@@ -63,8 +81,10 @@ class Node extends Instruction {
6381
predicate hasLocationInfo(
6482
string filepath, int startline, int startcolumn, int endline, int endcolumn
6583
) {
66-
getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
84+
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
6785
}
86+
87+
string toString() { result = instr.toString() }
6888
}
6989

7090
/**
@@ -92,19 +112,27 @@ class ExprNode extends Node {
92112
* The value of a parameter at function entry, viewed as a node in a data
93113
* flow graph.
94114
*/
95-
class ParameterNode extends Node, InitializeParameterInstruction {
115+
class ParameterNode extends Node {
116+
override InitializeParameterInstruction instr;
117+
96118
/**
97119
* Holds if this node is the parameter of `c` at the specified (zero-based)
98120
* position. The implicit `this` parameter is considered to have index `-1`.
99121
*/
100-
predicate isParameterOf(Function f, int i) { f.getParameter(i) = getParameter() }
122+
predicate isParameterOf(Function f, int i) { f.getParameter(i) = instr.getParameter() }
123+
124+
Parameter getParameter() { result = instr.getParameter() }
101125
}
102126

103127
/**
104128
* The value of an uninitialized local variable, viewed as a node in a data
105129
* flow graph.
106130
*/
107-
class UninitializedNode extends Node, UninitializedInstruction { }
131+
class UninitializedNode extends Node {
132+
override UninitializedInstruction instr;
133+
134+
LocalVariable getLocalVariable() { result = instr.getLocalVariable() }
135+
}
108136

109137
/**
110138
* A node associated with an object after an operation that might have
@@ -166,10 +194,14 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) {
166194
* data flow. It may have less flow than the `localFlowStep` predicate.
167195
*/
168196
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
169-
nodeTo.(CopyInstruction).getSourceValue() = nodeFrom or
170-
nodeTo.(PhiInstruction).getAnOperand().getDef() = nodeFrom or
197+
simpleInstructionLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asInstruction())
198+
}
199+
200+
private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction iTo) {
201+
iTo.(CopyInstruction).getSourceValue() = iFrom or
202+
iTo.(PhiInstruction).getAnOperand().getDef() = iFrom or
171203
// Treat all conversions as flow, even conversions between different numeric types.
172-
nodeTo.(ConvertInstruction).getUnary() = nodeFrom
204+
iTo.(ConvertInstruction).getUnary() = iFrom
173205
}
174206

175207
/**

0 commit comments

Comments
 (0)