Files
codeql/cpp/ql/src/Critical/GlobalUseBeforeInit.ql
2019-05-03 10:37:48 +02:00

107 lines
2.6 KiB
Plaintext

/**
* @name Global variable may be used before initialization
* @description Using an uninitialized variable may lead to undefined results.
* @kind problem
* @id cpp/global-use-before-init
* @problem.severity warning
* @tags reliability
* security
* external/cwe/cwe-457
*/
import cpp
import semmle.code.cpp.pointsto.CallGraph
predicate initFunc(GlobalVariable v, Function f) {
exists(VariableAccess access |
v.getAnAccess() = access and
access.isUsedAsLValue() and
access.getEnclosingFunction() = f
)
}
predicate useFunc(GlobalVariable v, Function f) {
exists(VariableAccess access |
v.getAnAccess() = access and
access.isRValue() and
access.getEnclosingFunction() = f
) and
not initFunc(v, f)
}
predicate uninitialisedBefore(GlobalVariable v, Function f) {
f.hasGlobalName("main")
or
exists(Call call, Function g |
uninitialisedBefore(v, g) and
call.getEnclosingFunction() = g and
(not functionInitialises(f, v) or locallyUninitialisedAt(v, call)) and
resolvedCall(call, f)
)
}
predicate functionInitialises(Function f, GlobalVariable v) {
exists(Call call |
call.getEnclosingFunction() = f and
initialisedBy(v, call)
)
}
// this predicate is restricted to global variables used in the
// same function as "call"
predicate locallyUninitialisedAt(GlobalVariable v, Call call) {
functionInitialises(call.getEnclosingFunction(), v) and
(
firstCall(call)
or
exists(Call mid |
locallyUninitialisedAt(v, mid) and not initialisedBy(v, mid) and callPair(mid, call)
)
)
}
predicate initialisedBy(GlobalVariable v, Call call) {
exists(Function f |
resolvedCall(call, f) and
initialises(v, f)
)
}
predicate initialises(GlobalVariable v, Function f) {
initFunc(v, f)
or
exists(Function mid | initialises(v, mid) and allCalls(f, mid))
}
predicate firstCall(Call call) { beforeCall(call) }
predicate beforeCall(ControlFlowNode node) {
exists(Function f | f.getBlock() = node)
or
exists(ControlFlowNode mid |
beforeCall(mid) and
not mid instanceof Call and
node = mid.getASuccessor()
)
}
predicate callPair(Call call, Call successor) { callReaches(call, successor) }
predicate callReaches(Call call, ControlFlowNode successor) {
call.getASuccessor() = successor
or
exists(ControlFlowNode mid |
callReaches(call, mid) and
not mid instanceof Call and
mid.getASuccessor() = successor
)
}
from GlobalVariable v, Function f
where
uninitialisedBefore(v, f) and
useFunc(v, f)
select f,
"The variable '" + v.getName() +
" is used in this function but may not be initialized when it is called."