Skip to content

Commit 4138296

Browse files
authored
Python: Add test for "hidden" import * flow
TL;DR: We were missing out on flow in the following situation: `mod1.py`: ```python foo = SOURCE ``` `mod2.py`: ```python from mod1 import * ``` `test.py`: ```python from mod2 import foo SINK(foo) ``` This is because there's no node at which a read of `foo` takes place within `test.py`, and so the added reads make no difference. Unfortunately, this means the previous test was a bit too simplistic, since it only looks for module variable reads and writes. Because of this, we change the test to be a more traditional "all flow" style (though restricted to `CfgNode`s).
1 parent 09a11f4 commit 4138296

File tree

3 files changed

+25
-18
lines changed

3 files changed

+25
-18
lines changed
Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
moduleVariables
2-
| three.py:0:0:0:0 | ModuleVariableNode for three.foo |
3-
| trois.py:0:0:0:0 | ModuleVariableNode for trois.foo |
4-
reads
5-
| three.py:0:0:0:0 | ModuleVariableNode for three.foo | test1.py:2:7:2:9 | ControlFlowNode for foo |
6-
| three.py:0:0:0:0 | ModuleVariableNode for three.foo | two.py:2:7:2:9 | ControlFlowNode for foo |
7-
| trois.py:0:0:0:0 | ModuleVariableNode for trois.foo | deux.py:2:7:2:9 | ControlFlowNode for foo |
8-
| trois.py:0:0:0:0 | ModuleVariableNode for trois.foo | test2.py:2:7:2:9 | ControlFlowNode for foo |
9-
writes
10-
| three.py:1:1:1:3 | GSSA Variable foo | three.py:0:0:0:0 | ModuleVariableNode for three.foo |
11-
| trois.py:1:1:1:3 | GSSA Variable foo | trois.py:0:0:0:0 | ModuleVariableNode for trois.foo |
1+
| test3.py:1:17:1:19 | ControlFlowNode for ImportMember | test3.py:2:7:2:9 | ControlFlowNode for foo |
2+
| three.py:1:1:1:3 | ControlFlowNode for foo | test1.py:2:7:2:9 | ControlFlowNode for foo |
3+
| three.py:1:1:1:3 | ControlFlowNode for foo | two.py:2:7:2:9 | ControlFlowNode for foo |
4+
| three.py:1:7:1:7 | ControlFlowNode for IntegerLiteral | test1.py:2:7:2:9 | ControlFlowNode for foo |
5+
| three.py:1:7:1:7 | ControlFlowNode for IntegerLiteral | two.py:2:7:2:9 | ControlFlowNode for foo |
6+
| trois.py:1:1:1:3 | ControlFlowNode for foo | deux.py:2:7:2:9 | ControlFlowNode for foo |
7+
| trois.py:1:1:1:3 | ControlFlowNode for foo | test2.py:2:7:2:9 | ControlFlowNode for foo |
8+
| trois.py:1:7:1:7 | ControlFlowNode for IntegerLiteral | deux.py:2:7:2:9 | ControlFlowNode for foo |
9+
| trois.py:1:7:1:7 | ControlFlowNode for IntegerLiteral | test2.py:2:7:2:9 | ControlFlowNode for foo |
Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
1-
import python
21
import semmle.python.dataflow.new.DataFlow
32

4-
query DataFlow::Node moduleVariables() { result instanceof DataFlow::ModuleVariableNode }
3+
/**
4+
* A configuration to find all flows.
5+
* To be used on tiny programs.
6+
*/
7+
class AllFlowsConfig extends DataFlow::Configuration {
8+
AllFlowsConfig() { this = "AllFlowsConfig" }
59

6-
query predicate reads(DataFlow::Node fromNode, DataFlow::Node toNode) {
7-
fromNode.(DataFlow::ModuleVariableNode).getARead() = toNode
8-
}
10+
override predicate isSource(DataFlow::Node node) { any() }
911

10-
query predicate writes(DataFlow::Node fromNode, DataFlow::Node toNode) {
11-
fromNode = toNode.(DataFlow::ModuleVariableNode).getAWrite()
12+
override predicate isSink(DataFlow::Node node) { any() }
1213
}
14+
15+
from DataFlow::CfgNode source, DataFlow::CfgNode sink
16+
where
17+
source != sink and
18+
exists(AllFlowsConfig cfg | cfg.hasFlow(source, sink))
19+
select source, sink
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
from one import foo
2+
print(foo)

0 commit comments

Comments
 (0)