Skip to content

Commit fb8d0f5

Browse files
authored
Merge pull request #850 from markshannon/python-improve-import-analysis
Python improve import analysis
2 parents 184e65d + e37bda2 commit fb8d0f5

File tree

3 files changed

+58
-26
lines changed

3 files changed

+58
-26
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ private predicate class_with_global_metaclass(Class cls, GlobalVariable metaclas
337337

338338
/** Holds if this variable is implicitly defined */
339339
private predicate implicit_definition(Variable v) {
340-
v.getId() = "*"
340+
v.getId() = "*" or v.getId() = "$"
341341
or
342342
exists(ImportStar is | is.getScope() = v.getScope())
343343
}

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

Lines changed: 44 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -114,19 +114,23 @@ module PointsTo {
114114
/** INTERNAL -- Do not use.
115115
*
116116
* Holds if `package.name` points to `(value, cls, origin)`, where `package` is a package object. */
117-
cached predicate package_attribute_points_to(PackageObject package, string name, Object value, ClassObject cls, ControlFlowNode origin) {
117+
cached predicate package_attribute_points_to(PackageObject package, string name, Object value, ClassObject cls, ObjectOrCfg origin) {
118118
py_module_attributes(package.getInitModule().getModule(), name, value, cls, origin)
119119
or
120120
exists(Module init |
121-
init = package.getInitModule().getModule() |
122-
not exists(PythonSsaSourceVariable v | v.getScope() = init | v.getName() = name or v.getName() = "*")
123-
or
124-
exists(EssaVariable v, PointsToContext imp |
125-
v.getScope() = init and v.getName() = "*" and v.getAUse() = init.getANormalExit() |
126-
SSA::ssa_variable_named_attribute_points_to(v, imp, name, undefinedVariable(), _, _) and
127-
imp.isImport()
121+
init = package.getInitModule().getModule() and
122+
not exists(EssaVariable var | var.getAUse() = init.getANormalExit() and var.getSourceVariable().getName() = name) and
123+
exists(EssaVariable var, Context context |
124+
isModuleStateVariable(var) and var.getAUse() = init.getANormalExit() and
125+
context.isImport() and
126+
SSA::ssa_variable_named_attribute_points_to(var, context, name, undefinedVariable(), _, _) and
127+
origin = value and
128+
value = package.submodule(name) and
129+
cls = theModuleType()
128130
)
129-
) and explicitly_imported(value) and
131+
)
132+
or
133+
package.hasNoInitModule() and
130134
value = package.submodule(name) and cls = theModuleType() and origin = value
131135
}
132136

@@ -145,7 +149,7 @@ module PointsTo {
145149
or
146150
not exists(EssaVariable var | var.getAUse() = m.getANormalExit() and var.getSourceVariable().getName() = name) and
147151
exists(EssaVariable var, PointsToContext imp |
148-
var.getAUse() = m.getANormalExit() and var.getName() = "*" |
152+
var.getAUse() = m.getANormalExit() and isModuleStateVariable(var) |
149153
SSA::ssa_variable_named_attribute_points_to(var, imp, name, obj, cls, origin) and
150154
imp.isImport() and obj != undefinedVariable()
151155
)
@@ -661,19 +665,25 @@ module PointsTo {
661665
/** Holds if `f` is a "from import" expression, `from mod import x` and points to `(value, cls, origin)`. */
662666
pragma [nomagic]
663667
private predicate from_import_points_to(ImportMemberNode f, PointsToContext context, Object value, ClassObject cls, ControlFlowNode origin) {
664-
exists(EssaVariable var, ObjectOrCfg orig |
665-
live_import_from_dot_in_init(f, var) and
666-
ssa_variable_points_to(var, context, value, cls, orig) and
668+
exists(string name, ModuleObject mod, ObjectOrCfg orig |
669+
points_to(f.getModule(name), context, mod, _, _) and
667670
origin = origin_from_object_or_here(orig, f)
668-
)
669-
or
670-
not live_import_from_dot_in_init(f, _) and
671-
exists(string name, ModuleObject mod |
672-
points_to(f.getModule(name), context, mod, _, _) |
673-
exists(ObjectOrCfg orig |
674-
Layer::module_attribute_points_to(mod, name, value, cls, orig) and
675-
origin = origin_from_object_or_here(orig, f)
671+
|
672+
mod.getSourceModule() = f.getEnclosingModule() and
673+
exists(EssaVariable var |
674+
var.getSourceVariable().getName() = name and var.getAUse() = f and
675+
ssa_variable_points_to(var, context, value, cls, orig)
676676
)
677+
or
678+
mod.getSourceModule() = f.getEnclosingModule() and
679+
not exists(EssaVariable var | var.getSourceVariable().getName() = name and var.getAUse() = f) and
680+
exists(EssaVariable dollar |
681+
isModuleStateVariable(dollar) and dollar.getAUse() = f and
682+
SSA::ssa_variable_named_attribute_points_to(dollar, context, name, value, cls, orig)
683+
)
684+
or
685+
not mod.getSourceModule() = f.getEnclosingModule() and
686+
Layer::module_attribute_points_to(mod, name, value, cls, orig)
677687
)
678688
}
679689

@@ -1679,7 +1689,7 @@ module PointsTo {
16791689
/* Undefined variable */
16801690
exists(Scope scope |
16811691
not def.getVariable().getName() = "__name__" and
1682-
not def.getVariable().getName() = "*" and
1692+
not def.getVariable().getName() = "$" and
16831693
def.getScope() = scope and context.appliesToScope(scope) |
16841694
def.getSourceVariable() instanceof GlobalVariable and scope instanceof Module
16851695
or
@@ -1852,7 +1862,7 @@ module PointsTo {
18521862
)
18531863
or
18541864
origin = def.getDefiningNode() and
1855-
def.getSourceVariable().getName() = "*" and
1865+
isModuleStateVariable(def.getVariable()) and
18561866
context.isImport() and
18571867
exists(PackageObject package |
18581868
package.getInitModule().getModule() = def.getScope() |
@@ -1963,7 +1973,7 @@ module PointsTo {
19631973
/* Helper for import_star_named_attribute_points_to */
19641974
pragma [noinline]
19651975
private predicate star_variable_import_star_module(ImportStarRefinement def, ImportStarNode imp, PointsToContext context, ModuleObject mod) {
1966-
def.getSourceVariable().getName() = "*" and
1976+
isModuleStateVariable(def.getVariable()) and
19671977
exists(ControlFlowNode fmod |
19681978
fmod = imp.getModule() and
19691979
imp = def.getDefiningNode() and
@@ -1983,7 +1993,7 @@ module PointsTo {
19831993
/* Helper for ssa_star_variable_input_points_to */
19841994
pragma [noinline]
19851995
private predicate ssa_star_import_star_input(ImportStarRefinement def, EssaVariable var) {
1986-
def.getSourceVariable().getName() = "*" and var = def.getInput()
1996+
isModuleStateVariable(def.getVariable()) and var = def.getInput()
19871997
}
19881998

19891999
pragma [noinline]
@@ -2777,6 +2787,15 @@ module PointsTo {
27772787

27782788
}
27792789

2790+
/** Get the ESSA pseudo-variable used to retain module state
2791+
* during module initialization. Module attributes are handled
2792+
* as attributes of this variable, allowing the SSA form to track
2793+
* mutations of the module during its creation.
2794+
*/
2795+
private predicate isModuleStateVariable(EssaVariable var) {
2796+
var.getName() = "$" and var.getScope() instanceof Module
2797+
}
2798+
27802799
/** INTERNAL -- Public for testing only */
27812800
module Test {
27822801

python/ql/src/semmle/python/types/ModuleObject.qll

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ abstract class ModuleObject extends Object {
1616
none()
1717
}
1818

19+
/** Gets the source scope corresponding to this module, if this is a Python module */
20+
Module getSourceModule() {
21+
none()
22+
}
23+
1924
Container getPath() {
2025
none()
2126
}
@@ -136,6 +141,10 @@ class PythonModuleObject extends ModuleObject {
136141
result = this.getOrigin()
137142
}
138143

144+
override Module getSourceModule() {
145+
result = this.getOrigin()
146+
}
147+
139148
override Container getPath() {
140149
result = this.getModule().getFile()
141150
}
@@ -206,6 +215,10 @@ class PackageObject extends ModuleObject {
206215
result = this.getOrigin()
207216
}
208217

218+
override Module getSourceModule() {
219+
result = this.getModule().getInitModule()
220+
}
221+
209222
override Container getPath() {
210223
exists(ModuleObject m |
211224
m.getPackage() = this |

0 commit comments

Comments
 (0)