Skip to content

Commit c2ac60f

Browse files
authored
Merge pull request github#11311 from MathiasVP/repair-mustflow
C++: Repair `MustFlow` library for use-use flow
2 parents 6c33ddc + 7e80a57 commit c2ac60f

File tree

6 files changed

+167
-316
lines changed

6 files changed

+167
-316
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: breaking
3+
---
4+
The predicates in the `MustFlow::Configuration` class used by the `MustFlow` library (`semmle.code.cpp.ir.dataflow.MustFlow`) have changed to be defined directly in terms of the C++ IR instead of IR dataflow nodes.

cpp/ql/lib/semmle/code/cpp/ir/dataflow/MustFlow.qll

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
*/
66

77
private import cpp
8-
import semmle.code.cpp.ir.dataflow.DataFlow
98
private import semmle.code.cpp.ir.IR
109

1110
/**
@@ -25,18 +24,18 @@ abstract class MustFlowConfiguration extends string {
2524
/**
2625
* Holds if `source` is a relevant data flow source.
2726
*/
28-
abstract predicate isSource(DataFlow::Node source);
27+
abstract predicate isSource(Instruction source);
2928

3029
/**
3130
* Holds if `sink` is a relevant data flow sink.
3231
*/
33-
abstract predicate isSink(DataFlow::Node sink);
32+
abstract predicate isSink(Operand sink);
3433

3534
/**
3635
* Holds if the additional flow step from `node1` to `node2` must be taken
3736
* into account in the analysis.
3837
*/
39-
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { none() }
38+
predicate isAdditionalFlowStep(Operand node1, Instruction node2) { none() }
4039

4140
/** Holds if this configuration allows flow from arguments to parameters. */
4241
predicate allowInterproceduralFlow() { any() }
@@ -48,30 +47,30 @@ abstract class MustFlowConfiguration extends string {
4847
* included in the module `PathGraph`.
4948
*/
5049
final predicate hasFlowPath(MustFlowPathNode source, MustFlowPathSink sink) {
51-
this.isSource(source.getNode()) and
50+
this.isSource(source.getInstruction()) and
5251
source.getASuccessor+() = sink
5352
}
5453
}
5554

