Skip to content

Commit 128053e

Browse files
committed
C++: Add basic modeling of functions that don't throw
1 parent c4c8c9d commit 128053e

File tree

8 files changed

+39
-8
lines changed

8 files changed

+39
-8
lines changed

cpp/ql/lib/semmle/code/cpp/models/implementations/Memcpy.qll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,14 @@ import semmle.code.cpp.models.interfaces.DataFlow
99
import semmle.code.cpp.models.interfaces.Alias
1010
import semmle.code.cpp.models.interfaces.SideEffect
1111
import semmle.code.cpp.models.interfaces.Taint
12+
import semmle.code.cpp.models.interfaces.NonThrowing
1213

1314
/**
1415
* The standard functions `memcpy`, `memmove` and `bcopy`; and the gcc variant
1516
* `__builtin___memcpy_chk`.
1617
*/
1718
private class MemcpyFunction extends ArrayFunction, DataFlowFunction, SideEffectFunction,
18-
AliasFunction
19+
AliasFunction, NonThrowingFunction
1920
{
2021
MemcpyFunction() {
2122
// memcpy(dest, src, num)

cpp/ql/lib/semmle/code/cpp/models/implementations/Memset.qll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ import semmle.code.cpp.models.interfaces.ArrayFunction
88
import semmle.code.cpp.models.interfaces.DataFlow
99
import semmle.code.cpp.models.interfaces.Alias
1010
import semmle.code.cpp.models.interfaces.SideEffect
11+
import semmle.code.cpp.models.interfaces.NonThrowing
1112

1213
private class MemsetFunctionModel extends ArrayFunction, DataFlowFunction, AliasFunction,
13-
SideEffectFunction
14+
SideEffectFunction, NonThrowingFunction
1415
{
1516
MemsetFunctionModel() {
1617
this.hasGlobalOrStdOrBslName("memset")
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import semmle.code.cpp.models.interfaces.NonThrowing
2+
3+
/**
4+
* A function that is annotated with a `noexcept` specifier (or the equivalent
5+
* `throw()` specifier) guaranteeing that the function can not throw exceptions.
6+
*
7+
* Note: The `throw` specifier was deprecated in C++11 and removed in C++17.
8+
*/
9+
class NoexceptFunction extends NonThrowingFunction {
10+
NoexceptFunction() { this.isNoExcept() or this.isNoThrow() }
11+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* Provides an abstract class for modeling functions that never throws.
3+
*
4+
* See also `ThrowingFunction` for modeling functions that do throw.
5+
*/
6+
7+
import semmle.code.cpp.Function
8+
import semmle.code.cpp.models.Models
9+
10+
/**
11+
* A function that is guaranteed to never throw.
12+
*/
13+
abstract class NonThrowingFunction extends Function { }

cpp/ql/src/Security/CWE/CWE-570/IncorrectAllocationErrorHandling.ql

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
import cpp
1717
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
1818
import semmle.code.cpp.controlflow.Guards
19+
import semmle.code.cpp.models.interfaces.NonThrowing
20+
import semmle.code.cpp.models.implementations.NoexceptFunction
1921

2022
/** Gets the `Constructor` invoked when `newExpr` allocates memory. */
2123
Constructor getConstructorForAllocation(NewOrNewArrayExpr newExpr) {
@@ -44,9 +46,8 @@ predicate deleteMayThrow(DeleteOrDeleteArrayExpr deleteExpr) {
4446
* like it might throw an exception, and the function does not have a `noexcept` or `throw()` specifier.
4547
*/
4648
predicate functionMayThrow(Function f) {
47-
(not exists(f.getBlock()) or stmtMayThrow(f.getBlock())) and
48-
not f.isNoExcept() and
49-
not f.isNoThrow()
49+
not f instanceof NonThrowingFunction and
50+
(not exists(f.getBlock()) or stmtMayThrow(f.getBlock()))
5051
}
5152

5253
/** Holds if the evaluation of `stmt` may throw an exception. */
@@ -172,8 +173,7 @@ class ThrowingAllocator extends Function {
172173
not exists(Parameter p | p = this.getAParameter() |
173174
p.getUnspecifiedType().stripType() instanceof NoThrowType
174175
) and
175-
not this.isNoExcept() and
176-
not this.isNoThrow()
176+
not this instanceof NoexceptFunction
177177
)
178178
}
179179
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Add modeling of C functions that don't throw, thereby increasing the precision of the `cpp/incorrect-allocation-error-handling` ("Incorrect allocation-error handling") query. The query now produces additional true positives.

cpp/ql/test/query-tests/Security/CWE/CWE-570/IncorrectAllocationErrorHandling.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@
1717
| test.cpp:229:15:229:35 | new | This allocation cannot throw. $@ is unnecessary. | test.cpp:231:16:231:19 | { ... } | This catch block |
1818
| test.cpp:242:14:242:34 | new | This allocation cannot throw. $@ is unnecessary. | test.cpp:243:34:243:36 | { ... } | This catch block |
1919
| test.cpp:276:17:276:31 | new[] | This allocation cannot return null. $@ is unnecessary. | test.cpp:277:8:277:12 | ! ... | This check |
20+
| test.cpp:288:19:288:47 | new[] | This allocation cannot throw. $@ is unnecessary. | test.cpp:291:30:293:5 | { ... } | This catch block |

cpp/ql/test/query-tests/Security/CWE/CWE-570/test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ namespace qhelp {
282282
}
283283

284284
// BAD: the allocation won't throw an exception, but
285-
// instead return a null pointer. [NOT DETECTED]
285+
// instead return a null pointer.
286286
void bad2(std::size_t length) noexcept {
287287
try {
288288
int* dest = new(std::nothrow) int[length];

0 commit comments

Comments
 (0)