Merge pull request #21621 from mrc0mmand/lgtm-false-positive

lgtm: ignore certain cleanup functions
This commit is contained in:
Zbigniew Jędrzejewski-Szmek
2021-12-06 11:31:38 +01:00
committed by GitHub
@@ -16,22 +16,11 @@
import cpp
import semmle.code.cpp.controlflow.StackVariableReachability
/**
* Auxiliary predicate: Types that don't require initialization
* before they are used, since they're stack-allocated.
*/
predicate allocatedType(Type t) {
/* Arrays: "int foo[1]; foo[0] = 42;" is ok. */
t instanceof ArrayType
or
/* Structs: "struct foo bar; bar.baz = 42" is ok. */
t instanceof Class
or
/* Typedefs to other allocated types are fine. */
allocatedType(t.(TypedefType).getUnderlyingType())
or
/* Type specifiers don't affect whether or not a type is allocated. */
allocatedType(t.getUnspecifiedType())
/** Auxiliary predicate: List cleanup functions we want to explicitly ignore
* since they don't do anything illegal even when the variable is uninitialized
*/
predicate cleanupFunctionDenyList(string fun) {
fun = "erase_char"
}
/**
@@ -40,11 +29,11 @@ predicate allocatedType(Type t) {
*/
DeclStmt declWithNoInit(LocalVariable v) {
result.getADeclaration() = v and
not exists(v.getInitializer()) and
not v.hasInitializer() and
/* The variable has __attribute__((__cleanup__(...))) set */
v.getAnAttribute().hasName("cleanup") and
/* The type of the variable is not stack-allocated. */
exists(Type t | t = v.getType() | not allocatedType(t))
/* Check if the cleanup function is not on a deny list */
not cleanupFunctionDenyList(v.getAnAttribute().getAnArgument().getValueText())
}
class UninitialisedLocalReachability extends StackVariableReachability {
@@ -69,7 +58,29 @@ class UninitialisedLocalReachability extends StackVariableReachability {
override predicate isBarrier(ControlFlowNode node, StackVariable v) {
// only report the _first_ possibly uninitialized use
useOfVar(v, node) or
definitionBarrier(v, node)
(
/* If there's an return statement somewhere between the variable declaration
* and a possible definition, don't accept is as a valid initialization.
*
* E.g.:
* _cleanup_free_ char *x;
* ...
* if (...)
* return;
* ...
* x = malloc(...);
*
* is not a valid initialization, since we might return from the function
* _before_ the actual iniitialization (emphasis on _might_, since we
* don't know if the return statement might ever evaluate to true).
*/
definitionBarrier(v, node) and
not exists(ReturnStmt rs |
/* The attribute check is "just" a complexity optimization */
v.getFunction() = rs.getEnclosingFunction() and v.getAnAttribute().hasName("cleanup") |
rs.getLocation().isBefore(node.getLocation())
)
)
}
}