From 4543c66d26ba2cd7df87869abfe32f45bd3ecbe4 Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 9 Jan 2026 13:49:17 +0000 Subject: [PATCH] Python: Prepare `LocalSourceNode` for locality Removes the dependence on the (global) `ModuleVariableNode.getARead()`, by adding a local version (that doesn't include `import *` reads) instead. --- .../python/dataflow/new/internal/DataFlowPublic.qll | 10 +++++++--- .../python/dataflow/new/internal/LocalSources.qll | 4 ++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll index 4d112bcdcdd..10ac89b023d 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll @@ -440,13 +440,17 @@ class ModuleVariableNode extends Node, TModuleVariableNode { /** Gets a node that reads this variable. */ Node getARead() { - result.asCfgNode() = var.getALoad().getAFlowNode() and - // Ignore reads that happen when the module is imported. These are only executed once. - not result.getScope() = mod + result = this.getALocalRead() or this = import_star_read(result) } + /** Gets a node that reads this variable, excluding reads that happen through `from ... import *`. */ + Node getALocalRead() { + result.asCfgNode() = var.getALoad().getAFlowNode() and + not result.getScope() = mod + } + /** Gets an `EssaNode` that corresponds to an assignment of this global variable. */ Node getAWrite() { any(EssaNodeDefinition def).definedBy(var, result.asCfgNode().(DefinitionNode)) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/LocalSources.qll b/python/ql/lib/semmle/python/dataflow/new/internal/LocalSources.qll index c43a111c9c8..7752846ae1f 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/LocalSources.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/LocalSources.qll @@ -67,7 +67,7 @@ class LocalSourceNode extends Node { or // We explicitly include any read of a global variable, as some of these may have local flow going // into them. - this = any(ModuleVariableNode mvn).getARead() + this = any(ModuleVariableNode v).getALocalRead() or // We include all scope entry definitions, as these act as the local source within the scope they // enter. @@ -248,7 +248,7 @@ private module Cached { pragma[nomagic] private predicate localSourceFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFrom, nodeTo, _) and - not nodeTo = any(ModuleVariableNode v).getARead() + not nodeTo = any(ModuleVariableNode v).getALocalRead() } /**