mirror of
https://github.com/github/codeql.git
synced 2026-04-11 18:14:01 +02:00
64 lines
2.0 KiB
Plaintext
64 lines
2.0 KiB
Plaintext
/**
|
|
* @name Guarded Free
|
|
* @description NULL-condition guards before function calls to the memory-deallocation
|
|
* function free(3) are unnecessary, because passing NULL to free(3) is a no-op.
|
|
* @kind problem
|
|
* @problem.severity recommendation
|
|
* @precision very-high
|
|
* @id cpp/guarded-free
|
|
* @tags maintainability
|
|
* readability
|
|
*/
|
|
|
|
import cpp
|
|
import semmle.code.cpp.controlflow.Guards
|
|
|
|
class FreeCall extends FunctionCall {
|
|
FreeCall() { this.getTarget().hasGlobalName("free") }
|
|
}
|
|
|
|
predicate blockContainsPreprocessorBranches(BasicBlock bb) {
|
|
exists(PreprocessorBranch ppb, Location bbLoc, Location ppbLoc |
|
|
bbLoc = bb.(Stmt).getLocation() and ppbLoc = ppb.getLocation()
|
|
|
|
|
bbLoc.getFile() = ppb.getFile() and
|
|
bbLoc.getStartLine() < ppbLoc.getStartLine() and
|
|
ppbLoc.getEndLine() < bbLoc.getEndLine()
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Holds if `gc` ensures that `v` is non-zero when reaching `bb`, and `bb`
|
|
* contains a single statement which is `fc`.
|
|
*/
|
|
pragma[nomagic]
|
|
private predicate interesting(GuardCondition gc, FreeCall fc, Variable v, BasicBlock bb) {
|
|
gc.ensuresEq(v.getAnAccess(), 0, bb, false) and
|
|
fc.getArgument(0) = v.getAnAccess() and
|
|
bb = fc.getBasicBlock() and
|
|
(
|
|
// No block statement: if (x) free(x);
|
|
bb = fc.getEnclosingStmt()
|
|
or
|
|
// Block statement with a single nested statement: if (x) { free(x); }
|
|
strictcount(bb.(BlockStmt).getAStmt()) = 1
|
|
) and
|
|
not fc.isInMacroExpansion() and
|
|
not blockContainsPreprocessorBranches(bb) and
|
|
not (gc instanceof BinaryOperation and not gc instanceof ComparisonOperation) and
|
|
not exists(CommaExpr c | c.getAChild*() = fc)
|
|
}
|
|
|
|
/** Holds if `gc` only guards a single block. */
|
|
bindingset[gc]
|
|
pragma[inline_late]
|
|
private predicate guardConditionGuardsUniqueBlock(GuardCondition gc) {
|
|
strictcount(BasicBlock bb | gc.ensuresEq(_, 0, bb, _)) = 1
|
|
}
|
|
|
|
from GuardCondition gc, FreeCall fc, Variable v, BasicBlock bb
|
|
where
|
|
interesting(gc, fc, v, bb) and
|
|
guardConditionGuardsUniqueBlock(gc)
|
|
select gc, "unnecessary NULL check before call to $@", fc, "free"
|