-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathUninitializedLocal.ql
More file actions
84 lines (74 loc) · 2.68 KB
/
UninitializedLocal.ql
File metadata and controls
84 lines (74 loc) · 2.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
/**
* @name Potentially uninitialized local variable
* @description Reading from a local variable that has not been assigned to
* will typically yield garbage.
* @kind problem
* @id cpp/uninitialized-local
* @problem.severity warning
* @security-severity 7.8
* @precision medium
* @tags security
* external/cwe/cwe-665
* external/cwe/cwe-457
*/
import cpp
import semmle.code.cpp.controlflow.StackVariableReachability
/**
* Auxiliary predicate: Types that don't require initialization
* before they are used, since they're stack-allocated.
*/
predicate allocatedType(Type t) {
/* Arrays: "int foo[1]; foo[0] = 42;" is ok. */
t instanceof ArrayType
or
/* Structs: "struct foo bar; bar.baz = 42" is ok. */
t instanceof Class
or
/* Typedefs to other allocated types are fine. */
allocatedType(t.(TypedefType).getUnderlyingType())
or
/* Type specifiers don't affect whether or not a type is allocated. */
allocatedType(t.getUnspecifiedType())
}
/**
* A declaration of a local variable that leaves the
* variable uninitialized.
*/
DeclStmt declWithNoInit(LocalVariable v) {
result.getADeclaration() = v and
not exists(v.getInitializer()) and
/* The type of the variable is not stack-allocated. */
exists(Type t | t = v.getType() | not allocatedType(t))
}
class UninitialisedLocalReachability extends StackVariableReachability {
UninitialisedLocalReachability() { this = "UninitialisedLocal" }
override predicate isSource(ControlFlowNode node, StackVariable v) { node = declWithNoInit(v) }
override predicate isSink(ControlFlowNode node, StackVariable v) { useOfVarActual(v, node) }
override predicate isBarrier(ControlFlowNode node, StackVariable v) {
// only report the _first_ possibly uninitialized use
useOfVarActual(v, node) or
definitionBarrier(v, node)
}
}
pragma[noinline]
predicate containsInlineAssembly(Function f) { exists(AsmStmt s | s.getEnclosingFunction() = f) }
/**
* Auxiliary predicate: List common exceptions or false positives
* for this check to exclude them.
*/
VariableAccess commonException() {
// If the uninitialized use we've found is in a macro expansion, it's
// typically something like va_start(), and we don't want to complain.
result.getParent().isInMacroExpansion()
or
result.getParent() instanceof BuiltInOperation
or
// Finally, exclude functions that contain assembly blocks. It's
// anyone's guess what happens in those.
containsInlineAssembly(result.getEnclosingFunction())
}
from UninitialisedLocalReachability r, LocalVariable v, VariableAccess va
where
r.reaches(_, v, va) and
not va = commonException()
select va, "The variable $@ may not be initialized here.", v, v.getName()