/**
 * @name Variable not initialized before use
 * @description A variable is used before initialized. The value of a variable is undefined before initialization, and its use should be avoided.
 * @kind problem
 * @id cpp/not-initialised
 * @problem.severity error
 * @tags reliability
 *       external/cwe/cwe-457
 */
import cpp

// This query is the JSF version
//
// (see also InitialisationNotRun.ql and GlobalUseBeforeInit.ql)

// Holds if s defines variable v (conservative)
predicate defines(ControlFlowNode s, Variable lv) {
  exists(VariableAccess va | va = s and va.getTarget() = lv and va.isUsedAsLValue())
}

// Holds if s uses variable v (conservative)
predicate uses(ControlFlowNode s, Variable lv) {
  exists(VariableAccess va | va = s and va.getTarget() = lv and va.isRValue()
    and not va.getParent+() instanceof SizeofOperator)
}

// Holds if there is a path from the declaration of lv to n such that lv is
// definitely not defined before n
predicate noDefPath(LocalVariable lv, ControlFlowNode n) {
     n.(DeclStmt).getADeclaration() = lv and not exists(lv.getInitializer())
  or exists(ControlFlowNode p | noDefPath(lv, p) and n = p.getASuccessor() and not defines(p, lv))
}

predicate isAggregateType(Type t) {
  t instanceof Class or t instanceof ArrayType
}

// Holds if va is a use of a local variable that has not been previously
// defined
predicate undefinedLocalUse(VariableAccess va) {
  exists(LocalVariable lv |
    // it is hard to tell when a struct or array has been initialized, so we
    // ignore them
    not isAggregateType(lv.getUnderlyingType()) and
    not lv.getType().hasName("va_list") and
    va = lv.getAnAccess() and
    noDefPath(lv, va) and
    uses(va, lv))
}

// Holds if gv is a potentially uninitialized global variable
predicate uninitialisedGlobal(GlobalVariable gv) {
  exists(VariableAccess va |
    not isAggregateType(gv.getUnderlyingType()) and
    va = gv.getAnAccess() and
    va.isRValue() and
    not gv.hasInitializer() and
    not gv.hasSpecifier("extern"))
}

from Element elt
where undefinedLocalUse(elt) or uninitialisedGlobal(elt)
select elt, "Variable '" + elt.toString() + "' is not initialized."
