mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
Add files via upload
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
// BAD: no memory allocation errors are detected
|
||||
void f(const int *array, std::size_t size) noexcept {
|
||||
int *copy = new int[size];
|
||||
std::memcpy(copy, array, size * sizeof(*copy));
|
||||
// ...
|
||||
delete [] copy;
|
||||
}
|
||||
// GOOD: memory allocation errors are detected
|
||||
void f(const int *array, std::size_t size) noexcept {
|
||||
int *copy;
|
||||
try {
|
||||
copy = new int[size];
|
||||
} catch(std::bad_alloc) {
|
||||
// Handle error
|
||||
return;
|
||||
}
|
||||
// At this point, copy has been initialized to allocated memory
|
||||
std::memcpy(copy, array, size * sizeof(*copy));
|
||||
// ...
|
||||
delete [] copy;
|
||||
}
|
||||
// GOOD: memory allocation errors are detected
|
||||
void f(const int *array, std::size_t size) noexcept {
|
||||
int *copy = new (std::nothrow) int[size];
|
||||
if (!copy) {
|
||||
// Handle error
|
||||
return;
|
||||
}
|
||||
std::memcpy(copy, array, size * sizeof(*copy));
|
||||
// ...
|
||||
delete [] copy;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>when using the new operator to allocate memory, you need to pay attention to the different way of detecting errors. so <code> ::operator new(std::size_t) </code> throws an exception on error, and <code> ::operator new(std::size_t, const std::nothrow_t &) </code> returns zero on error. the programmer can get confused and check the error that occurs when allocating memory incorrectly. That can lead to an unhandled program termination or to a violation of the program logic.</p>
|
||||
|
||||
<p>Loss of detection probably refers to use cases where memory allocation using your own solutions with strong nesting. It is also possible when using a buffer in the form of fields of different structures with the same names.</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
<p>We recommend using the error detection method, depending on the selected memory allocation method.</code>.</p>
|
||||
|
||||
</recommendation>
|
||||
<example>
|
||||
<p>The following file demonstrates various approaches to detecting memory allocation errors using the new operator.</p>
|
||||
<sample src="WrongInDetectingAndHandlingMemoryAllocationErrors.cpp" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
|
||||
<li>
|
||||
CERT C++ Coding Standard:
|
||||
<a href="https://wiki.sei.cmu.edu/confluence/display/cplusplus/MEM52-CPP.+Detect+and+handle+memory+allocation+errors">MEM52-CPP. Detect and handle memory allocation errors</a>.
|
||||
</li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* @name Сonfusion In Detecting And Handling Memory Allocation Errors
|
||||
* @description --::operator new(std::size_t) throws an exception on error, and ::operator new(std::size_t, const std::nothrow_t &) returns zero on error.
|
||||
* --the programmer can get confused when check the error that occurs when allocating memory incorrectly.
|
||||
* --Making a call of this type may result in a zero byte being written just outside the buffer.
|
||||
* @kind problem
|
||||
* @id cpp/detect-and-handle-memory-allocation-errors
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @tags correctness
|
||||
* security
|
||||
* external/cwe/cwe-570
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
/**
|
||||
* Lookup if condition compare with 0
|
||||
*/
|
||||
class IfCompareWithZero extends IfStmt {
|
||||
IfCompareWithZero() {
|
||||
this.getCondition().(EQExpr).getAChild().getValue() = "0"
|
||||
or
|
||||
this.getCondition().(NEExpr).getAChild().getValue() = "0" and
|
||||
this.hasElse()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* lookup for calls to `operator new`, with incorrect error handling.
|
||||
*/
|
||||
class WrongCheckErrorOperatorNew extends FunctionCall {
|
||||
Expr exp;
|
||||
|
||||
WrongCheckErrorOperatorNew() {
|
||||
this = exp.(NewOrNewArrayExpr).getAChild().(FunctionCall) and
|
||||
(
|
||||
this.getTarget().hasGlobalOrStdName("operator new")
|
||||
or
|
||||
this.getTarget().hasGlobalOrStdName("operator new[]")
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if handler `try ... catch` exists.
|
||||
*/
|
||||
predicate isExistsTryCatchBlock() {
|
||||
exists(TryStmt tb, AssignExpr aex, Initializer it |
|
||||
tb.getAChild*() = exp
|
||||
or
|
||||
exp = it.getExpr() and
|
||||
tb.getAChild*().(DeclStmt).getADeclaration() = it.getDeclaration()
|
||||
or
|
||||
aex.getAChild*() = exp and
|
||||
tb.getAChild*().(AssignExpr) = aex
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if results call `operator new` check in `operator if`.
|
||||
*/
|
||||
predicate isExistsIfCondition() {
|
||||
exists(IfCompareWithZero ifc, AssignExpr aex, Initializer it |
|
||||
// call `operator new` directly from the condition of `operator if`.
|
||||
this = ifc.getCondition().getAChild()
|
||||
or
|
||||
// check results call `operator new` with variable appropriation
|
||||
postDominates(ifc, this) and
|
||||
aex.getAChild() = exp and
|
||||
ifc.getCondition().getAChild().(VariableAccess).getTarget() =
|
||||
aex.getLValue().(VariableAccess).getTarget()
|
||||
or
|
||||
// check results call `operator new` with declaration variable
|
||||
postDominates(ifc, this) and
|
||||
exp = it.getExpr() and
|
||||
it.getDeclaration() = ifc.getCondition().getAChild().(VariableAccess).getTarget()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(std::nothrow)` exists in call `operator new`.
|
||||
*/
|
||||
predicate isExistsNothrow() { this.getAChild().toString() = "nothrow" }
|
||||
}
|
||||
|
||||
from WrongCheckErrorOperatorNew op
|
||||
where
|
||||
// use call `operator new` with `(std::nothrow)` and checking error using `try ... catch` block and not `operator if`
|
||||
op.isExistsNothrow() and not op.isExistsIfCondition() and op.isExistsTryCatchBlock()
|
||||
or
|
||||
// use call `operator new` without `(std::nothrow)` and checking error using `operator if` and not `try ... catch` block
|
||||
not op.isExistsNothrow() and not op.isExistsTryCatchBlock() and op.isExistsIfCondition()
|
||||
select op, "memory allocation error check is incorrect or missing"
|
||||
Reference in New Issue
Block a user