Skip to content

Commit 07e8d99

Browse files
committed
Python: exclude constants from being SSA variables
1 parent 8d3dba9 commit 07e8d99

3 files changed

Lines changed: 31 additions & 18 deletions

File tree

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

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -45,24 +45,27 @@ private import codeql.controlflow.BasicBlock as BB
4545
*/
4646
private newtype TSsaSourceVariable =
4747
TPyVar(Py::Variable v) {
48-
// Has a use somewhere — read-relevant for SSA.
49-
exists(Cfg::NameNode n | n.uses(v))
50-
or
51-
// Or has a deletion (treated as a write that destroys the value).
52-
exists(Cfg::NameNode n | n.deletes(v))
53-
or
54-
// Or is a module-scope global written in this module — must be
55-
// tracked even if never read locally, because importers may read
56-
// it as an attribute on the module object.
57-
v.getScope() instanceof Py::Module and
58-
exists(Cfg::NameNode n | n.defines(v))
59-
or
60-
// Or is a parameter — parameters must always have a
61-
// `ParameterDefinition` for dataflow argument-routing to work,
62-
// even if the parameter is never read in its scope. Mirrors
63-
// legacy ESSA's `ParameterDefinition` (which fired for every
64-
// parameter binding regardless of liveness).
65-
exists(Py::Parameter p | p.asName() = v.getAStore())
48+
not v.getALoad() instanceof Py::NameConstant and
49+
(
50+
// Has a use somewhere — read-relevant for SSA.
51+
exists(Cfg::NameNode n | n.uses(v))
52+
or
53+
// Or has a deletion (treated as a write that destroys the value).
54+
exists(Cfg::NameNode n | n.deletes(v))
55+
or
56+
// Or is a module-scope global written in this module — must be
57+
// tracked even if never read locally, because importers may read
58+
// it as an attribute on the module object.
59+
v.getScope() instanceof Py::Module and
60+
exists(Cfg::NameNode n | n.defines(v))
61+
or
62+
// Or is a parameter — parameters must always have a
63+
// `ParameterDefinition` for dataflow argument-routing to work,
64+
// even if the parameter is never read in its scope. Mirrors
65+
// legacy ESSA's `ParameterDefinition` (which fired for every
66+
// parameter binding regardless of liveness).
67+
exists(Py::Parameter p | p.asName() = v.getAStore())
68+
)
6669
}
6770

6871
/**

python/ql/test/library-tests/dataflow-new-ssa-vs-legacy/CmpTest.ql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,10 @@ where
5252
kind = "def-only-old" and
5353
sig = legacyDefSig(_) and
5454
not sig = newDefSig(_)
55+
or
56+
kind = "constant-variable" and
57+
exists(NewSsa::SsaSourceVariable v |
58+
v.getVariable().getALoad() instanceof NameConstant and
59+
sig = v.getName()
60+
)
5561
select kind, sig

python/ql/test/library-tests/dataflow-new-ssa-vs-legacy/test.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,7 @@ def with_binding():
5151

5252
def read_global():
5353
return GLOBAL
54+
55+
56+
def constants():
57+
return True, False, None

0 commit comments

Comments
 (0)