Skip to content

Commit fe4ae7e

Browse files
committed
C++: General solution for functions that may exit.
1 parent 8fa3ffe commit fe4ae7e

File tree

3 files changed

+21
-34
lines changed

3 files changed

+21
-34
lines changed

cpp/ql/src/experimental/Security/CWE/CWE-401/MemoryLeakOnFailedCallToRealloc.ql

Lines changed: 20 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,19 @@
1313

1414
import cpp
1515

16+
/**
17+
* A function call that potentially does not return (such as `exit`).
18+
*/
19+
class CallMayNotReturn extends FunctionCall {
20+
CallMayNotReturn() {
21+
// call that is known to not return
22+
not exists(this.(ControlFlowNode).getASuccessor())
23+
or
24+
// call to another function that may not return
25+
exists(CallMayNotReturn exit | getTarget() = exit.getEnclosingFunction())
26+
}
27+
}
28+
1629
/**
1730
* A call to `realloc` of the form `v = realloc(v, size)`, for some variable `v`.
1831
*/
@@ -30,40 +43,15 @@ class ReallocCallLeak extends FunctionCall {
3043
)
3144
}
3245

33-
predicate isExistsIfWithExitCall() {
34-
exists(IfStmt ifc |
35-
this.getArgument(0) = v.getAnAccess() and
36-
ifc.getCondition().getAChild*() = v.getAnAccess() and
37-
ifc.getEnclosingFunction() = this.getEnclosingFunction() and
38-
ifc.getLocation().getStartLine() >= this.getArgument(0).getLocation().getStartLine() and
39-
exists(FunctionCall fc |
40-
fc.getTarget().hasName("exit") and
41-
fc.getEnclosingFunction() = this.getEnclosingFunction() and
42-
(ifc.getThen().getAChild*() = fc or ifc.getElse().getAChild*() = fc)
43-
)
44-
or
45-
exists(FunctionCall fc, FunctionCall ftmp1, FunctionCall ftmp2 |
46-
ftmp1.getTarget().hasName("exit") and
47-
ftmp2.(ControlFlowNode).getASuccessor*() = ftmp1 and
48-
fc = ftmp2.getEnclosingFunction().getACallToThisFunction() and
49-
fc.getEnclosingFunction() = this.getEnclosingFunction() and
50-
(ifc.getThen().getAChild*() = fc or ifc.getElse().getAChild*() = fc)
51-
)
52-
)
53-
}
54-
55-
predicate isExistsAssertWithArgumentCall() {
56-
exists(FunctionCall fc |
57-
fc.getTarget().hasName("__assert_fail") and
58-
this.getEnclosingFunction() = fc.getEnclosingFunction() and
59-
fc.getLocation().getStartLine() > this.getArgument(0).getLocation().getEndLine() and
60-
fc.getArgument(0).toString().matches("%" + this.getArgument(0).toString() + "%")
61-
)
46+
/**
47+
* Holds if failure of this allocation may be handled by termination, for
48+
* example a call to `exit()`.
49+
*/
50+
predicate mayHandleByTermination() {
51+
this.(ControlFlowNode).getASuccessor*() instanceof CallMayNotReturn
6252
}
6353
}
6454

6555
from ReallocCallLeak rcl
66-
where
67-
not rcl.isExistsIfWithExitCall() and
68-
not rcl.isExistsAssertWithArgumentCall()
56+
where not rcl.mayHandleByTermination()
6957
select rcl, "possible loss of original pointer on unsuccessful call realloc"

cpp/ql/test/experimental/query-tests/Security/CWE/CWE-401/semmle/tests/MemoryLeakOnFailedCallToRealloc.expected

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,3 @@
44
| test.c:186:29:186:35 | call to realloc | possible loss of original pointer on unsuccessful call realloc |
55
| test.c:282:29:282:35 | call to realloc | possible loss of original pointer on unsuccessful call realloc |
66
| test.c:299:26:299:32 | call to realloc | possible loss of original pointer on unsuccessful call realloc |
7-
| test.c:316:33:316:39 | call to realloc | possible loss of original pointer on unsuccessful call realloc |

cpp/ql/test/experimental/query-tests/Security/CWE/CWE-401/semmle/tests/test.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ void abort(void);
310310

311311
unsigned char *noBadResize_4_1(unsigned char *buffer, size_t currentSize, size_t newSize)
312312
{
313-
// GOOD: program to end [FALSE POSITIVE]
313+
// GOOD: program to end
314314
if (currentSize < newSize)
315315
{
316316
if (buffer = (unsigned char *)realloc(buffer, newSize))

0 commit comments

Comments
 (0)