Skip to content

Commit 5181cc1

Browse files
committed
C++: Add a 'allowInterproceduralFlow' predicate to the 'MustFlow' library to and use it instead of checking the enclosing callables after computing the dataflow graph.
1 parent b906c1a commit 5181cc1

File tree

3 files changed

+32
-18
lines changed

3 files changed

+32
-18
lines changed

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

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ abstract class MustFlowConfiguration extends string {
3838
*/
3939
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { none() }
4040

41+
/** Holds if this configuration allows flow from arguments to parameters. */
42+
predicate allowInterproceduralFlow() { any() }
43+
4144
/**
4245
* Holds if data must flow from `source` to `sink` for this configuration.
4346
*
@@ -204,10 +207,25 @@ private module Cached {
204207
}
205208
}
206209

210+
/**
211+
* Gets the enclosing callable of `n`. Unlike `n.getEnclosingCallable()`, this
212+
* predicate ensures that joins go from `n` to the result instead of the other
213+
* way around.
214+
*/
215+
pragma[inline]
216+
private Declaration getEnclosingCallable(DataFlow::Node n) {
217+
pragma[only_bind_into](result) = pragma[only_bind_out](n).getEnclosingCallable()
218+
}
219+
207220
/** Holds if `nodeFrom` flows to `nodeTo`. */
208221
private predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, MustFlowConfiguration config) {
209222
exists(config) and
210-
Cached::step(nodeFrom, nodeTo)
223+
Cached::step(pragma[only_bind_into](nodeFrom), pragma[only_bind_into](nodeTo)) and
224+
(
225+
config.allowInterproceduralFlow()
226+
or
227+
getEnclosingCallable(nodeFrom) = getEnclosingCallable(nodeTo)
228+
)
211229
or
212230
config.isAdditionalFlowStep(nodeFrom, nodeTo)
213231
}

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

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,18 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration {
5252
)
5353
}
5454

55+
// We disable flow into callables in this query as we'd otherwise get a result on this piece of code:
56+
// ```cpp
57+
// int* id(int* px) {
58+
// return px; // this returns the local variable `x`, but it's fine as the local variable isn't declared in this scope.
59+
// }
60+
// void f() {
61+
// int x;
62+
// int* px = id(&x);
63+
// }
64+
// ```
65+
override predicate allowInterproceduralFlow() { none() }
66+
5567
/**
5668
* This configuration intentionally conflates addresses of fields and their object, and pointer offsets
5769
* with their base pointer as this allows us to detect cases where an object's address flows to a
@@ -77,9 +89,6 @@ from
7789
ReturnStackAllocatedMemoryConfig conf
7890
where
7991
conf.hasFlowPath(pragma[only_bind_into](source), pragma[only_bind_into](sink)) and
80-
source.getNode().asInstruction() = var and
81-
// Only raise an alert if we're returning from the _same_ callable as the on that
82-
// declared the stack variable.
83-
var.getEnclosingFunction() = sink.getNode().getEnclosingCallable()
92+
source.getNode().asInstruction() = var
8493
select sink.getNode(), source, sink, "May return stack-allocated memory from $@.", var.getAst(),
8594
var.getAst().toString()

cpp/ql/test/query-tests/Likely Bugs/Memory Management/ReturnStackAllocatedMemory/ReturnStackAllocatedMemory.expected

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -100,12 +100,6 @@ edges
100100
| test.cpp:190:10:190:13 | Unary | test.cpp:190:10:190:13 | (reference dereference) |
101101
| test.cpp:190:10:190:13 | Unary | test.cpp:190:10:190:13 | (reference to) |
102102
| test.cpp:190:10:190:13 | pRef | test.cpp:190:10:190:13 | Unary |
103-
| test.cpp:225:14:225:15 | px | test.cpp:226:10:226:11 | Load |
104-
| test.cpp:226:10:226:11 | Load | test.cpp:226:10:226:11 | px |
105-
| test.cpp:226:10:226:11 | px | test.cpp:226:10:226:11 | StoreValue |
106-
| test.cpp:231:16:231:17 | & ... | test.cpp:225:14:225:15 | px |
107-
| test.cpp:231:17:231:17 | Unary | test.cpp:231:16:231:17 | & ... |
108-
| test.cpp:231:17:231:17 | x | test.cpp:231:17:231:17 | Unary |
109103
nodes
110104
| test.cpp:17:9:17:11 | & ... | semmle.label | & ... |
111105
| test.cpp:17:9:17:11 | StoreValue | semmle.label | StoreValue |
@@ -221,13 +215,6 @@ nodes
221215
| test.cpp:190:10:190:13 | Unary | semmle.label | Unary |
222216
| test.cpp:190:10:190:13 | Unary | semmle.label | Unary |
223217
| test.cpp:190:10:190:13 | pRef | semmle.label | pRef |
224-
| test.cpp:225:14:225:15 | px | semmle.label | px |
225-
| test.cpp:226:10:226:11 | Load | semmle.label | Load |
226-
| test.cpp:226:10:226:11 | StoreValue | semmle.label | StoreValue |
227-
| test.cpp:226:10:226:11 | px | semmle.label | px |
228-
| test.cpp:231:16:231:17 | & ... | semmle.label | & ... |
229-
| test.cpp:231:17:231:17 | Unary | semmle.label | Unary |
230-
| test.cpp:231:17:231:17 | x | semmle.label | x |
231218
#select
232219
| test.cpp:17:9:17:11 | StoreValue | test.cpp:17:10:17:11 | mc | test.cpp:17:9:17:11 | StoreValue | May return stack-allocated memory from $@. | test.cpp:17:10:17:11 | mc | mc |
233220
| test.cpp:25:9:25:11 | StoreValue | test.cpp:23:18:23:19 | mc | test.cpp:25:9:25:11 | StoreValue | May return stack-allocated memory from $@. | test.cpp:23:18:23:19 | mc | mc |

0 commit comments

Comments
 (0)