Semmle 1.21
Skip to end of metadata
Go to start of metadata

Name: Global variable may be used before initialization

Description: Using an uninitialized variable may lead to undefined results.

ID: cpp/global-use-before-init

Kind: problem

Severity: warning

Query: GlobalUseBeforeInit.ql
 * @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) {
  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
    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)
  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)
  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
  exists(ControlFlowNode mid |
    callReaches(call, mid) and
    not mid instanceof Call and
    mid.getASuccessor() = successor

from GlobalVariable v, Function f
  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."

This rule finds calls to functions that use a global variable before the variable has been initialized. Not all compilers generate code that zero-out memory, especially when optimizations are enabled or the compiler is not compliant with the latest language standards. Accessing uninitialized memory will lead to undefined results.

This check is an approximation, so some results may not be actual defects in the program. It is not possible in general to compute the actual branch taken in conditional statements such as "if" without running the program with all possible input data. This means that it is not possible to determine if a particular statement is going to be executed.


Initialize the global variable. If no constant can be used for initialization, ensure that all accesses to the variable occur after the initialization code is executed.


In the example below, callCtr is wrongly used before it has been initialized.

int g_callCtr;

void initGlobals() {
	g_callCtr = 0;

int main(int argc, char* argv[]) {
	cout << g_callCtr; //callCtr used before it is initialized