-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Expand file tree
/
Copy pathGlobalUseBeforeInit.ql
More file actions
133 lines (116 loc) · 3.65 KB
/
GlobalUseBeforeInit.ql
File metadata and controls
133 lines (116 loc) · 3.65 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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/**
* @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
* @security-severity 7.8
* @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
)
}
/** Holds if `v` has an initializer in function `f` that dominates `node`. */
predicate dominatingInitInFunc(GlobalVariable v, Function f, ControlFlowNode node) {
exists(VariableAccess initAccess |
v.getAnAccess() = initAccess and
initAccess.isUsedAsLValue() and
initAccess.getEnclosingFunction() = f and
dominates(initAccess, node)
)
}
predicate safeAccess(VariableAccess access) {
// it is safe if the variable access is part of a `sizeof` expression
exists(SizeofExprOperator e | e.getAChild*() = access)
}
predicate useFunc(GlobalVariable v, Function f) {
exists(VariableAccess access |
v.getAnAccess() = access and
access.isRValue() and
access.getEnclosingFunction() = f and
not safeAccess(access) and
not dominatingInitInFunc(v, f, access)
)
}
predicate uninitialisedBefore(GlobalVariable v, Function f) {
f.hasGlobalName("main") and
not initialisedAtDeclaration(v) and
not isStdlibVariable(v)
or
exists(Call call, Function g |
uninitialisedBefore(v, g) and
call.getEnclosingFunction() = g and
(not functionInitialises(g, v) or locallyUninitialisedAt(v, call)) and
resolvedCall(call, f)
)
}
predicate functionInitialises(Function f, GlobalVariable v) {
initFunc(v, f)
or
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)
)
) and
not dominatingInitInFunc(v, call.getEnclosingFunction(), 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
)
}
/** Holds if `v` has an initializer. */
predicate initialisedAtDeclaration(GlobalVariable v) { exists(v.getInitializer()) }
/** Holds if `v` is a global variable that does not need to be initialized. */
predicate isStdlibVariable(GlobalVariable v) { v.hasGlobalName(["stdin", "stdout", "stderr"]) }
from GlobalVariable v, Function f
where
uninitialisedBefore(v, f) and
useFunc(v, f)
select f, "The variable $@ is used in this function but may not be initialized when it is called.",
v, v.getName()