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).
This commit is contained in:
Taus
2021-12-02 17:05:54 +00:00
committed by GitHub
parent 09a11f4166
commit 4138296ec6
3 changed files with 25 additions and 18 deletions

View File

@@ -1,11 +1,9 @@
moduleVariables
| three.py:0:0:0:0 | ModuleVariableNode for three.foo |
| trois.py:0:0:0:0 | ModuleVariableNode for trois.foo |
reads
| three.py:0:0:0:0 | ModuleVariableNode for three.foo | test1.py:2:7:2:9 | ControlFlowNode for foo |
| three.py:0:0:0:0 | ModuleVariableNode for three.foo | two.py:2:7:2:9 | ControlFlowNode for foo |
| trois.py:0:0:0:0 | ModuleVariableNode for trois.foo | deux.py:2:7:2:9 | ControlFlowNode for foo |
| trois.py:0:0:0:0 | ModuleVariableNode for trois.foo | test2.py:2:7:2:9 | ControlFlowNode for foo |
writes
| three.py:1:1:1:3 | GSSA Variable foo | three.py:0:0:0:0 | ModuleVariableNode for three.foo |
| trois.py:1:1:1:3 | GSSA Variable foo | trois.py:0:0:0:0 | ModuleVariableNode for trois.foo |
| test3.py:1:17:1:19 | ControlFlowNode for ImportMember | test3.py:2:7:2:9 | ControlFlowNode for foo |
| three.py:1:1:1:3 | ControlFlowNode for foo | test1.py:2:7:2:9 | ControlFlowNode for foo |
| three.py:1:1:1:3 | ControlFlowNode for foo | two.py:2:7:2:9 | ControlFlowNode for foo |
| three.py:1:7:1:7 | ControlFlowNode for IntegerLiteral | test1.py:2:7:2:9 | ControlFlowNode for foo |
| three.py:1:7:1:7 | ControlFlowNode for IntegerLiteral | two.py:2:7:2:9 | ControlFlowNode for foo |
| trois.py:1:1:1:3 | ControlFlowNode for foo | deux.py:2:7:2:9 | ControlFlowNode for foo |
| trois.py:1:1:1:3 | ControlFlowNode for foo | test2.py:2:7:2:9 | ControlFlowNode for foo |
| trois.py:1:7:1:7 | ControlFlowNode for IntegerLiteral | deux.py:2:7:2:9 | ControlFlowNode for foo |
| trois.py:1:7:1:7 | ControlFlowNode for IntegerLiteral | test2.py:2:7:2:9 | ControlFlowNode for foo |

View File

@@ -1,12 +1,19 @@
import python
import semmle.python.dataflow.new.DataFlow
query DataFlow::Node moduleVariables() { result instanceof DataFlow::ModuleVariableNode }
/**
* A configuration to find all flows.
* To be used on tiny programs.
*/
class AllFlowsConfig extends DataFlow::Configuration {
AllFlowsConfig() { this = "AllFlowsConfig" }
query predicate reads(DataFlow::Node fromNode, DataFlow::Node toNode) {
fromNode.(DataFlow::ModuleVariableNode).getARead() = toNode
override predicate isSource(DataFlow::Node node) { any() }
override predicate isSink(DataFlow::Node node) { any() }
}
query predicate writes(DataFlow::Node fromNode, DataFlow::Node toNode) {
fromNode = toNode.(DataFlow::ModuleVariableNode).getAWrite()
}
from DataFlow::CfgNode source, DataFlow::CfgNode sink
where
source != sink and
exists(AllFlowsConfig cfg | cfg.hasFlow(source, sink))
select source, sink

View File

@@ -0,0 +1,2 @@
from one import foo
print(foo)