5655
/** Holds if `node` flows from a source. */
5756
pragma[nomagic]
58-
private predicate flowsFromSource(DataFlow::Node node, MustFlowConfiguration config) {
57+
private predicate flowsFromSource(Instruction node, MustFlowConfiguration config) {
5958
config.isSource(node)
6059
or
61-
exists(DataFlow::Node mid |
60+
exists(Instruction mid |
6261
step(mid, node, config) and
6362
flowsFromSource(mid, pragma[only_bind_into](config))
6463
)
6564
}
6665

6766
/** Holds if `node` flows to a sink. */
6867
pragma[nomagic]
69-
private predicate flowsToSink(DataFlow::Node node, MustFlowConfiguration config) {
68+
private predicate flowsToSink(Instruction node, MustFlowConfiguration config) {
7069
flowsFromSource(node, pragma[only_bind_into](config)) and
7170
(
72-
config.isSink(node)
71+
config.isSink(node.getAUse())
7372
or
74-
exists(DataFlow::Node mid |
73+
exists(Instruction mid |
7574
step(node, mid, config) and
7675
flowsToSink(mid, pragma[only_bind_into](config))
7776
)
@@ -198,12 +197,13 @@ private module Cached {
198197
}
199198

200199
cached
201-
predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
202-
instructionToOperandStep(nodeFrom.asInstruction(), nodeTo.asOperand())
203-
or
204-
flowThroughCallable(nodeFrom.asInstruction(), nodeTo.asInstruction())
200+
predicate step(Instruction nodeFrom, Instruction nodeTo) {
201+
exists(Operand mid |
202+
instructionToOperandStep(nodeFrom, mid) and
203+
operandToInstructionStep(mid, nodeTo)
204+
)
205205
or
206-
operandToInstructionStep(nodeFrom.asOperand(), nodeTo.asInstruction())
206+
flowThroughCallable(nodeFrom, nodeTo)
207207
}
208208
}
209209

@@ -213,12 +213,12 @@ private module Cached {
213213
* way around.
214214
*/
215215
pragma[inline]
216-
private Declaration getEnclosingCallable(DataFlow::Node n) {
217-
pragma[only_bind_into](result) = pragma[only_bind_out](n).getEnclosingCallable()
216+
private IRFunction getEnclosingCallable(Instruction n) {
217+
pragma[only_bind_into](result) = pragma[only_bind_out](n).getEnclosingIRFunction()
218218
}
219219

220220
/** Holds if `nodeFrom` flows to `nodeTo`. */
221-
private predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, MustFlowConfiguration config) {
221+
private predicate step(Instruction nodeFrom, Instruction nodeTo, MustFlowConfiguration config) {
222222
exists(config) and
223223
Cached::step(pragma[only_bind_into](nodeFrom), pragma[only_bind_into](nodeTo)) and
224224
(
@@ -227,45 +227,45 @@ private predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, MustFlowC
227227
getEnclosingCallable(nodeFrom) = getEnclosingCallable(nodeTo)
228228
)
229229
or
230-
config.isAdditionalFlowStep(nodeFrom, nodeTo)
230+
config.isAdditionalFlowStep(nodeFrom.getAUse(), nodeTo)
231231
}
232232

233233
private newtype TLocalPathNode =
234-
MkLocalPathNode(DataFlow::Node n, MustFlowConfiguration config) {
234+
MkLocalPathNode(Instruction n, MustFlowConfiguration config) {
235235
flowsToSink(n, config) and
236236
(
237237
config.isSource(n)
238238
or
239-
exists(MustFlowPathNode mid | step(mid.getNode(), n, config))
239+
exists(MustFlowPathNode mid | step(mid.getInstruction(), n, config))
240240
)
241241
}
242242

243243
/** A `Node` that is in a path from a source to a sink. */
244244
class MustFlowPathNode extends TLocalPathNode {
245-
DataFlow::Node n;
245+
Instruction n;
246246

247247
MustFlowPathNode() { this = MkLocalPathNode(n, _) }
248248

249249
/** Gets the underlying node. */
250-
DataFlow::Node getNode() { result = n }
250+
Instruction getInstruction() { result = n }
251251

252252
/** Gets a textual representation of this node. */
253-
string toString() { result = n.toString() }
253+
string toString() { result = n.getAst().toString() }
254254

255255
/** Gets the location of this element. */
256256
Location getLocation() { result = n.getLocation() }
257257

258258
/** Gets a successor node, if any. */
259259
MustFlowPathNode getASuccessor() {
260-
step(this.getNode(), result.getNode(), this.getConfiguration())
260+
step(this.getInstruction(), result.getInstruction(), this.getConfiguration())
261261
}
262262

263263
/** Gets the associated configuration. */
264264
MustFlowConfiguration getConfiguration() { this = MkLocalPathNode(_, result) }
265265
}
266266

267267
private class MustFlowPathSink extends MustFlowPathNode {
268-
MustFlowPathSink() { this.getConfiguration().isSink(this.getNode()) }
268+
MustFlowPathSink() { this.getConfiguration().isSink(this.getInstruction().getAUse()) }
269269
}
270270

271271
/**

cpp/ql/src/Likely Bugs/Memory Management/ReturnStackAllocatedMemory.ql

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@ predicate intentionallyReturnsStackPointer(Function f) {
2626
class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration {
2727
ReturnStackAllocatedMemoryConfig() { this = "ReturnStackAllocatedMemoryConfig" }
2828

29-
override predicate isSource(DataFlow::Node source) {
29+
override predicate isSource(Instruction source) {
3030
// Holds if `source` is a node that represents the use of a stack variable
3131
exists(VariableAddressInstruction var, Function func |
32-
var = source.asInstruction() and
33-
func = var.getEnclosingFunction() and
32+
var = source and
33+
func = source.getEnclosingFunction() and
3434
var.getAstVariable() instanceof StackVariable and
3535
// Pointer-to-member types aren't properly handled in the dbscheme.
3636
not var.getResultType() instanceof PointerToMemberType and
@@ -40,15 +40,15 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration {
4040
)
4141
}
4242

43-
override predicate isSink(DataFlow::Node sink) {
43+
override predicate isSink(Operand sink) {
4444
// Holds if `sink` is a node that represents the `StoreInstruction` that is subsequently used in
4545
// a `ReturnValueInstruction`.
4646
// We use the `StoreInstruction` instead of the instruction that defines the
4747
// `ReturnValueInstruction`'s source value operand because the former has better location information.
4848
exists(StoreInstruction store |
4949
store.getDestinationAddress().(VariableAddressInstruction).getIRVariable() instanceof
5050
IRReturnVariable and
51-
sink.asOperand() = store.getSourceValueOperand()
51+
sink = store.getSourceValueOperand()
5252
)
5353
}
5454

@@ -77,10 +77,10 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration {
7777
* }
7878
* ```
7979
*/
80-
override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
81-
node2.asInstruction().(FieldAddressInstruction).getObjectAddressOperand() = node1.asOperand()
80+
override predicate isAdditionalFlowStep(Operand node1, Instruction node2) {
81+
node2.(FieldAddressInstruction).getObjectAddressOperand() = node1
8282
or
83-
node2.asInstruction().(PointerOffsetInstruction).getLeftOperand() = node1.asOperand()
83+
node2.(PointerOffsetInstruction).getLeftOperand() = node1
8484
}
8585
}
8686

@@ -89,6 +89,6 @@ from
8989
ReturnStackAllocatedMemoryConfig conf
9090
where
9191
conf.hasFlowPath(pragma[only_bind_into](source), pragma[only_bind_into](sink)) and
92-
source.getNode().asInstruction() = var
93-
select sink.getNode(), source, sink, "May return stack-allocated memory from $@.", var.getAst(),
94-
var.getAst().toString()
92+
source.getInstruction() = var
93+
select sink.getInstruction(), source, sink, "May return stack-allocated memory from $@.",
94+
var.getAst(), var.getAst().toString()

cpp/ql/src/Likely Bugs/OO/UnsafeUseOfThis.ql

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -22,37 +22,40 @@ import PathGraph
2222
class UnsafeUseOfThisConfig extends MustFlowConfiguration {
2323
UnsafeUseOfThisConfig() { this = "UnsafeUseOfThisConfig" }
2424

25-
override predicate isSource(DataFlow::Node source) { isSource(source, _, _) }
25+
override predicate isSource(Instruction source) { isSource(source, _, _) }
2626

27-
override predicate isSink(DataFlow::Node sink) { isSink(sink, _) }
27+
override predicate isSink(Operand sink) { isSink(sink, _) }
2828
}
2929

30-
/** Holds if `instr` is a `this` pointer used by the call instruction `call`. */
31-
predicate isSink(DataFlow::Node sink, CallInstruction call) {
30+
/** Holds if `sink` is a `this` pointer used by the call instruction `call`. */
31+
predicate isSink(Operand sink, CallInstruction call) {
3232
exists(PureVirtualFunction func |
3333
call.getStaticCallTarget() = func and
34-
call.getThisArgument() = sink.asInstruction() and
34+
call.getThisArgumentOperand() = sink and
3535
// Weed out implicit calls to destructors of a base class
3636
not func instanceof Destructor
3737
)
3838
}
3939

40-
/** Holds if `init` initializes the `this` pointer in class `c`. */
41-
predicate isSource(DataFlow::Node source, string msg, Class c) {
42-
exists(InitializeParameterInstruction init | init = source.asInstruction() |
43-
(
44-
exists(Constructor func |
45-
not func instanceof CopyConstructor and
46-
not func instanceof MoveConstructor and
47-
func = init.getEnclosingFunction() and
48-
msg = "construction"
49-
)
50-
or
51-
init.getEnclosingFunction() instanceof Destructor and msg = "destruction"
52-
) and
53-
init.getIRVariable() instanceof IRThisVariable and
54-
init.getEnclosingFunction().getDeclaringType() = c
55-
)
40+
/**
41+
* Holds if `source` initializes the `this` pointer in class `c`.
42+
*
43+
* The string `msg` describes whether the enclosing function is a
44+
* constructor or destructor.
45+
*/
46+
predicate isSource(InitializeParameterInstruction source, string msg, Class c) {
47+
(
48+
exists(Constructor func |
49+
not func instanceof CopyConstructor and
50+
not func instanceof MoveConstructor and
51+
func = source.getEnclosingFunction() and
52+
msg = "construction"
53+
)
54+
or
55+
source.getEnclosingFunction() instanceof Destructor and msg = "destruction"
56+
) and
57+
source.getIRVariable() instanceof IRThisVariable and
58+
source.getEnclosingFunction().getDeclaringType() = c
5659
}
5760

5861
/**
@@ -68,8 +71,8 @@ predicate flows(
6871
) {
6972
exists(UnsafeUseOfThisConfig conf |
7073
conf.hasFlowPath(source, sink) and
71-
isSource(source.getNode(), msg, sourceClass) and
72-
isSink(sink.getNode(), call)
74+
isSource(source.getInstruction(), msg, sourceClass) and
75+
isSink(sink.getInstruction().getAUse(), call)
7376
)
7477
}
7578

0 commit comments

Comments
 (0)