mirror of
https://github.com/github/codeql.git
synced 2026-02-11 12:41:06 +01:00
Some files that will change in #1736 have been spared. ./build -j4 target/jars/qlformat find ql/cpp/ql -name "*.ql" -print0 | xargs -0 target/jars/qlformat --input find ql/cpp/ql -name "*.qll" -print0 | xargs -0 target/jars/qlformat --input (cd ql && git checkout 'cpp/ql/src/semmle/code/cpp/ir/implementation/**/*SSA*.qll') buildutils-internal/scripts/pr-checks/sync-identical-files.py --latest
75 lines
2.5 KiB
Plaintext
75 lines
2.5 KiB
Plaintext
/**
|
|
* @name Inconsistent operation on return value
|
|
* @description A function is called, and the same operation is usually performed on the return value - for example, free, delete, close etc. However, in some cases it is not performed. These unusual cases may indicate misuse of the API and could cause resource leaks.
|
|
* @kind problem
|
|
* @problem.severity warning
|
|
* @precision medium
|
|
* @id cpp/inconsistent-call-on-result
|
|
* @tags reliability
|
|
* correctness
|
|
* statistical
|
|
* non-attributable
|
|
* external/cwe/cwe-252
|
|
*/
|
|
|
|
import cpp
|
|
|
|
predicate exclude(Function f) {
|
|
exists(string name | name = f.getName() |
|
|
name.toLowerCase().matches("get%") or
|
|
name.matches("strto%")
|
|
)
|
|
}
|
|
|
|
predicate checkExpr(Expr e, string operation, Variable v) {
|
|
exists(FunctionCall fc | fc = e and not exclude(fc.getTarget()) |
|
|
fc.getTarget().getName() = operation and
|
|
(fc.getAnArgument() = v.getAnAccess() or fc.getQualifier() = v.getAnAccess())
|
|
)
|
|
or
|
|
exists(DeleteExpr del | del = e |
|
|
del.getExpr() = v.getAnAccess() and
|
|
operation = "delete"
|
|
)
|
|
or
|
|
exists(DeleteArrayExpr del | del = e |
|
|
del.getExpr() = v.getAnAccess() and
|
|
operation = "delete[]"
|
|
)
|
|
}
|
|
|
|
predicate checkedFunctionCall(FunctionCall fc, string operation) {
|
|
relevantFunctionCall(fc, _) and
|
|
exists(Variable v, Expr check | v.getAnAssignedValue() = fc |
|
|
checkExpr(check, operation, v) and
|
|
check != fc
|
|
)
|
|
}
|
|
|
|
predicate relevantFunctionCall(FunctionCall fc, Function f) {
|
|
fc.getTarget() = f and
|
|
exists(Variable v | v.getAnAssignedValue() = fc) and
|
|
not okToIgnore(fc)
|
|
}
|
|
|
|
predicate okToIgnore(FunctionCall fc) { fc.isInMacroExpansion() }
|
|
|
|
predicate functionStats(Function f, string operation, int used, int total, int percentage) {
|
|
exists(PointerType pt | pt.getATypeNameUse() = f.getADeclarationEntry()) and
|
|
used = strictcount(FunctionCall fc | checkedFunctionCall(fc, operation) and f = fc.getTarget()) and
|
|
total = strictcount(FunctionCall fc | relevantFunctionCall(fc, f)) and
|
|
percentage = used * 100 / total
|
|
}
|
|
|
|
from FunctionCall unchecked, Function f, string operation, int percent
|
|
where
|
|
relevantFunctionCall(unchecked, f) and
|
|
not checkedFunctionCall(unchecked, operation) and
|
|
functionStats(f, operation, _, _, percent) and
|
|
percent >= 70 and
|
|
unchecked.getFile().getAbsolutePath().matches("%fbcode%") and
|
|
not unchecked.getFile().getAbsolutePath().matches("%\\_build%")
|
|
select unchecked,
|
|
"After " + percent.toString() + "% of calls to " + f.getName() + " there is a call to " +
|
|
operation + " on the return value. The call may be missing in this case."
|