Skip to content

Commit b622d62

Browse files
committed
C++: Wire up param/arg indirections in data flow
1 parent 2b2667a commit b622d62

6 files changed

Lines changed: 91 additions & 19 deletions

File tree

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

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,28 @@ private import DataFlowDispatch
88
* to the callable. Instance arguments (`this` pointer) are also included.
99
*/
1010
class ArgumentNode extends InstructionNode {
11-
ArgumentNode() { exists(CallInstruction call | this.getInstruction() = call.getAnArgument()) }
11+
ArgumentNode() {
12+
exists(CallInstruction call |
13+
instr = call.getAnArgument()
14+
or
15+
instr.(ReadSideEffectInstruction).getPrimaryInstruction() = call
16+
)
17+
}
1218

1319
/**
1420
* Holds if this argument occurs at the given position in the given call.
1521
* The instance argument is considered to have index `-1`.
1622
*/
1723
predicate argumentOf(DataFlowCall call, int pos) {
18-
this.getInstruction() = call.getPositionalArgument(pos)
24+
instr = call.getPositionalArgument(pos)
25+
or
26+
instr = call.getThisArgument() and pos = -1
1927
or
20-
this.getInstruction() = call.getThisArgument() and pos = -1
28+
exists(ReadSideEffectInstruction read |
29+
read = instr and
30+
read.getPrimaryInstruction() = call and
31+
pos = getArgumentPosOfSideEffect(read.getIndex())
32+
)
2133
}
2234

2335
/** Gets the call in which this node is an argument. */

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

Lines changed: 73 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ class Node extends TIRDataFlowNode {
5454
/** Gets the argument that defines this `DefinitionByReferenceNode`, if any. */
5555
Expr asDefiningArgument() { result = this.(DefinitionByReferenceNode).getArgument() }
5656

57-
/** Gets the parameter corresponding to this node, if any. */
58-
Parameter asParameter() { result = this.(ParameterNode).getParameter() }
57+
/** Gets the positional parameter corresponding to this node, if any. */
58+
Parameter asParameter() { result = this.(PositionalParameterNode).getParameter() }
5959

6060
/**
6161
* Gets the variable corresponding to this node, if any. This can be used for
@@ -142,28 +142,70 @@ class ExprNode extends InstructionNode {
142142
override string toString() { result = this.asConvertedExpr().toString() }
143143
}
144144

145+
/**
146+
* INTERNAL: do not use. Translates a parameter/argument index into a negative
147+
* number that denotes the index of its side effect (pointer indirection).
148+
*/
149+
bindingset[index]
150+
int getArgumentPosOfSideEffect(int index) {
151+
// -1 -> -2
152+
// 0 -> -3
153+
// 1 -> -4
154+
// ...
155+
result = -3 - index
156+
}
157+
145158
/**
146159
* The value of a parameter at function entry, viewed as a node in a data
147160
* flow graph.
148161
*/
149-
class ParameterNode extends InstructionNode {
150-
override InitializeParameterInstruction instr;
151-
162+
abstract class ParameterNode extends InstructionNode {
152163
/**
153-
* Holds if this node is the parameter of `c` at the specified (zero-based)
154-
* position. The implicit `this` parameter is considered to have index `-1`.
164+
* Holds if this node is the parameter of `f` at the specified position. The
165+
* implicit `this` parameter is considered to have position `-1`, and
166+
* pointer-indirection parameters are at further negative positions.
155167
*/
156-
predicate isParameterOf(Function f, int i) { f.getParameter(i) = instr.getParameter() }
168+
abstract predicate isParameterOf(Function f, int pos);
169+
}
170+
171+
private class ThisParameterNode extends ParameterNode {
172+
override InitializeThisInstruction instr;
173+
174+
override predicate isParameterOf(Function f, int pos) {
175+
pos = -1 and
176+
instr.getEnclosingFunction() = f
177+
}
178+
179+
override string toString() { result = "this" }
180+
}
157181

182+
class PositionalParameterNode extends ParameterNode {
183+
override InitializeParameterInstruction instr;
184+
185+
override predicate isParameterOf(Function f, int pos) {
186+
f.getParameter(pos) = instr.getParameter()
187+
}
188+
189+
/** Gets the `Parameter` associated with this node. */
158190
Parameter getParameter() { result = instr.getParameter() }
159191

160-
override string toString() { result = instr.getParameter().toString() }
192+
override string toString() { result = this.getParameter().toString() }
161193
}
162194

163-
private class ThisParameterNode extends InstructionNode {
164-
override InitializeThisInstruction instr;
195+
private class ParameterIndirectionNode extends ParameterNode {
196+
override InitializeIndirectionInstruction instr;
165197

166-
override string toString() { result = "this" }
198+
override predicate isParameterOf(Function f, int pos) {
199+
exists(int index |
200+
f.getParameter(index) = instr.getParameter() and
201+
pos = getArgumentPosOfSideEffect(index)
202+
)
203+
}
204+
205+
/** Gets the `Parameter` associated with this node. */
206+
Parameter getParameter() { result = instr.getParameter() }
207+
208+
override string toString() { result = "*" + this.getParameter().toString() }
167209
}
168210

169211
/**
@@ -294,7 +336,7 @@ ExprNode convertedExprNode(Expr e) { result.getExpr() = e }
294336
/**
295337
* Gets the `Node` corresponding to the value of `p` at function entry.
296338
*/
297-
ParameterNode parameterNode(Parameter p) { result.getParameter() = p }
339+
PositionalParameterNode parameterNode(Parameter p) { result.getParameter() = p }
298340

299341
/** Gets the `VariableNode` corresponding to the variable `v`. */
300342
VariableNode variableNode(Variable v) { result.getVariable() = v }
@@ -328,6 +370,24 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction
328370
or
329371
iTo.(PhiInstruction).getAnOperand().getDef() = iFrom
330372
or
373+
// A read side effect is almost never exact since we don't know exactly how
374+
// much memory the callee will read.
375+
iTo.(ReadSideEffectInstruction).getSideEffectOperand().getAnyDef() = iFrom and
376+
not iFrom.isResultConflated()
377+
or
378+
// Loading a single `int` from an `int *` parameter is not an exact load since
379+
// the parameter may point to an entire array rather than a single `int`. The
380+
// following rule ensures that any flow going into the
381+
// `InitializeIndirectionInstruction`, even if it's for a different array
382+
// element, will propagate to a load of the first element.
383+
//
384+
// Since we're linking `InitializeIndirectionInstruction` and
385+
// `LoadInstruction` together directly, this rule will break if there's any
386+
// reassignment of the parameter indirection, including a conditional one that
387+
// leads to a phi node.
388+
iTo.(LoadInstruction).getSourceValueOperand().getAnyDef() =
389+
iFrom.(InitializeIndirectionInstruction)
390+
or
331391
// Treat all conversions as flow, even conversions between different numeric types.
332392
iTo.(ConvertInstruction).getUnary() = iFrom
333393
or

cpp/ql/test/library-tests/dataflow/dataflow-tests/test_diff.expected

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
| lambdas.cpp:8:10:8:15 | lambdas.cpp:18:8:18:8 | AST only |
2424
| lambdas.cpp:8:10:8:15 | lambdas.cpp:21:3:21:6 | AST only |
2525
| lambdas.cpp:8:10:8:15 | lambdas.cpp:29:3:29:6 | AST only |
26-
| lambdas.cpp:8:10:8:15 | lambdas.cpp:41:8:41:8 | AST only |
2726
| lambdas.cpp:43:7:43:12 | lambdas.cpp:46:7:46:7 | AST only |
2827
| ref.cpp:29:11:29:16 | ref.cpp:62:10:62:11 | AST only |
2928
| ref.cpp:53:9:53:10 | ref.cpp:56:10:56:11 | AST only |

cpp/ql/test/library-tests/dataflow/dataflow-tests/test_ir.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
| globals.cpp:12:10:12:24 | flowTestGlobal1 | globals.cpp:13:23:13:28 | call to source |
4040
| globals.cpp:19:10:19:24 | flowTestGlobal2 | globals.cpp:23:23:23:28 | call to source |
4141
| lambdas.cpp:35:8:35:8 | a | lambdas.cpp:8:10:8:15 | call to source |
42+
| lambdas.cpp:41:8:41:8 | (reference dereference) | lambdas.cpp:8:10:8:15 | call to source |
4243
| test.cpp:7:8:7:9 | t1 | test.cpp:6:12:6:17 | call to source |
4344
| test.cpp:9:8:9:9 | t1 | test.cpp:6:12:6:17 | call to source |
4445
| test.cpp:10:8:10:9 | t2 | test.cpp:6:12:6:17 | call to source |

cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,13 @@
2020
| taint.cpp:130:7:130:9 | taint.cpp:127:8:127:13 | IR only |
2121
| taint.cpp:137:7:137:9 | taint.cpp:120:11:120:16 | AST only |
2222
| taint.cpp:173:8:173:13 | taint.cpp:164:19:164:24 | AST only |
23-
| taint.cpp:181:8:181:9 | taint.cpp:185:11:185:16 | AST only |
2423
| taint.cpp:195:7:195:7 | taint.cpp:192:23:192:28 | AST only |
2524
| taint.cpp:195:7:195:7 | taint.cpp:193:6:193:6 | AST only |
2625
| taint.cpp:216:7:216:7 | taint.cpp:207:6:207:11 | AST only |
2726
| taint.cpp:229:3:229:6 | taint.cpp:223:10:223:15 | AST only |
2827
| taint.cpp:233:8:233:8 | taint.cpp:223:10:223:15 | AST only |
2928
| taint.cpp:236:3:236:6 | taint.cpp:223:10:223:15 | AST only |
3029
| taint.cpp:244:3:244:6 | taint.cpp:223:10:223:15 | AST only |
31-
| taint.cpp:256:8:256:8 | taint.cpp:223:10:223:15 | AST only |
3230
| taint.cpp:261:7:261:7 | taint.cpp:258:7:258:12 | AST only |
3331
| taint.cpp:351:7:351:7 | taint.cpp:330:6:330:11 | AST only |
3432
| taint.cpp:352:7:352:7 | taint.cpp:330:6:330:11 | AST only |

cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@
88
| taint.cpp:151:7:151:12 | call to select | taint.cpp:151:20:151:25 | call to source |
99
| taint.cpp:167:8:167:13 | call to source | taint.cpp:167:8:167:13 | call to source |
1010
| taint.cpp:168:8:168:14 | tainted | taint.cpp:164:19:164:24 | call to source |
11+
| taint.cpp:181:8:181:9 | * ... | taint.cpp:185:11:185:16 | call to source |
1112
| taint.cpp:210:7:210:7 | x | taint.cpp:207:6:207:11 | call to source |
1213
| taint.cpp:215:7:215:7 | x | taint.cpp:207:6:207:11 | call to source |
1314
| taint.cpp:250:8:250:8 | a | taint.cpp:223:10:223:15 | call to source |
15+
| taint.cpp:256:8:256:8 | (reference dereference) | taint.cpp:223:10:223:15 | call to source |
1416
| taint.cpp:280:7:280:7 | t | taint.cpp:275:6:275:11 | call to source |
1517
| taint.cpp:289:7:289:7 | t | taint.cpp:275:6:275:11 | call to source |
1618
| taint.cpp:290:7:290:7 | x | taint.cpp:275:6:275:11 | call to source |

0 commit comments

Comments
 (0)