-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Expand file tree
/
Copy pathUndefinedGlobal.ql
More file actions
132 lines (122 loc) · 4.47 KB
/
UndefinedGlobal.ql
File metadata and controls
132 lines (122 loc) · 4.47 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
/**
* @name Use of an undefined global variable
* @description Using a global variable before it is initialized causes an exception.
* @kind problem
* @tags reliability
* correctness
* @problem.severity error
* @sub-severity low
* @precision low
* @id py/undefined-global-variable
*/
import python
import Variables.MonkeyPatched
import Loop
import semmle.python.pointsto.PointsTo
predicate guarded_against_name_error(Name u) {
exists(Try t | t.getBody().getAnItem().contains(u) |
((Name)((ExceptStmt)t.getAHandler()).getType()).getId() = "NameError"
)
or
exists(ConditionBlock guard, BasicBlock controlled, Call globals |
guard.getLastNode().getNode().contains(globals) or
guard.getLastNode().getNode() = globals |
globals.getFunc().(Name).getId() = "globals" and
guard.controls(controlled, _) and
controlled.contains(u.getAFlowNode())
)
}
predicate contains_unknown_import_star(Module m) {
exists(ImportStar imp | imp.getScope() = m |
not exists(ModuleObject imported | imported.importedAs(imp.getImportedModuleName()))
or
exists(ModuleObject imported |
imported.importedAs(imp.getImportedModuleName()) |
not imported.exportsComplete()
)
)
}
predicate undefined_use_in_function(Name u) {
exists(Function f | u.getScope().getScope*() = f and
/* Either function is a method or inner function or it is live at the end of the module scope */
(not f.getScope() = u.getEnclosingModule() or ((ImportTimeScope)u.getEnclosingModule()).definesName(f.getName()))
and
/* There is a use, but not a definition of this global variable in the function or enclosing scope */
exists(GlobalVariable v | u.uses(v) |
not exists(Assign a, Scope defnScope |
a.getATarget() = v.getAnAccess() and a.getScope() = defnScope |
defnScope = f or
/* Exclude modules as that case is handled more precisely below. */
(defnScope = f.getScope().getScope*() and not defnScope instanceof Module)
)
)
)
and
not ((ImportTimeScope)u.getEnclosingModule()).definesName(u.getId())
and
not exists(ModuleObject m | m.getModule() = u.getEnclosingModule() | m.hasAttribute(u.getId()))
and
not globallyDefinedName(u.getId())
and
not exists(SsaVariable var | var.getAUse().getNode() = u and not var.maybeUndefined())
and
not guarded_against_name_error(u)
and
not (u.getEnclosingModule().isPackageInit() and u.getId() = "__path__")
}
predicate undefined_use_in_class_or_module(Name u) {
exists(GlobalVariable v | u.uses(v))
and
not exists(Function f | u.getScope().getScope*() = f)
and
exists(SsaVariable var | var.getAUse().getNode() = u | var.maybeUndefined())
and
not guarded_against_name_error(u)
and
not exists(ModuleObject m | m.getModule() = u.getEnclosingModule() | m.hasAttribute(u.getId()))
and
not (u.getEnclosingModule().isPackageInit() and u.getId() = "__path__")
and
not globallyDefinedName(u.getId())
}
predicate use_of_exec(Module m) {
exists(Exec exec | exec.getScope() = m)
or
exists(CallNode call, FunctionObject exec |
exec.getACall() = call and call.getScope() = m |
exec = builtin_object("exec") or
exec = builtin_object("execfile")
)
}
predicate undefined_use(Name u) {
(
undefined_use_in_class_or_module(u)
or
undefined_use_in_function(u)
) and
not monkey_patched_builtin(u.getId()) and
not contains_unknown_import_star(u.getEnclosingModule()) and
not use_of_exec(u.getEnclosingModule()) and
not exists(u.getVariable().getAStore()) and
not u.refersTo(_) and
not probably_defined_in_loop(u)
}
private predicate first_use_in_a_block(Name use) {
exists(GlobalVariable v, BasicBlock b, int i |
i = min(int j | b.getNode(j).getNode() = v.getALoad()) and b.getNode(i) = use.getAFlowNode()
)
}
predicate first_undefined_use(Name use) {
undefined_use(use) and
exists(GlobalVariable v |
v.getALoad() = use |
first_use_in_a_block(use) and
not exists(ControlFlowNode other |
other.getNode() = v.getALoad() and
other.getBasicBlock().strictlyDominates(use.getAFlowNode().getBasicBlock())
)
)
}
from Name u
where first_undefined_use(u)
select u, "This use of global variable '" + u.getId() + "' may be undefined."