From dd2deacd0067e8de5e566da887a5584764cf63f5 Mon Sep 17 00:00:00 2001 From: yoff Date: Tue, 26 May 2026 10:09:04 +0000 Subject: [PATCH] Python: model `from X import *` as uncertain SSA writes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a 4th disjunct to `SsaImplInput::variableWrite` in the shared-SSA adapter that mirrors legacy ESSA's `ImportStarRefinement`: every variable whose scope is the import-star's scope, OR which is used in the import-star's scope, gets an uncertain write at the `import *` position. Uncertain writes do not kill prior definitions; shared SSA's `SsaUncertainWrite` joins the new value with the immediately-preceding definition via `uncertainWriteDefinitionInput`. This is the equivalent of legacy ESSA's two-input refinement. Cannot depend on `ImportStar` / `ImportResolution` (those modules import `SsaImpl`), so the predicate uses the structural heuristic on `Cfg::ImportStarNode` directly. This closes the two remaining failing dataflow library-tests: - `import-star/global` — `module_export` chains via `from X import *` re-exports now resolve: the importing module has an SSA def of every re-exported name, so `lastUseVar` finds the read at the use site. - `typetracking_imports/highlight_problem` — a direct `from .foo import foo` immediately followed by `from .other import *` is now correctly marked as dead at the direct import. Two scope-entry-def noise rows in `highlight_problem.expected` are also dropped — legacy ESSA needed them as refinement inputs, but shared SSA handles uncertain writes without an explicit prior def. They were always tagged `no use to normal exit` (dead). Dataflow library-tests: 62/64 → 64/64 passing. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../python/dataflow/new/internal/SsaImpl.qll | 45 ++++++++++++++----- .../highlight_problem.expected | 16 +++---- 2 files changed, 41 insertions(+), 20 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/SsaImpl.qll b/python/ql/lib/semmle/python/dataflow/new/internal/SsaImpl.qll index d406d30f148..d9609599a58 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/SsaImpl.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/SsaImpl.qll @@ -48,14 +48,6 @@ private module CfgForSsa implements BB::CfgSig { predicate dominatingEdge = CfgImpl::Cfg::dominatingEdge/2; } -/** - * A source variable for SSA. Wraps a Python `Variable` (the AST-level - * notion of a named binding within a scope) so that the shared SSA - * implementation can use it as a `SourceVariable`. - * - * We only track variables that are read at least once in their scope — - * tracking write-only variables is unnecessary work. - */ /** * A source variable for SSA, wrapping a Python AST `Variable`. * @@ -113,7 +105,9 @@ class SsaSourceVariable extends TSsaSourceVariable { * `SsaSourceVariable.getASourceUse()`. */ Cfg::ControlFlowNode getASourceUse() { - exists(Cfg::NameNode n | result = n | n.uses(this.getVariable()) or n.deletes(this.getVariable())) + exists(Cfg::NameNode n | result = n | + n.uses(this.getVariable()) or n.deletes(this.getVariable()) + ) } /** @@ -223,6 +217,31 @@ private module SsaImplInput implements SsaImplCommon::InputSig