Files
codeql/cpp/ql/src/Best Practices/GuardedFree.ql
2024-12-04 20:10:45 +00:00

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"