mirror of
https://github.com/github/codeql.git
synced 2026-05-01 03:35:13 +02:00
Python: Support flow through import *
Adds result for `ModuleVariableNode::getARead` corresponding to reads that go through (chains of) `import *`. This required a bit of a change to _which_ module variables we define. Previously, we only included variables that were accessed elsewhere in the same file, but now we must ensure to also include variables that may be accessed through `import *`.
This commit is contained in:
@@ -8,6 +8,7 @@ import semmle.python.dataflow.new.TypeTracker
|
||||
import Attributes
|
||||
import LocalSources
|
||||
private import semmle.python.essa.SsaCompute
|
||||
private import semmle.python.dataflow.new.internal.ImportStar
|
||||
|
||||
/**
|
||||
* IPA type for data flow nodes.
|
||||
@@ -30,7 +31,15 @@ newtype TNode =
|
||||
/** A synthetic node representing the value of an object after a state change. */
|
||||
TSyntheticPostUpdateNode(NeedsSyntheticPostUpdateNode pre) or
|
||||
/** A node representing a global (module-level) variable in a specific module. */
|
||||
TModuleVariableNode(Module m, GlobalVariable v) { v.getScope() = m and v.escapes() } or
|
||||
TModuleVariableNode(Module m, GlobalVariable v) {
|
||||
v.getScope() = m and
|
||||
(
|
||||
v.escapes()
|
||||
or
|
||||
isAccessedThroughImportStar(m) and
|
||||
ImportStar::globalNameDefinedInModule(v.getId(), m)
|
||||
)
|
||||
} or
|
||||
/**
|
||||
* A node representing the overflow positional arguments to a call.
|
||||
* That is, `call` contains more positional arguments than there are
|
||||
@@ -346,6 +355,8 @@ class ModuleVariableNode extends Node, TModuleVariableNode {
|
||||
result.asCfgNode() = var.getALoad().getAFlowNode() and
|
||||
// Ignore reads that happen when the module is imported. These are only executed once.
|
||||
not result.getScope() = mod
|
||||
or
|
||||
this = import_star_read(result)
|
||||
}
|
||||
|
||||
/** Gets an `EssaNode` that corresponds to an assignment of this global variable. */
|
||||
@@ -358,6 +369,13 @@ class ModuleVariableNode extends Node, TModuleVariableNode {
|
||||
override Location getLocation() { result = mod.getLocation() }
|
||||
}
|
||||
|
||||
private predicate isAccessedThroughImportStar(Module m) { m = ImportStar::getStarImported(_) }
|
||||
|
||||
private ModuleVariableNode import_star_read(Node n) {
|
||||
ImportStar::importStarResolvesTo(n.asCfgNode(), result.getModule()) and
|
||||
n.asCfgNode().(NameNode).getId() = result.getVariable().getId()
|
||||
}
|
||||
|
||||
/**
|
||||
* The node holding the extra positional arguments to a call. This node is passed as a tuple
|
||||
* to the starred parameter of the callable.
|
||||
|
||||
@@ -1 +1 @@
|
||||
known_attr = [1000]
|
||||
known_attr = [1000] #$ writes=known_attr
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
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 |
|
||||
|
||||
Reference in New Issue
Block a user