Skip to content

Commit 1d28c63

Browse files
authored
Merge pull request #810 from markshannon/python-hide-magic-variables
Python hide magic variables
2 parents 0f5b21e + 39705cf commit 1d28c63

File tree

9 files changed

+49
-44
lines changed

9 files changed

+49
-44
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: 37 additions & 20 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) {
407+
var instanceof GlobalVariable and
391408
exists(Module init |
392-
init.isPackageInit() and exists(init.getPackage().getSubModule(var.getId())) and
393-
var instanceof GlobalVariable and init.getEntryNode() = f and
409+
init.isPackageInit() and exists(init.getPackage().getSubModule(var.getName())) and
410+
init.getEntryNode() = f and
394411
var.getScope() = init
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 obj != undefinedVariable()
151151
)

python/ql/test/library-tests/PointsTo/new/Dataflow.expected

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
1-
| __init__.py:0 | *_0 = ScopeEntryDefinition |
21
| __init__.py:0 | __name___0 = ScopeEntryDefinition |
32
| __init__.py:0 | __package___0 = ScopeEntryDefinition |
43
| __init__.py:0 | module2_0 = ImplicitSubModuleDefinition |
54
| __init__.py:0 | moduleX_0 = ImplicitSubModuleDefinition |
65
| __init__.py:0 | sys_0 = ScopeEntryDefinition |
7-
| __init__.py:1 | *_1 = ImportStarRefinement(*_0) |
86
| __init__.py:1 | __name___1 = ImportStarRefinement(__name___0) |
97
| __init__.py:1 | __package___1 = ImportStarRefinement(__package___0) |
108
| __init__.py:1 | sys_1 = ImportStarRefinement(sys_0) |
11-
| __init__.py:2 | *_2 = ImportStarRefinement(*_1) |
129
| __init__.py:2 | __name___2 = ImportStarRefinement(__name___1) |
1310
| __init__.py:2 | __package___2 = ImportStarRefinement(__package___1) |
1411
| __init__.py:2 | module_0 = ImportMember |
@@ -498,7 +495,6 @@
498495
| h_classes.py:52 | arg1_0 = ParameterDefinition |
499496
| h_classes.py:52 | n_0 = FunctionExpr |
500497
| h_classes.py:52 | self_0 = ParameterDefinition |
501-
| i_imports.py:0 | *_0 = ScopeEntryDefinition |
502498
| i_imports.py:0 | BytesIO_0 = ScopeEntryDefinition |
503499
| i_imports.py:0 | StringIO_0 = ScopeEntryDefinition |
504500
| i_imports.py:0 | __name___0 = ScopeEntryDefinition |
@@ -513,7 +509,6 @@
513509
| i_imports.py:3 | a_0 = IntegerLiteral |
514510
| i_imports.py:4 | b_0 = IntegerLiteral |
515511
| i_imports.py:5 | c_0 = IntegerLiteral |
516-
| i_imports.py:7 | *_1 = ImportStarRefinement(*_0) |
517512
| i_imports.py:7 | BytesIO_1 = ImportStarRefinement(BytesIO_0) |
518513
| i_imports.py:7 | StringIO_1 = ImportStarRefinement(StringIO_0) |
519514
| i_imports.py:7 | __name___1 = ImportStarRefinement(__name___0) |
@@ -528,7 +523,6 @@
528523
| i_imports.py:13 | argv_1 = ImportMember |
529524
| i_imports.py:17 | sys_1 = ImportExpr |
530525
| i_imports.py:23 | code_1 = ImportExpr |
531-
| i_imports.py:27 | *_2 = ImportStarRefinement(*_1) |
532526
| i_imports.py:27 | __name___2 = ImportStarRefinement(__name___1) |
533527
| i_imports.py:27 | __package___2 = ImportStarRefinement(__package___1) |
534528
| i_imports.py:27 | a_2 = ImportStarRefinement(a_1) |

python/ql/test/library-tests/PointsTo/new/Dataflow.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ import python
44
import Util
55

66
from EssaVariable v, EssaDefinition def
7-
where def = v.getDefinition()
7+
where def = v.getDefinition() and not v.getSourceVariable() instanceof SpecialSsaSourceVariable
88
select locate(def.getLocation(), "abdefghijknrs_"), v.getRepresentation() + " = " + def.getRepresentation()

python/ql/test/library-tests/PointsTo/new/SsaAttr.expected

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,6 @@
3737
| g_class_init.py:52 | self_3 | version | phi(self_1, self_2) | 'v2' | runtime |
3838
| g_class_init.py:52 | self_3 | version | phi(self_1, self_2) | 'v3' | runtime |
3939
| g_class_init.py:54 | self_1 | version | Pi(self_0) [true] | 'v2' | runtime |
40-
| i_imports.py:7 | *_1 | x | ImportStarRefinement(*_0) | float 1.0 | import |
41-
| i_imports.py:7 | *_1 | y | ImportStarRefinement(*_0) | float 2.0 | import |
42-
| i_imports.py:27 | *_2 | module1 | ImportStarRefinement(*_1) | Module code.test_package.module1 | import |
43-
| i_imports.py:27 | *_2 | module2 | ImportStarRefinement(*_1) | Module code.test_package.module2 | import |
44-
| i_imports.py:27 | *_2 | p | ImportStarRefinement(*_1) | int 1 | import |
45-
| i_imports.py:27 | *_2 | q | ImportStarRefinement(*_1) | int 2 | import |
46-
| i_imports.py:27 | *_2 | r | ImportStarRefinement(*_1) | Dict | import |
47-
| i_imports.py:27 | *_2 | s | ImportStarRefinement(*_1) | NoneType None | import |
48-
| i_imports.py:27 | *_2 | x | ImportStarRefinement(*_1) | float 1.0 | import |
49-
| i_imports.py:27 | *_2 | y | ImportStarRefinement(*_1) | float 2.0 | import |
5040
| k_getsetattr.py:6 | self_0 | a | ParameterDefinition | float 7.0 | code/k_getsetattr.py:15 from runtime |
5141
| k_getsetattr.py:6 | self_0 | c | ParameterDefinition | int 2 | code/k_getsetattr.py:15 from runtime |
5242
| k_getsetattr.py:7 | self_1 | a | ArgumentRefinement(self_0) | int 0 | code/k_getsetattr.py:15 from runtime |

python/ql/test/library-tests/PointsTo/new/SsaAttr.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ private import semmle.python.pointsto.PointsToContext
55
import Util
66

77
from EssaVariable var, string name, Object o, PointsToContext ctx
8-
where PointsTo::Test::ssa_variable_named_attribute_points_to(var, ctx, name, o, _, _)
8+
where PointsTo::Test::ssa_variable_named_attribute_points_to(var, ctx, name, o, _, _) and not var.getSourceVariable() instanceof SpecialSsaSourceVariable
99
select
1010
locate(var.getDefinition().getLocation(), "abdfgikm"), var.getRepresentation(),
1111
name, var.getDefinition().getRepresentation(), repr(o), ctx

python/ql/test/library-tests/PointsTo/new/SsaUses.expected

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
| __init__.py:0 | *_2 | Exit node for Module code.test_package.__init__ |
21
| __init__.py:0 | __name___0 | Exit node for Module code.__init__ |
32
| __init__.py:0 | __name___0 | Exit node for Module code.package.__init__ |
43
| __init__.py:0 | __name___2 | Exit node for Module code.test_package.__init__ |
@@ -12,11 +11,9 @@
1211
| __init__.py:0 | moduleX_1 | Exit node for Module code.package.__init__ |
1312
| __init__.py:0 | module_0 | Exit node for Module code.package.__init__ |
1413
| __init__.py:0 | sys_2 | Exit node for Module code.test_package.__init__ |
15-
| __init__.py:1 | *_0 | ControlFlowNode for from module1 import * |
1614
| __init__.py:1 | __name___0 | ControlFlowNode for from module1 import * |
1715
| __init__.py:1 | __package___0 | ControlFlowNode for from module1 import * |
1816
| __init__.py:1 | sys_0 | ControlFlowNode for from module1 import * |
19-
| __init__.py:2 | *_1 | ControlFlowNode for from module2 import * |
2017
| __init__.py:2 | __name___1 | ControlFlowNode for from module2 import * |
2118
| __init__.py:2 | __package___1 | ControlFlowNode for from module2 import * |
2219
| __init__.py:2 | sys_1 | ControlFlowNode for from module2 import * |

python/ql/test/library-tests/PointsTo/new/SsaUses.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ import semmle.python.pointsto.PointsTo
55
import Util
66

77
from EssaVariable var, ControlFlowNode use
8-
where use = var.getAUse()
8+
where use = var.getAUse() and not var.getSourceVariable() instanceof SpecialSsaSourceVariable
99
select locate(use.getLocation(), "abdeghjks_"), var.getRepresentation(), use.toString()

0 commit comments

Comments
 (0)