mirror of
https://github.com/github/codeql.git
synced 2026-04-20 14:34:04 +02:00
Merge pull request #17298 from paldepind/model-functions-that-dont-throw
C++: Add basic modeling of functions that don't throw
This commit is contained in:
@@ -42,6 +42,7 @@ private import implementations.Accept
|
||||
private import implementations.Poll
|
||||
private import implementations.Select
|
||||
private import implementations.MySql
|
||||
private import implementations.NoexceptFunction
|
||||
private import implementations.ODBC
|
||||
private import implementations.SqLite3
|
||||
private import implementations.PostgreSql
|
||||
|
||||
@@ -9,13 +9,14 @@ import semmle.code.cpp.models.interfaces.DataFlow
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
import semmle.code.cpp.models.interfaces.Taint
|
||||
import semmle.code.cpp.models.interfaces.NonThrowing
|
||||
|
||||
/**
|
||||
* The standard functions `memcpy`, `memmove` and `bcopy`; and the gcc variant
|
||||
* `__builtin___memcpy_chk`.
|
||||
*/
|
||||
private class MemcpyFunction extends ArrayFunction, DataFlowFunction, SideEffectFunction,
|
||||
AliasFunction
|
||||
AliasFunction, NonThrowingFunction
|
||||
{
|
||||
MemcpyFunction() {
|
||||
// memcpy(dest, src, num)
|
||||
|
||||
@@ -8,9 +8,10 @@ import semmle.code.cpp.models.interfaces.ArrayFunction
|
||||
import semmle.code.cpp.models.interfaces.DataFlow
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
import semmle.code.cpp.models.interfaces.NonThrowing
|
||||
|
||||
private class MemsetFunctionModel extends ArrayFunction, DataFlowFunction, AliasFunction,
|
||||
SideEffectFunction
|
||||
SideEffectFunction, NonThrowingFunction
|
||||
{
|
||||
MemsetFunctionModel() {
|
||||
this.hasGlobalOrStdOrBslName("memset")
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import semmle.code.cpp.models.interfaces.NonThrowing
|
||||
|
||||
/**
|
||||
* A function that is annotated with a `noexcept` specifier (or the equivalent
|
||||
* `throw()` specifier) guaranteeing that the function can not throw exceptions.
|
||||
*
|
||||
* Note: The `throw` specifier was deprecated in C++11 and removed in C++17.
|
||||
*/
|
||||
class NoexceptFunction extends NonThrowingFunction {
|
||||
NoexceptFunction() { this.isNoExcept() or this.isNoThrow() }
|
||||
}
|
||||
@@ -8,11 +8,12 @@
|
||||
import semmle.code.cpp.models.interfaces.FormattingFunction
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
import semmle.code.cpp.models.interfaces.NonThrowing
|
||||
|
||||
/**
|
||||
* The standard functions `printf`, `wprintf` and their glib variants.
|
||||
*/
|
||||
private class Printf extends FormattingFunction, AliasFunction {
|
||||
private class Printf extends FormattingFunction, AliasFunction, NonThrowingFunction {
|
||||
Printf() {
|
||||
this instanceof TopLevelFunction and
|
||||
(
|
||||
@@ -36,7 +37,7 @@ private class Printf extends FormattingFunction, AliasFunction {
|
||||
/**
|
||||
* The standard functions `fprintf`, `fwprintf` and their glib variants.
|
||||
*/
|
||||
private class Fprintf extends FormattingFunction {
|
||||
private class Fprintf extends FormattingFunction, NonThrowingFunction {
|
||||
Fprintf() {
|
||||
this instanceof TopLevelFunction and
|
||||
(
|
||||
@@ -54,7 +55,7 @@ private class Fprintf extends FormattingFunction {
|
||||
/**
|
||||
* The standard function `sprintf` and its Microsoft and glib variants.
|
||||
*/
|
||||
private class Sprintf extends FormattingFunction {
|
||||
private class Sprintf extends FormattingFunction, NonThrowingFunction {
|
||||
Sprintf() {
|
||||
this instanceof TopLevelFunction and
|
||||
(
|
||||
@@ -97,7 +98,7 @@ private class Sprintf extends FormattingFunction {
|
||||
/**
|
||||
* Implements `Snprintf`.
|
||||
*/
|
||||
private class SnprintfImpl extends Snprintf, AliasFunction, SideEffectFunction {
|
||||
private class SnprintfImpl extends Snprintf, AliasFunction, SideEffectFunction, NonThrowingFunction {
|
||||
SnprintfImpl() {
|
||||
this instanceof TopLevelFunction and
|
||||
(
|
||||
@@ -204,7 +205,7 @@ private class StringCchPrintf extends FormattingFunction {
|
||||
/**
|
||||
* The standard function `syslog`.
|
||||
*/
|
||||
private class Syslog extends FormattingFunction {
|
||||
private class Syslog extends FormattingFunction, NonThrowingFunction {
|
||||
Syslog() {
|
||||
this instanceof TopLevelFunction and
|
||||
this.hasGlobalName("syslog") and
|
||||
|
||||
@@ -7,13 +7,16 @@ import semmle.code.cpp.models.interfaces.ArrayFunction
|
||||
import semmle.code.cpp.models.interfaces.DataFlow
|
||||
import semmle.code.cpp.models.interfaces.Taint
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
import semmle.code.cpp.models.interfaces.NonThrowing
|
||||
|
||||
/**
|
||||
* The standard function `strcat` and its wide, sized, and Microsoft variants.
|
||||
*
|
||||
* Does not include `strlcat`, which is covered by `StrlcatFunction`
|
||||
*/
|
||||
class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, SideEffectFunction {
|
||||
class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, SideEffectFunction,
|
||||
NonThrowingFunction
|
||||
{
|
||||
StrcatFunction() {
|
||||
this.hasGlobalOrStdOrBslName([
|
||||
"strcat", // strcat(dst, src)
|
||||
|
||||
@@ -7,11 +7,14 @@ import semmle.code.cpp.models.interfaces.ArrayFunction
|
||||
import semmle.code.cpp.models.interfaces.DataFlow
|
||||
import semmle.code.cpp.models.interfaces.Taint
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
import semmle.code.cpp.models.interfaces.NonThrowing
|
||||
|
||||
/**
|
||||
* The standard function `strcpy` and its wide, sized, and Microsoft variants.
|
||||
*/
|
||||
class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, SideEffectFunction {
|
||||
class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, SideEffectFunction,
|
||||
NonThrowingFunction
|
||||
{
|
||||
StrcpyFunction() {
|
||||
this.hasGlobalOrStdOrBslName([
|
||||
"strcpy", // strcpy(dst, src)
|
||||
|
||||
11
cpp/ql/lib/semmle/code/cpp/models/interfaces/NonThrowing.qll
Normal file
11
cpp/ql/lib/semmle/code/cpp/models/interfaces/NonThrowing.qll
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Provides an abstract class for modeling functions that never throw.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.Function
|
||||
import semmle.code.cpp.models.Models
|
||||
|
||||
/**
|
||||
* A function that is guaranteed to never throw.
|
||||
*/
|
||||
abstract class NonThrowingFunction extends Function { }
|
||||
@@ -16,6 +16,7 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
||||
import semmle.code.cpp.controlflow.Guards
|
||||
import semmle.code.cpp.models.implementations.NoexceptFunction
|
||||
|
||||
/** Gets the `Constructor` invoked when `newExpr` allocates memory. */
|
||||
Constructor getConstructorForAllocation(NewOrNewArrayExpr newExpr) {
|
||||
@@ -44,9 +45,8 @@ predicate deleteMayThrow(DeleteOrDeleteArrayExpr deleteExpr) {
|
||||
* like it might throw an exception, and the function does not have a `noexcept` or `throw()` specifier.
|
||||
*/
|
||||
predicate functionMayThrow(Function f) {
|
||||
(not exists(f.getBlock()) or stmtMayThrow(f.getBlock())) and
|
||||
not f.isNoExcept() and
|
||||
not f.isNoThrow()
|
||||
not f instanceof NonThrowingFunction and
|
||||
(not exists(f.getBlock()) or stmtMayThrow(f.getBlock()))
|
||||
}
|
||||
|
||||
/** Holds if the evaluation of `stmt` may throw an exception. */
|
||||
@@ -172,8 +172,7 @@ class ThrowingAllocator extends Function {
|
||||
not exists(Parameter p | p = this.getAParameter() |
|
||||
p.getUnspecifiedType().stripType() instanceof NoThrowType
|
||||
) and
|
||||
not this.isNoExcept() and
|
||||
not this.isNoThrow()
|
||||
not this instanceof NoexceptFunction
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* 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.
|
||||
@@ -17,3 +17,4 @@
|
||||
| test.cpp:229:15:229:35 | new | This allocation cannot throw. $@ is unnecessary. | test.cpp:231:16:231:19 | { ... } | This catch block |
|
||||
| test.cpp:242:14:242:34 | new | This allocation cannot throw. $@ is unnecessary. | test.cpp:243:34:243:36 | { ... } | This catch block |
|
||||
| test.cpp:276:17:276:31 | new[] | This allocation cannot return null. $@ is unnecessary. | test.cpp:277:8:277:12 | ! ... | This check |
|
||||
| test.cpp:288:19:288:47 | new[] | This allocation cannot throw. $@ is unnecessary. | test.cpp:291:30:293:5 | { ... } | This catch block |
|
||||
|
||||
@@ -282,7 +282,7 @@ namespace qhelp {
|
||||
}
|
||||
|
||||
// BAD: the allocation won't throw an exception, but
|
||||
// instead return a null pointer. [NOT DETECTED]
|
||||
// instead return a null pointer.
|
||||
void bad2(std::size_t length) noexcept {
|
||||
try {
|
||||
int* dest = new(std::nothrow) int[length];
|
||||
|
||||
Reference in New Issue
Block a user