Skip to content

Commit 39e7bba

Browse files
authored
Merge pull request github#12203 from RasmusWL/import-resolution-phi
Python: Handle if-then-else definitions in import resolution
2 parents 2f8ddda + 9ed021a commit 39e7bba

File tree

5 files changed

+34
-4
lines changed

5 files changed

+34
-4
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Fixed module resolution so we properly recognize definitions made within if-then-else statements.

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

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,19 @@ module ImportResolution {
7171
*/
7272
pragma[nomagic]
7373
predicate module_export(Module m, string name, DataFlow::CfgNode defn) {
74-
exists(EssaVariable v |
74+
exists(EssaVariable v, EssaDefinition essaDef |
7575
v.getName() = name and
76-
v.getAUse() = ImportStar::getStarImported*(m).getANormalExit()
76+
v.getAUse() = ImportStar::getStarImported*(m).getANormalExit() and
77+
(
78+
essaDef = v.getDefinition()
79+
or
80+
// to handle definitions guarded by if-then-else
81+
essaDef = v.getDefinition().(PhiFunction).getAnInput()
82+
)
7783
|
78-
defn.getNode() = v.getDefinition().(AssignmentDefinition).getValue()
84+
defn.getNode() = essaDef.(AssignmentDefinition).getValue()
7985
or
80-
defn.getNode() = v.getDefinition().(ArgumentRefinement).getArgument()
86+
defn.getNode() = essaDef.(ArgumentRefinement).getArgument()
8187
)
8288
or
8389
exists(Alias a |
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
from trace import *
2+
enter(__file__)
3+
4+
# definition based on "random" choice in this case it will always go the the if-branch,
5+
# but our analysis is not able to figure this out
6+
if eval("True"):
7+
if_then_else_defined = "if_defined"
8+
else:
9+
# we also check that nested if-then-else works, it would be easy to accidentally
10+
# only support _one_ level of nesting.
11+
if eval("True"):
12+
if_then_else_defined = "else_defined_1"
13+
else:
14+
if_then_else_defined = "else_defined_2"
15+
16+
exit(__file__)

python/ql/test/experimental/import-resolution/main.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@ def local_import():
8989
from package.subpackage2 import *
9090
check("subpackage2_attr", subpackage2_attr, "subpackage2_attr", globals()) #$ prints=subpackage2_attr
9191

92+
# check that definitions from within if-then-else are found
93+
from if_then_else import if_then_else_defined
94+
check("if_then_else_defined", if_then_else_defined, "if_defined", globals()) #$ prints=if_defined prints=else_defined_1 prints=else_defined_2
9295

9396
exit(__file__)
9497

python/ql/test/query-tests/Security/CWE-732-WeakFilePermissions/WeakFilePermissions.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@
22
| test.py:8:1:8:20 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to world writable. |
33
| test.py:9:1:9:21 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to world writable. |
44
| test.py:11:1:11:21 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to group readable. |
5+
| test.py:13:1:13:28 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to group writable. |
56
| test.py:14:1:14:19 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to group writable. |
67
| test.py:16:1:16:25 | ControlFlowNode for Attribute() | Overly permissive mask in open sets file to world readable. |

0 commit comments

Comments
 (0)