Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d8531c4

Browse files
committed
Python ESSA: Move variable definitions into new file and unify 'generic' and 'python specific' parts.
1 parent 523c5b1 commit d8531c4

3 files changed

Lines changed: 400 additions & 454 deletions

File tree

Lines changed: 395 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,395 @@
1+
import python
2+
3+
/* Classification of variables. These should be non-overlapping and complete.
4+
*
5+
* Function local variables - Non escaping variables in a function, except 'self'
6+
* Self variables - The 'self' variable for a method.
7+
* Class local variables - Local variables declared in a class
8+
* Non-local variables - Escaping variables in a function
9+
* Built-in variables - Global variables with no definition
10+
* Non-escaping globals -- Global variables that have definitions and all of those definitions are in the module scope
11+
* Escaping globals -- Global variables that have definitions and at least one of those definitions is in another scope.
12+
*/
13+
14+
/** A source language variable, to be converted into a set of SSA variables. */
15+
abstract class SsaSourceVariable extends @py_variable {
16+
17+
SsaSourceVariable() {
18+
/* Exclude `True`, `False` and `None` */
19+
not this.(Variable).getALoad() instanceof NameConstant
20+
}
21+
22+
/** Gets the name of this variable */
23+
string getName() {
24+
variable(this, _, result)
25+
}
26+
27+
Scope getScope() {
28+
variable(this, result, _)
29+
}
30+
31+
/** Gets an implicit use of this variable */
32+
abstract ControlFlowNode getAnImplicitUse();
33+
34+
abstract ControlFlowNode getScopeEntryDefinition();
35+
36+
string toString() {
37+
result = "SsaSourceVariable " + this.getName()
38+
}
39+
40+
/** Gets a use of this variable, either explicit or implicit. */
41+
ControlFlowNode getAUse() {
42+
result = this.getASourceUse()
43+
or
44+
result = this.getAnImplicitUse()
45+
or
46+
/* `import *` is a definition of *all* variables, so must be a use as well, for pass-through
47+
* once we have established that a variable is not redefined.
48+
*/
49+
SsaSource::import_star_refinement(this, result, _)
50+
or
51+
/* Add a use at the end of scope for all variables to keep them live
52+
* This is necessary for taint-tracking.
53+
*/
54+
result = this.getScope().getANormalExit()
55+
}
56+
57+
/** Holds if `def` defines an ESSA variable for this variable. */
58+
predicate hasDefiningNode(ControlFlowNode def) {
59+
def = this.getScopeEntryDefinition()
60+
or
61+
SsaSource::assignment_definition(this, def, _)
62+
or
63+
SsaSource::multi_assignment_definition(this, def, _, _)
64+
or
65+
SsaSource::deletion_definition(this, def)
66+
or
67+
SsaSource::init_module_submodule_defn(this, def)
68+
or
69+
SsaSource::parameter_definition(this, def)
70+
or
71+
SsaSource::exception_capture(this, def)
72+
or
73+
SsaSource::with_definition(this, def)
74+
}
75+
76+
/** Holds if `def` defines an ESSA variable for this variable in such a way
77+
* that the new variable is a refinement in some way of the variable used at `use`.
78+
*/
79+
predicate hasRefinement(ControlFlowNode use, ControlFlowNode def) {
80+
this.hasDefiningNode(_) and /* Can't have a refinement unless there is a definition */
81+
refinement(this, use, def)
82+
}
83+
84+
/** Holds if the edge `pred`->`succ` defines an ESSA variable for this variable in such a way
85+
* that the new variable is a refinement in some way of the variable used at `use`.
86+
*/
87+
predicate hasRefinementEdge(ControlFlowNode use, BasicBlock pred, BasicBlock succ) {
88+
test_contains(pred.getLastNode(), use) and
89+
use.(NameNode).uses(this) and
90+
(pred.getAFalseSuccessor() = succ or pred.getATrueSuccessor() = succ) and
91+
/* There is a store to this variable -- We don't want to refine builtins */
92+
exists(this.(Variable).getAStore())
93+
}
94+
95+
/** Gets a use of this variable that corresponds to an explicit use in the source. */
96+
ControlFlowNode getASourceUse() {
97+
result.(NameNode).uses(this)
98+
or
99+
result.(NameNode).deletes(this)
100+
}
101+
102+
abstract CallNode redefinedAtCallSite();
103+
104+
}
105+
106+
private predicate refinement(SsaSourceVariable v, ControlFlowNode use, ControlFlowNode def) {
107+
SsaSource::import_star_refinement(v, use, def)
108+
or
109+
SsaSource::attribute_assignment_refinement(v, use, def)
110+
or
111+
SsaSource::argument_refinement(v, use, def)
112+
or
113+
SsaSource::attribute_deletion_refinement(v, use, def)
114+
or
115+
SsaSource::test_refinement(v, use, def)
116+
or
117+
SsaSource::method_call_refinement(v, use, def)
118+
or
119+
def = v.redefinedAtCallSite() and def = use
120+
}
121+
122+
123+
class FunctionLocalVariable extends SsaSourceVariable {
124+
125+
FunctionLocalVariable() {
126+
this.(LocalVariable).getScope() instanceof Function and
127+
not this instanceof NonLocalVariable
128+
}
129+
130+
override ControlFlowNode getAnImplicitUse() {
131+
this.(Variable).isSelf() and this.(Variable).getScope().getANormalExit() = result
132+
}
133+
134+
override ControlFlowNode getScopeEntryDefinition() {
135+
exists(Scope s |
136+
s.getEntryNode() = result |
137+
s = this.(LocalVariable).getScope() and
138+
not this.(LocalVariable).isParameter()
139+
or
140+
s != this.(LocalVariable).getScope() and
141+
s = this.(LocalVariable).getALoad().getScope()
142+
)
143+
}
144+
145+
override CallNode redefinedAtCallSite() { none() }
146+
147+
}
148+
149+
class NonLocalVariable extends SsaSourceVariable {
150+
151+
NonLocalVariable() {
152+
exists(Function f |
153+
this.(LocalVariable).getScope() = f and
154+
this.(LocalVariable).getAStore().getScope() != f
155+
)
156+
}
157+
158+
override ControlFlowNode getAnImplicitUse() {
159+
result.(CallNode).getScope().getScope*() = this.(LocalVariable).getScope()
160+
}
161+
162+
override ControlFlowNode getScopeEntryDefinition() {
163+
exists(Function f |
164+
f.getScope+() = this.(LocalVariable).getScope() and
165+
f.getEntryNode() = result
166+
)
167+
or
168+
not this.(LocalVariable).isParameter() and
169+
this.(LocalVariable).getScope().getEntryNode() = result
170+
}
171+
172+
pragma [noinline]
173+
Scope scope_as_local_variable() {
174+
result = this.(LocalVariable).getScope()
175+
}
176+
177+
override CallNode redefinedAtCallSite() {
178+
result.getScope().getScope*() = this.scope_as_local_variable()
179+
}
180+
181+
}
182+
183+
class ClassLocalVariable extends SsaSourceVariable {
184+
185+
ClassLocalVariable() {
186+
this.(LocalVariable).getScope() instanceof Class
187+
}
188+
189+
override ControlFlowNode getAnImplicitUse() {
190+
none()
191+
}
192+
193+
override ControlFlowNode getScopeEntryDefinition() {
194+
result = this.(LocalVariable).getScope().getEntryNode()
195+
}
196+
197+
override CallNode redefinedAtCallSite() { none() }
198+
199+
}
200+
201+
class BuiltinVariable extends SsaSourceVariable {
202+
203+
BuiltinVariable() {
204+
this instanceof GlobalVariable and
205+
not exists(this.(Variable).getAStore()) and
206+
not this.(Variable).getId() = "__name__" and
207+
not this.(Variable).getId() = "__package__" and
208+
not exists(ImportStar is | is.getScope() = this.(Variable).getScope())
209+
}
210+
211+
override ControlFlowNode getAnImplicitUse() {
212+
none()
213+
}
214+
215+
override ControlFlowNode getScopeEntryDefinition() {
216+
none()
217+
}
218+
219+
override CallNode redefinedAtCallSite() { none() }
220+
221+
}
222+
223+
class ModuleVariable extends SsaSourceVariable {
224+
225+
ModuleVariable() {
226+
this instanceof GlobalVariable and
227+
(
228+
exists(this.(Variable).getAStore())
229+
or
230+
this.(Variable).getId() = "__name__"
231+
or
232+
this.(Variable).getId() = "__package__"
233+
or
234+
exists(ImportStar is | is.getScope() = this.(Variable).getScope())
235+
)
236+
}
237+
238+
pragma [noinline]
239+
CallNode global_variable_callnode() {
240+
result.getScope() = this.(GlobalVariable).getScope()
241+
}
242+
243+
pragma[noinline]
244+
ImportMemberNode global_variable_import() {
245+
result.getScope() = this.(GlobalVariable).getScope() and
246+
import_from_dot_in_init(result.(ImportMemberNode).getModule(this.getName()))
247+
}
248+
249+
override ControlFlowNode getAnImplicitUse() {
250+
result = global_variable_callnode()
251+
or
252+
result = global_variable_import()
253+
or
254+
exists(ImportTimeScope scope |
255+
scope.entryEdge(result, _) |
256+
this = scope.getOuterVariable(_) or
257+
this.(Variable).getAUse().getScope() = scope
258+
)
259+
or
260+
/* For implicit use of __metaclass__ when constructing class */
261+
exists(Class c |
262+
class_with_global_metaclass(c, this) and
263+
c.(ImportTimeScope).entryEdge(result, _)
264+
)
265+
or
266+
exists(ImportTimeScope s |
267+
result = s.getANormalExit() and this.(Variable).getScope() = s and
268+
implicit_definition(this)
269+
)
270+
}
271+
272+
override ControlFlowNode getScopeEntryDefinition() {
273+
exists(Scope s |
274+
s.getEntryNode() = result |
275+
/* Module entry point */
276+
this.(GlobalVariable).getScope() = s
277+
or
278+
/* For implicit use of __metaclass__ when constructing class */
279+
class_with_global_metaclass(s, this)
280+
or
281+
/* Variable is used in scope */
282+
this.(GlobalVariable).getAUse().getScope() = s
283+
)
284+
or
285+
exists(ImportTimeScope scope |
286+
scope.entryEdge(_, result) |
287+
this = scope.getOuterVariable(_) or
288+
this.(Variable).getAUse().getScope() = scope
289+
)
290+
}
291+
292+
override CallNode redefinedAtCallSite() { none() }
293+
294+
}
295+
296+
class NonEscapingGlobalVariable extends ModuleVariable {
297+
298+
NonEscapingGlobalVariable() {
299+
this instanceof GlobalVariable and
300+
exists(this.(Variable).getAStore()) and
301+
not variable_or_attribute_defined_out_of_scope(this)
302+
}
303+
304+
}
305+
306+
class EscapingGlobalVariable extends ModuleVariable {
307+
308+
EscapingGlobalVariable() {
309+
this instanceof GlobalVariable and exists(this.(Variable).getAStore()) and variable_or_attribute_defined_out_of_scope(this)
310+
}
311+
312+
override ControlFlowNode getAnImplicitUse() {
313+
result = ModuleVariable.super.getAnImplicitUse()
314+
or
315+
result.(CallNode).getScope().getScope+() = this.(GlobalVariable).getScope()
316+
or
317+
result = this.innerScope().getANormalExit()
318+
}
319+
320+
private Scope innerScope() {
321+
result.getScope+() = this.(GlobalVariable).getScope() and
322+
not result instanceof ImportTimeScope
323+
}
324+
325+
override ControlFlowNode getScopeEntryDefinition() {
326+
result = ModuleVariable.super.getScopeEntryDefinition()
327+
or
328+
result = this.innerScope().getEntryNode()
329+
}
330+
331+
pragma [noinline]
332+
Scope scope_as_global_variable() {
333+
result = this.(GlobalVariable).getScope()
334+
}
335+
336+
override CallNode redefinedAtCallSite() {
337+
result.(CallNode).getScope().getScope*() = this.scope_as_global_variable()
338+
}
339+
340+
}
341+
342+
class EscapingAssignmentGlobalVariable extends EscapingGlobalVariable {
343+
344+
EscapingAssignmentGlobalVariable() {
345+
exists(NameNode n | n.defines(this) and not n.getScope() = this.getScope())
346+
}
347+
348+
}
349+
350+
351+
class SpecialSsaSourceVariable extends SsaSourceVariable {
352+
353+
SpecialSsaSourceVariable() {
354+
variable(this, _, "*") or variable(this, _, "$")
355+
}
356+
357+
override ControlFlowNode getAnImplicitUse() {
358+
exists(ImportTimeScope s |
359+
result = s.getANormalExit() and this.getScope() = s
360+
)
361+
}
362+
363+
override ControlFlowNode getScopeEntryDefinition() {
364+
/* Module entry point */
365+
this.getScope().getEntryNode() = result
366+
}
367+
368+
pragma [noinline]
369+
Scope scope_as_global_variable() {
370+
result = this.(GlobalVariable).getScope()
371+
}
372+
373+
override CallNode redefinedAtCallSite() {
374+
result.(CallNode).getScope().getScope*() = this.scope_as_global_variable()
375+
}
376+
377+
}
378+
379+
/** Holds if this variable is implicitly defined */
380+
private predicate implicit_definition(Variable v) {
381+
v.getId() = "*" or v.getId() = "$"
382+
or
383+
exists(ImportStar is | is.getScope() = v.getScope())
384+
}
385+
386+
private predicate variable_or_attribute_defined_out_of_scope(Variable v) {
387+
exists(NameNode n | n.defines(v) and not n.getScope() = v.getScope())
388+
or
389+
exists(AttrNode a | a.isStore() and a.getObject() = v.getAUse() and not a.getScope() = v.getScope())
390+
}
391+
392+
private predicate class_with_global_metaclass(Class cls, GlobalVariable metaclass) {
393+
metaclass.getId() = "__metaclass__" and major_version() = 2 and
394+
cls.getEnclosingModule() = metaclass.getScope()
395+
}

0 commit comments

Comments
 (0)