Skip to content

Commit 89a331f

Browse files
authored
Merge pull request #10359 from tausbn/python-clean-up-import-resolution
Python: Clean up module resolution
2 parents 569fad6 + 5ce60d0 commit 89a331f

File tree

4 files changed

+49
-27
lines changed

4 files changed

+49
-27
lines changed

python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll

Lines changed: 5 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
private import python
22
private import DataFlowPublic
33
private import semmle.python.essa.SsaCompute
4-
private import semmle.python.dataflow.new.internal.ImportStar
4+
private import semmle.python.dataflow.new.internal.ImportResolution
55
// Since we allow extra data-flow steps from modeled frameworks, we import these
66
// up-front, to ensure these are included. This provides a more seamless experience from
77
// a user point of view, since they don't need to know they need to import a specific
@@ -335,11 +335,7 @@ predicate runtimeJumpStep(Node nodeFrom, Node nodeTo) {
335335
nodeFrom = nodeTo.(ModuleVariableNode).getAWrite()
336336
or
337337
// Setting the possible values of the variable at the end of import time
338-
exists(SsaVariable def |
339-
def = any(SsaVariable var).getAnUltimateDefinition() and
340-
def.getDefinition() = nodeFrom.asCfgNode() and
341-
def.getVariable() = nodeTo.(ModuleVariableNode).getVariable()
342-
)
338+
nodeFrom = nodeTo.(ModuleVariableNode).getADefiningWrite()
343339
}
344340

345341
/**
@@ -423,9 +419,9 @@ predicate jumpStepSharedWithTypeTracker(Node nodeFrom, Node nodeTo) {
423419
runtimeJumpStep(nodeFrom, nodeTo)
424420
or
425421
// Read of module attribute:
426-
exists(AttrRead r, ModuleValue mv |
427-
r.getObject().asCfgNode().pointsTo(mv) and
428-
module_export(mv.getScope(), r.getAttributeName(), nodeFrom) and
422+
exists(AttrRead r |
423+
ImportResolution::module_export(ImportResolution::getModule(r.getObject()),
424+
r.getAttributeName(), nodeFrom) and
429425
nodeTo = r
430426
)
431427
or
@@ -449,22 +445,6 @@ predicate jumpStepNotSharedWithTypeTracker(Node nodeFrom, Node nodeTo) {
449445
any(Orm::AdditionalOrmSteps es).jumpStep(nodeFrom, nodeTo)
450446
}
451447

452-
/**
453-
* Holds if the module `m` defines a name `name` by assigning `defn` to it. This is an
454-
* overapproximation, as `name` may not in fact be exported (e.g. by defining an `__all__` that does
455-
* not include `name`).
456-
*/
457-
private predicate module_export(Module m, string name, CfgNode defn) {
458-
exists(EssaVariable v |
459-
v.getName() = name and
460-
v.getAUse() = ImportStar::getStarImported*(m).getANormalExit()
461-
|
462-
defn.getNode() = v.getDefinition().(AssignmentDefinition).getValue()
463-
or
464-
defn.getNode() = v.getDefinition().(ArgumentRefinement).getArgument()
465-
)
466-
}
467-
468448
//--------
469449
// Field flow
470450
//--------

python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,15 @@ class ModuleVariableNode extends Node, TModuleVariableNode {
393393
result.asVar().getDefinition().(EssaNodeDefinition).definedBy(var, any(DefinitionNode defn))
394394
}
395395

396+
/** Gets the possible values of the variable at the end of import time */
397+
CfgNode getADefiningWrite() {
398+
exists(SsaVariable def |
399+
def = any(SsaVariable ssa_var).getAnUltimateDefinition() and
400+
def.getDefinition() = result.asCfgNode() and
401+
def.getVariable() = var
402+
)
403+
}
404+
396405
override DataFlowCallable getEnclosingCallable() { result.(DataFlowModuleScope).getScope() = mod }
397406

398407
override Location getLocation() { result = mod.getLocation() }
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
private import python
2+
private import semmle.python.dataflow.new.DataFlow
3+
private import semmle.python.dataflow.new.internal.ImportStar
4+
private import semmle.python.dataflow.new.TypeTracker
5+
6+
module ImportResolution {
7+
/**
8+
* Holds if the module `m` defines a name `name` by assigning `defn` to it. This is an
9+
* overapproximation, as `name` may not in fact be exported (e.g. by defining an `__all__` that does
10+
* not include `name`).
11+
*/
12+
predicate module_export(Module m, string name, DataFlow::CfgNode defn) {
13+
exists(EssaVariable v |
14+
v.getName() = name and
15+
v.getAUse() = ImportStar::getStarImported*(m).getANormalExit()
16+
|
17+
defn.getNode() = v.getDefinition().(AssignmentDefinition).getValue()
18+
or
19+
defn.getNode() = v.getDefinition().(ArgumentRefinement).getArgument()
20+
)
21+
}
22+
23+
Module getModule(DataFlow::CfgNode node) {
24+
exists(ModuleValue mv |
25+
node.getNode().pointsTo(mv) and
26+
result = mv.getScope()
27+
)
28+
}
29+
}

python/ql/lib/semmle/python/dataflow/new/internal/ImportStar.qll

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
private import python
44
private import semmle.python.dataflow.new.internal.Builtins
5+
private import semmle.python.dataflow.new.internal.ImportResolution
6+
private import semmle.python.dataflow.new.DataFlow
57

68
cached
79
module ImportStar {
@@ -71,8 +73,10 @@ module ImportStar {
7173
*/
7274
cached
7375
Module getStarImported(Module m) {
74-
exists(ImportStar i |
75-
i.getScope() = m and result = i.getModule().pointsTo().(ModuleValue).getScope()
76+
exists(ImportStar i, DataFlow::CfgNode imported_module |
77+
imported_module.getNode().getNode() = i.getModule() and
78+
i.getScope() = m and
79+
result = ImportResolution::getModule(imported_module)
7680
)
7781
}
7882

0 commit comments

Comments
 (0)