Skip to content

Commit 28bea69

Browse files
committed
Python: ESSA definitions; make '*' special variable into its own class.
1 parent 50ce961 commit 28bea69

File tree

3 files changed

+47
-23
lines changed

3 files changed

+47
-23
lines changed

python/ql/src/semmle/python/Variables.qll

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@ import python
44
/** A variable, either a global or local variable (including parameters) */
55
class Variable extends @py_variable {
66

7+
Variable() {
8+
exists(string name |
9+
variable(this, _, name) and
10+
not name = "*" and not name = "$"
11+
)
12+
}
13+
714
/** Gets the identifier (name) of this variable */
815
string getId() {
916
variable(this, _, result)

python/ql/src/semmle/python/dataflow/SsaDefinitions.qll

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,11 @@ abstract class PythonSsaSourceVariable extends SsaSourceVariable {
2626
}
2727

2828
override string getName() {
29-
result = this.(Variable).getId()
29+
variable(this, _, result)
30+
}
31+
32+
Scope getScope() {
33+
variable(this, result, _)
3034
}
3135

3236
abstract ControlFlowNode getAnImplicitUse();
@@ -46,7 +50,7 @@ abstract class PythonSsaSourceVariable extends SsaSourceVariable {
4650
/* Add a use at the end of scope for all variables to keep them live
4751
* This is necessary for taint-tracking.
4852
*/
49-
result = this.(Variable).getScope().getANormalExit()
53+
result = this.getScope().getANormalExit()
5054
}
5155

5256
override predicate hasDefiningNode(ControlFlowNode def) {
@@ -107,7 +111,6 @@ class FunctionLocalVariable extends PythonSsaSourceVariable {
107111
}
108112

109113
override ControlFlowNode getScopeEntryDefinition() {
110-
not this.(LocalVariable).getId() = "*" and
111114
exists(Scope s |
112115
s.getEntryNode() = result |
113116
s = this.(LocalVariable).getScope() and
@@ -146,7 +149,6 @@ class NonLocalVariable extends PythonSsaSourceVariable {
146149
}
147150

148151
override CallNode redefinedAtCallSite() {
149-
not this.(LocalVariable).getId() = "*" and
150152
result.getScope().getScope*() = this.(LocalVariable).getScope()
151153
}
152154

@@ -163,7 +165,6 @@ class ClassLocalVariable extends PythonSsaSourceVariable {
163165
}
164166

165167
override ControlFlowNode getScopeEntryDefinition() {
166-
not this.(LocalVariable).getId() = "*" and
167168
result = this.(LocalVariable).getScope().getEntryNode()
168169
}
169170

@@ -235,7 +236,6 @@ class ModuleVariable extends PythonSsaSourceVariable {
235236
}
236237

237238
override ControlFlowNode getScopeEntryDefinition() {
238-
not this.(GlobalVariable).getId() = "*" and
239239
exists(Scope s |
240240
s.getEntryNode() = result |
241241
/* Module entry point */
@@ -253,13 +253,6 @@ class ModuleVariable extends PythonSsaSourceVariable {
253253
this = scope.getOuterVariable(_) or
254254
this.(Variable).getAUse().getScope() = scope
255255
)
256-
or
257-
this.(GlobalVariable).getId() = "*" and
258-
exists(Scope s |
259-
s.getEntryNode() = result and
260-
this.(Variable).getScope() = s and
261-
exists(ImportStar is | is.getScope() = s)
262-
)
263256
}
264257

265258
override CallNode redefinedAtCallSite() { none() }
@@ -307,6 +300,29 @@ class EscapingGlobalVariable extends ModuleVariable {
307300

308301
}
309302

303+
class SpecialSsaSourceVariable extends PythonSsaSourceVariable {
304+
305+
SpecialSsaSourceVariable() {
306+
variable(this, _, "*") or variable(this, _, "$")
307+
}
308+
309+
override ControlFlowNode getAnImplicitUse() {
310+
exists(ImportTimeScope s |
311+
result = s.getANormalExit() and this.getScope() = s
312+
)
313+
}
314+
315+
override ControlFlowNode getScopeEntryDefinition() {
316+
/* Module entry point */
317+
this.getScope().getEntryNode() = result
318+
}
319+
320+
override CallNode redefinedAtCallSite() {
321+
result.(CallNode).getScope().getScope*() = this.(GlobalVariable).getScope()
322+
}
323+
324+
}
325+
310326
private predicate variable_or_attribute_defined_out_of_scope(Variable v) {
311327
exists(NameNode n | n.defines(v) and not n.getScope() = v.getScope())
312328
or
@@ -330,7 +346,7 @@ cached module SsaSource {
330346

331347
/** Holds if `v` is used as the receiver in a method call. */
332348
cached predicate method_call_refinement(Variable v, ControlFlowNode use, CallNode call) {
333-
use = v.getAUse() and
349+
use = v.getAUse() and
334350
call.getFunction().(AttrNode).getObject() = use
335351
}
336352

@@ -387,16 +403,17 @@ cached module SsaSource {
387403
/** Holds if the name of `var` refers to a submodule of a package and `f` is the entry point
388404
* to the __init__ module of that package.
389405
*/
390-
cached predicate init_module_submodule_defn(Variable var, ControlFlowNode f) {
406+
cached predicate init_module_submodule_defn(PythonSsaSourceVariable var, ControlFlowNode f) {
391407
exists(Module init |
392-
init.isPackageInit() and exists(init.getPackage().getSubModule(var.getId())) and
393-
var instanceof GlobalVariable and init.getEntryNode() = f and
394-
var.getScope() = init
408+
init.isPackageInit() and exists(init.getPackage().getSubModule(var.getName())) and
409+
init.getEntryNode() = f and
410+
var.getScope() = init and
411+
var instanceof GlobalVariable
395412
)
396413
}
397414

398415
/** Holds if the `v` is in scope at a `from import ... *` and may thus be redefined by that statement */
399-
cached predicate import_star_refinement(Variable v, ControlFlowNode use, ControlFlowNode def) {
416+
cached predicate import_star_refinement(PythonSsaSourceVariable v, ControlFlowNode use, ControlFlowNode def) {
400417
use = def and def instanceof ImportStarNode
401418
and
402419
(
@@ -443,7 +460,7 @@ cached module SsaSource {
443460

444461
}
445462

446-
private predicate refinement(Variable v, ControlFlowNode use, ControlFlowNode def) {
463+
private predicate refinement(PythonSsaSourceVariable v, ControlFlowNode use, ControlFlowNode def) {
447464
SsaSource::import_star_refinement(v, use, def)
448465
or
449466
SsaSource::attribute_assignment_refinement(v, use, def)
@@ -456,5 +473,5 @@ private predicate refinement(Variable v, ControlFlowNode use, ControlFlowNode de
456473
or
457474
SsaSource::method_call_refinement(v, use, def)
458475
or
459-
def = v.(PythonSsaSourceVariable).redefinedAtCallSite() and def = use
476+
def = v.redefinedAtCallSite() and def = use
460477
}

python/ql/src/semmle/python/pointsto/PointsTo.qll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ module PointsTo {
119119
or
120120
exists(Module init |
121121
init = package.getInitModule().getModule() |
122-
not exists(Variable v | v.getScope() = init | v.getId() = name or v.getId() = "*")
122+
not exists(PythonSsaSourceVariable v | v.getScope() = init | v.getName() = name or v.getName() = "*")
123123
or
124124
exists(EssaVariable v, PointsToContext imp |
125125
v.getScope() = init and v.getName() = "*" and v.getAUse() = init.getANormalExit() |
@@ -145,7 +145,7 @@ module PointsTo {
145145
or
146146
not exists(EssaVariable var | var.getAUse() = m.getANormalExit() and var.getSourceVariable().getName() = name) and
147147
exists(EssaVariable var, PointsToContext imp |
148-
var.getAUse() = m.getANormalExit() and var.getSourceVariable().getName() = "*" |
148+
var.getAUse() = m.getANormalExit() and var.getName() = "*" |
149149
SSA::ssa_variable_named_attribute_points_to(var, imp, name, obj, cls, origin) and
150150
imp.isImport() and not obj = undefinedVariable()
151151
)

0 commit comments

Comments
 (0)