From de7744950ff5733c96946a3b86bc96d574ebbf06 Mon Sep 17 00:00:00 2001 From: yoff Date: Thu, 28 May 2026 13:13:11 +0000 Subject: [PATCH] Python: migrate remaining tests off getAFlowNode() and fix star-import SSA step Sweep the last few uses of legacy AstNode.getAFlowNode() in tests over to explicit ControlFlowNode joins after the shared-CFG migration. importflow.ql needs the new Cfg::ControlFlowNode/CompareNode types because DataFlow::Node. asCfgNode() now returns the shared-CFG node. Also extend ImportResolution::allowedEssaImportStep to walk back through uncertain-write SSA inputs, so that a later 'from X import *' does not hide the preceding explicit (re)assignment from module-export resolution. Without this, a reassigned name that survives a wildcard import was no longer recognised as the module export. Rebless ModuleExport.expected to drop the legacy 'ControlFlowNode for' toString prefix and pick up the two correct rows exposed by the fix. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../new/internal/ImportResolution.qll | 8 +- .../comprehensions/ConsistencyCheck.ql | 4 +- .../import-resolution/ModuleExport.expected | 240 +++++++++--------- .../import-resolution/importflow.ql | 9 +- .../PointsToSupport/UseFromDefinition.ql | 2 +- .../ControlFlow/splitting/NodeCount.ql | 2 +- .../dataflow/tainttracking/TestTaintLib.qll | 2 +- 7 files changed, 139 insertions(+), 128 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/ImportResolution.qll b/python/ql/lib/semmle/python/dataflow/new/internal/ImportResolution.qll index 735a7e831bd..38ec4d146a4 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/ImportResolution.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/ImportResolution.qll @@ -87,8 +87,14 @@ module ImportResolution { ) { // to handle definitions guarded by if-then-else defFrom = defTo.(SsaImpl::PhiFunction).getAnInput() + or + // to handle uncertain writes such as `from X import *`, which create an + // uncertain SSA definition for every name in the importing scope. The + // immediately preceding definition is still potentially the value of the + // module export. + SsaImpl::Ssa::uncertainWriteDefinitionInput(defTo, defFrom) // Note: legacy ESSA refinement-step (e.g. for `foo.bar = X`) is - // not modelled in the new SSA. We rely on phi steps only. + // not modelled in the new SSA beyond the cases handled above. } /** diff --git a/python/ql/test/2/library-tests/comprehensions/ConsistencyCheck.ql b/python/ql/test/2/library-tests/comprehensions/ConsistencyCheck.ql index 2f5191fb547..c1a214e40c7 100644 --- a/python/ql/test/2/library-tests/comprehensions/ConsistencyCheck.ql +++ b/python/ql/test/2/library-tests/comprehensions/ConsistencyCheck.ql @@ -5,5 +5,7 @@ import python select count(Comprehension c | - count(c.toString()) != 1 or count(c.getLocation()) != 1 or not exists(c.getAFlowNode()) + count(c.toString()) != 1 or + count(c.getLocation()) != 1 or + not exists(ControlFlowNode n | n.getNode() = c) ) diff --git a/python/ql/test/experimental/import-resolution/ModuleExport.expected b/python/ql/test/experimental/import-resolution/ModuleExport.expected index f67ae004011..80605a523c0 100644 --- a/python/ql/test/experimental/import-resolution/ModuleExport.expected +++ b/python/ql/test/experimental/import-resolution/ModuleExport.expected @@ -1,120 +1,120 @@ -| attr_clash.__init__ | __file__ | attr_clash/__init__.py:6:6:6:13 | ControlFlowNode for __file__ | -| attr_clash.__init__ | clashing_attr | attr_clash/__init__.py:4:1:4:13 | ControlFlowNode for clashing_attr | -| attr_clash.__init__ | enter | attr_clash/__init__.py:2:1:2:5 | ControlFlowNode for enter | -| attr_clash.__init__ | exit | attr_clash/__init__.py:6:1:6:4 | ControlFlowNode for exit | -| attr_clash.clashing_attr | __file__ | attr_clash/clashing_attr.py:4:6:4:13 | ControlFlowNode for __file__ | -| attr_clash.clashing_attr | enter | attr_clash/clashing_attr.py:2:1:2:5 | ControlFlowNode for enter | -| attr_clash.clashing_attr | exit | attr_clash/clashing_attr.py:4:1:4:4 | ControlFlowNode for exit | -| attr_clash.non_clashing_submodule | __file__ | attr_clash/non_clashing_submodule.py:4:6:4:13 | ControlFlowNode for __file__ | -| attr_clash.non_clashing_submodule | enter | attr_clash/non_clashing_submodule.py:2:1:2:5 | ControlFlowNode for enter | -| attr_clash.non_clashing_submodule | exit | attr_clash/non_clashing_submodule.py:4:1:4:4 | ControlFlowNode for exit | -| bar | __file__ | bar.py:6:6:6:13 | ControlFlowNode for __file__ | -| bar | bar_attr | bar.py:4:1:4:8 | ControlFlowNode for bar_attr | -| bar | enter | bar.py:2:1:2:5 | ControlFlowNode for enter | -| bar | exit | bar.py:6:1:6:4 | ControlFlowNode for exit | -| baz | __file__ | baz.py:6:6:6:13 | ControlFlowNode for __file__ | -| baz | baz_attr | baz.py:4:1:4:8 | ControlFlowNode for baz_attr | -| baz | enter | baz.py:2:1:2:5 | ControlFlowNode for enter | -| baz | exit | baz.py:6:1:6:4 | ControlFlowNode for exit | -| block_flow_check | SOURCE | block_flow_check.py:12:25:12:30 | ControlFlowNode for SOURCE | -| block_flow_check | __file__ | block_flow_check.py:14:6:14:13 | ControlFlowNode for __file__ | -| block_flow_check | check | block_flow_check.py:12:1:12:5 | ControlFlowNode for check | -| block_flow_check | enter | block_flow_check.py:2:1:2:5 | ControlFlowNode for enter | -| block_flow_check | exit | block_flow_check.py:14:1:14:4 | ControlFlowNode for exit | -| block_flow_check | globals | block_flow_check.py:12:33:12:39 | ControlFlowNode for globals | -| block_flow_check | object | block_flow_check.py:4:14:4:19 | ControlFlowNode for object | -| foo | __file__ | foo.py:14:6:14:13 | ControlFlowNode for __file__ | -| foo | __private_foo_attr | foo.py:8:1:8:18 | ControlFlowNode for __private_foo_attr | -| foo | bar_reexported | foo.py:11:8:11:10 | ControlFlowNode for ImportExpr | -| foo | bar_reexported | foo.py:12:34:12:47 | ControlFlowNode for bar_reexported | -| foo | check | foo.py:12:1:12:5 | ControlFlowNode for check | -| foo | enter | foo.py:2:1:2:5 | ControlFlowNode for enter | -| foo | exit | foo.py:14:1:14:4 | ControlFlowNode for exit | -| foo | foo_attr | foo.py:5:1:5:8 | ControlFlowNode for foo_attr | -| foo | globals | foo.py:12:71:12:77 | ControlFlowNode for globals | -| generous_export | Exception | generous_export.py:16:11:16:19 | ControlFlowNode for Exception | -| generous_export | SOURCE | generous_export.py:15:11:15:16 | ControlFlowNode for SOURCE | -| generous_export | SOURCE | generous_export.py:20:25:20:30 | ControlFlowNode for SOURCE | -| generous_export | __file__ | generous_export.py:22:6:22:13 | ControlFlowNode for __file__ | -| generous_export | check | generous_export.py:20:1:20:5 | ControlFlowNode for check | -| generous_export | enter | generous_export.py:2:1:2:5 | ControlFlowNode for enter | -| generous_export | eval | generous_export.py:10:4:10:7 | ControlFlowNode for eval | -| generous_export | exit | generous_export.py:22:1:22:4 | ControlFlowNode for exit | -| generous_export | globals | generous_export.py:20:33:20:39 | ControlFlowNode for globals | -| generous_export | object | generous_export.py:4:14:4:19 | ControlFlowNode for object | -| generous_export | print | generous_export.py:15:5:15:9 | ControlFlowNode for print | -| has_defined_all | __all__ | has_defined_all.py:7:1:7:7 | ControlFlowNode for __all__ | -| has_defined_all | __file__ | has_defined_all.py:9:6:9:13 | ControlFlowNode for __file__ | -| has_defined_all | all_defined_bar | has_defined_all.py:5:1:5:15 | ControlFlowNode for all_defined_bar | -| has_defined_all | all_defined_foo | has_defined_all.py:4:1:4:15 | ControlFlowNode for all_defined_foo | -| has_defined_all | enter | has_defined_all.py:2:1:2:5 | ControlFlowNode for enter | -| has_defined_all | exit | has_defined_all.py:9:1:9:4 | ControlFlowNode for exit | -| has_defined_all_copy | __all__ | has_defined_all_copy.py:9:1:9:7 | ControlFlowNode for __all__ | -| has_defined_all_copy | __file__ | has_defined_all_copy.py:11:6:11:13 | ControlFlowNode for __file__ | -| has_defined_all_copy | all_defined_bar_copy | has_defined_all_copy.py:7:1:7:20 | ControlFlowNode for all_defined_bar_copy | -| has_defined_all_copy | all_defined_foo_copy | has_defined_all_copy.py:6:1:6:20 | ControlFlowNode for all_defined_foo_copy | -| has_defined_all_copy | enter | has_defined_all_copy.py:4:1:4:5 | ControlFlowNode for enter | -| has_defined_all_copy | exit | has_defined_all_copy.py:11:1:11:4 | ControlFlowNode for exit | -| has_defined_all_indirection | __file__ | has_defined_all_indirection.py:6:6:6:13 | ControlFlowNode for __file__ | -| has_defined_all_indirection | all_defined_foo_copy | has_defined_all_copy.py:6:1:6:20 | ControlFlowNode for all_defined_foo_copy | -| has_defined_all_indirection | enter | has_defined_all_indirection.py:2:1:2:5 | ControlFlowNode for enter | -| has_defined_all_indirection | exit | has_defined_all_indirection.py:6:1:6:4 | ControlFlowNode for exit | -| if_then_else | __file__ | if_then_else.py:16:6:16:13 | ControlFlowNode for __file__ | -| if_then_else | enter | if_then_else.py:2:1:2:5 | ControlFlowNode for enter | -| if_then_else | eval | if_then_else.py:11:8:11:11 | ControlFlowNode for eval | -| if_then_else | exit | if_then_else.py:16:1:16:4 | ControlFlowNode for exit | -| if_then_else | if_then_else_defined | if_then_else.py:7:5:7:24 | ControlFlowNode for if_then_else_defined | -| if_then_else | if_then_else_defined | if_then_else.py:12:9:12:28 | ControlFlowNode for if_then_else_defined | -| if_then_else | if_then_else_defined | if_then_else.py:14:9:14:28 | ControlFlowNode for if_then_else_defined | -| if_then_else_refined | SOURCE | if_then_else_refined.py:11:11:11:16 | ControlFlowNode for SOURCE | -| if_then_else_refined | SOURCE | if_then_else_refined.py:13:11:13:16 | ControlFlowNode for SOURCE | -| if_then_else_refined | __file__ | if_then_else_refined.py:19:6:19:13 | ControlFlowNode for __file__ | -| if_then_else_refined | check | if_then_else_refined.py:17:1:17:5 | ControlFlowNode for check | -| if_then_else_refined | enter | if_then_else_refined.py:4:1:4:5 | ControlFlowNode for enter | -| if_then_else_refined | eval | if_then_else_refined.py:10:4:10:7 | ControlFlowNode for eval | -| if_then_else_refined | exit | if_then_else_refined.py:19:1:19:4 | ControlFlowNode for exit | -| if_then_else_refined | globals | if_then_else_refined.py:17:24:17:30 | ControlFlowNode for globals | -| if_then_else_refined | src | if_then_else_refined.py:17:19:17:21 | ControlFlowNode for src | -| package.__init__ | __file__ | package/__init__.py:7:6:7:13 | ControlFlowNode for __file__ | -| package.__init__ | attr_used_in_subpackage | package/__init__.py:4:1:4:23 | ControlFlowNode for attr_used_in_subpackage | -| package.__init__ | enter | package/__init__.py:2:1:2:5 | ControlFlowNode for enter | -| package.__init__ | exit | package/__init__.py:7:1:7:4 | ControlFlowNode for exit | -| package.__init__ | package_attr | package/__init__.py:5:1:5:12 | ControlFlowNode for package_attr | -| package.subpackage2.__init__ | __file__ | package/subpackage2/__init__.py:6:6:6:13 | ControlFlowNode for __file__ | -| package.subpackage2.__init__ | enter | package/subpackage2/__init__.py:2:1:2:5 | ControlFlowNode for enter | -| package.subpackage2.__init__ | exit | package/subpackage2/__init__.py:6:1:6:4 | ControlFlowNode for exit | -| package.subpackage2.__init__ | subpackage2_attr | package/subpackage2/__init__.py:4:1:4:16 | ControlFlowNode for subpackage2_attr | -| package.subpackage.__init__ | __file__ | package/subpackage/__init__.py:14:6:14:13 | ControlFlowNode for __file__ | -| package.subpackage.__init__ | check | package/subpackage/__init__.py:12:1:12:5 | ControlFlowNode for check | -| package.subpackage.__init__ | enter | package/subpackage/__init__.py:2:1:2:5 | ControlFlowNode for enter | -| package.subpackage.__init__ | exit | package/subpackage/__init__.py:14:1:14:4 | ControlFlowNode for exit | -| package.subpackage.__init__ | globals | package/subpackage/__init__.py:12:79:12:85 | ControlFlowNode for globals | -| package.subpackage.__init__ | imported_attr | package/subpackage/__init__.py:7:16:7:55 | ControlFlowNode for ImportMember | -| package.subpackage.__init__ | imported_attr | package/subpackage/__init__.py:8:24:8:36 | ControlFlowNode for imported_attr | -| package.subpackage.__init__ | irrelevant_attr | package/subpackage/__init__.py:11:24:11:38 | ControlFlowNode for ImportMember | -| package.subpackage.__init__ | irrelevant_attr | package/subpackage/__init__.py:11:24:11:38 | ControlFlowNode for irrelevant_attr | -| package.subpackage.__init__ | submodule | package/subpackage/__init__.py:12:35:12:43 | ControlFlowNode for submodule | -| package.subpackage.__init__ | subpackage_attr | package/subpackage/__init__.py:4:1:4:15 | ControlFlowNode for subpackage_attr | -| package.subpackage.submodule | __file__ | package/subpackage/submodule.py:7:6:7:13 | ControlFlowNode for __file__ | -| package.subpackage.submodule | enter | package/subpackage/submodule.py:2:1:2:5 | ControlFlowNode for enter | -| package.subpackage.submodule | exit | package/subpackage/submodule.py:7:1:7:4 | ControlFlowNode for exit | -| package.subpackage.submodule | irrelevant_attr | package/subpackage/submodule.py:5:1:5:15 | ControlFlowNode for irrelevant_attr | -| package.subpackage.submodule | submodule_attr | package/subpackage/submodule.py:4:1:4:14 | ControlFlowNode for submodule_attr | -| refined | SOURCE | refined.py:12:25:12:30 | ControlFlowNode for SOURCE | -| refined | __file__ | refined.py:14:6:14:13 | ControlFlowNode for __file__ | -| refined | check | refined.py:12:1:12:5 | ControlFlowNode for check | -| refined | enter | refined.py:2:1:2:5 | ControlFlowNode for enter | -| refined | exit | refined.py:14:1:14:4 | ControlFlowNode for exit | -| refined | globals | refined.py:12:33:12:39 | ControlFlowNode for globals | -| refined | object | refined.py:4:14:4:19 | ControlFlowNode for object | -| simplistic_reexport | __file__ | simplistic_reexport.py:19:6:19:13 | ControlFlowNode for __file__ | -| simplistic_reexport | bar_attr | simplistic_reexport.py:6:17:6:24 | ControlFlowNode for ImportMember | -| simplistic_reexport | bar_attr | simplistic_reexport.py:10:19:10:26 | ControlFlowNode for bar_attr | -| simplistic_reexport | baz_attr | baz.py:4:1:4:8 | ControlFlowNode for baz_attr | -| simplistic_reexport | baz_attr | simplistic_reexport.py:17:19:17:26 | ControlFlowNode for baz_attr | -| simplistic_reexport | check | simplistic_reexport.py:17:1:17:5 | ControlFlowNode for check | -| simplistic_reexport | enter | baz.py:2:1:2:5 | ControlFlowNode for enter | -| simplistic_reexport | enter | simplistic_reexport.py:4:1:4:5 | ControlFlowNode for enter | -| simplistic_reexport | exit | baz.py:6:1:6:4 | ControlFlowNode for exit | -| simplistic_reexport | exit | simplistic_reexport.py:19:1:19:4 | ControlFlowNode for exit | -| simplistic_reexport | globals | simplistic_reexport.py:17:44:17:50 | ControlFlowNode for globals | +| attr_clash.__init__ | __file__ | attr_clash/__init__.py:6:6:6:13 | __file__ | +| attr_clash.__init__ | clashing_attr | attr_clash/__init__.py:4:1:4:13 | clashing_attr | +| attr_clash.__init__ | enter | attr_clash/__init__.py:2:1:2:5 | enter | +| attr_clash.__init__ | exit | attr_clash/__init__.py:6:1:6:4 | exit | +| attr_clash.clashing_attr | __file__ | attr_clash/clashing_attr.py:4:6:4:13 | __file__ | +| attr_clash.clashing_attr | enter | attr_clash/clashing_attr.py:2:1:2:5 | enter | +| attr_clash.clashing_attr | exit | attr_clash/clashing_attr.py:4:1:4:4 | exit | +| attr_clash.non_clashing_submodule | __file__ | attr_clash/non_clashing_submodule.py:4:6:4:13 | __file__ | +| attr_clash.non_clashing_submodule | enter | attr_clash/non_clashing_submodule.py:2:1:2:5 | enter | +| attr_clash.non_clashing_submodule | exit | attr_clash/non_clashing_submodule.py:4:1:4:4 | exit | +| bar | __file__ | bar.py:6:6:6:13 | __file__ | +| bar | bar_attr | bar.py:4:1:4:8 | bar_attr | +| bar | enter | bar.py:2:1:2:5 | enter | +| bar | exit | bar.py:6:1:6:4 | exit | +| baz | __file__ | baz.py:6:6:6:13 | __file__ | +| baz | baz_attr | baz.py:4:1:4:8 | baz_attr | +| baz | enter | baz.py:2:1:2:5 | enter | +| baz | exit | baz.py:6:1:6:4 | exit | +| block_flow_check | SOURCE | block_flow_check.py:12:25:12:30 | SOURCE | +| block_flow_check | __file__ | block_flow_check.py:14:6:14:13 | __file__ | +| block_flow_check | check | block_flow_check.py:12:1:12:5 | check | +| block_flow_check | enter | block_flow_check.py:2:1:2:5 | enter | +| block_flow_check | exit | block_flow_check.py:14:1:14:4 | exit | +| block_flow_check | globals | block_flow_check.py:12:33:12:39 | globals | +| block_flow_check | object | block_flow_check.py:4:14:4:19 | object | +| foo | __file__ | foo.py:14:6:14:13 | __file__ | +| foo | __private_foo_attr | foo.py:8:1:8:18 | __private_foo_attr | +| foo | bar_reexported | foo.py:11:8:11:10 | ImportExpr | +| foo | bar_reexported | foo.py:12:34:12:47 | bar_reexported | +| foo | check | foo.py:12:1:12:5 | check | +| foo | enter | foo.py:2:1:2:5 | enter | +| foo | exit | foo.py:14:1:14:4 | exit | +| foo | foo_attr | foo.py:5:1:5:8 | foo_attr | +| foo | globals | foo.py:12:71:12:77 | globals | +| generous_export | Exception | generous_export.py:16:11:16:19 | Exception | +| generous_export | SOURCE | generous_export.py:15:11:15:16 | SOURCE | +| generous_export | SOURCE | generous_export.py:20:25:20:30 | SOURCE | +| generous_export | __file__ | generous_export.py:22:6:22:13 | __file__ | +| generous_export | check | generous_export.py:20:1:20:5 | check | +| generous_export | enter | generous_export.py:2:1:2:5 | enter | +| generous_export | eval | generous_export.py:10:4:10:7 | eval | +| generous_export | exit | generous_export.py:22:1:22:4 | exit | +| generous_export | globals | generous_export.py:20:33:20:39 | globals | +| generous_export | object | generous_export.py:4:14:4:19 | object | +| generous_export | print | generous_export.py:15:5:15:9 | print | +| has_defined_all | __all__ | has_defined_all.py:7:1:7:7 | __all__ | +| has_defined_all | __file__ | has_defined_all.py:9:6:9:13 | __file__ | +| has_defined_all | all_defined_bar | has_defined_all.py:5:1:5:15 | all_defined_bar | +| has_defined_all | all_defined_foo | has_defined_all.py:4:1:4:15 | all_defined_foo | +| has_defined_all | enter | has_defined_all.py:2:1:2:5 | enter | +| has_defined_all | exit | has_defined_all.py:9:1:9:4 | exit | +| has_defined_all_copy | __all__ | has_defined_all_copy.py:9:1:9:7 | __all__ | +| has_defined_all_copy | __file__ | has_defined_all_copy.py:11:6:11:13 | __file__ | +| has_defined_all_copy | all_defined_bar_copy | has_defined_all_copy.py:7:1:7:20 | all_defined_bar_copy | +| has_defined_all_copy | all_defined_foo_copy | has_defined_all_copy.py:6:1:6:20 | all_defined_foo_copy | +| has_defined_all_copy | enter | has_defined_all_copy.py:4:1:4:5 | enter | +| has_defined_all_copy | exit | has_defined_all_copy.py:11:1:11:4 | exit | +| has_defined_all_indirection | __file__ | has_defined_all_indirection.py:6:6:6:13 | __file__ | +| has_defined_all_indirection | all_defined_foo_copy | has_defined_all_copy.py:6:1:6:20 | all_defined_foo_copy | +| has_defined_all_indirection | enter | has_defined_all_indirection.py:2:1:2:5 | enter | +| has_defined_all_indirection | exit | has_defined_all_indirection.py:6:1:6:4 | exit | +| if_then_else | __file__ | if_then_else.py:16:6:16:13 | __file__ | +| if_then_else | enter | if_then_else.py:2:1:2:5 | enter | +| if_then_else | eval | if_then_else.py:11:8:11:11 | eval | +| if_then_else | exit | if_then_else.py:16:1:16:4 | exit | +| if_then_else | if_then_else_defined | if_then_else.py:7:5:7:24 | if_then_else_defined | +| if_then_else | if_then_else_defined | if_then_else.py:12:9:12:28 | if_then_else_defined | +| if_then_else | if_then_else_defined | if_then_else.py:14:9:14:28 | if_then_else_defined | +| if_then_else_refined | SOURCE | if_then_else_refined.py:11:11:11:16 | SOURCE | +| if_then_else_refined | SOURCE | if_then_else_refined.py:13:11:13:16 | SOURCE | +| if_then_else_refined | __file__ | if_then_else_refined.py:19:6:19:13 | __file__ | +| if_then_else_refined | check | if_then_else_refined.py:17:1:17:5 | check | +| if_then_else_refined | enter | if_then_else_refined.py:4:1:4:5 | enter | +| if_then_else_refined | eval | if_then_else_refined.py:10:4:10:7 | eval | +| if_then_else_refined | exit | if_then_else_refined.py:19:1:19:4 | exit | +| if_then_else_refined | globals | if_then_else_refined.py:17:24:17:30 | globals | +| if_then_else_refined | src | if_then_else_refined.py:17:19:17:21 | src | +| package.__init__ | __file__ | package/__init__.py:7:6:7:13 | __file__ | +| package.__init__ | attr_used_in_subpackage | package/__init__.py:4:1:4:23 | attr_used_in_subpackage | +| package.__init__ | enter | package/__init__.py:2:1:2:5 | enter | +| package.__init__ | exit | package/__init__.py:7:1:7:4 | exit | +| package.__init__ | package_attr | package/__init__.py:5:1:5:12 | package_attr | +| package.subpackage2.__init__ | __file__ | package/subpackage2/__init__.py:6:6:6:13 | __file__ | +| package.subpackage2.__init__ | enter | package/subpackage2/__init__.py:2:1:2:5 | enter | +| package.subpackage2.__init__ | exit | package/subpackage2/__init__.py:6:1:6:4 | exit | +| package.subpackage2.__init__ | subpackage2_attr | package/subpackage2/__init__.py:4:1:4:16 | subpackage2_attr | +| package.subpackage.__init__ | __file__ | package/subpackage/__init__.py:14:6:14:13 | __file__ | +| package.subpackage.__init__ | check | package/subpackage/__init__.py:12:1:12:5 | check | +| package.subpackage.__init__ | enter | package/subpackage/__init__.py:2:1:2:5 | enter | +| package.subpackage.__init__ | exit | package/subpackage/__init__.py:14:1:14:4 | exit | +| package.subpackage.__init__ | globals | package/subpackage/__init__.py:12:79:12:85 | globals | +| package.subpackage.__init__ | imported_attr | package/subpackage/__init__.py:7:16:7:55 | After ImportMember | +| package.subpackage.__init__ | imported_attr | package/subpackage/__init__.py:8:24:8:36 | imported_attr | +| package.subpackage.__init__ | irrelevant_attr | package/subpackage/__init__.py:11:24:11:38 | After ImportMember | +| package.subpackage.__init__ | irrelevant_attr | package/subpackage/__init__.py:11:24:11:38 | irrelevant_attr | +| package.subpackage.__init__ | submodule | package/subpackage/__init__.py:12:35:12:43 | submodule | +| package.subpackage.__init__ | subpackage_attr | package/subpackage/__init__.py:4:1:4:15 | subpackage_attr | +| package.subpackage.submodule | __file__ | package/subpackage/submodule.py:7:6:7:13 | __file__ | +| package.subpackage.submodule | enter | package/subpackage/submodule.py:2:1:2:5 | enter | +| package.subpackage.submodule | exit | package/subpackage/submodule.py:7:1:7:4 | exit | +| package.subpackage.submodule | irrelevant_attr | package/subpackage/submodule.py:5:1:5:15 | irrelevant_attr | +| package.subpackage.submodule | submodule_attr | package/subpackage/submodule.py:4:1:4:14 | submodule_attr | +| refined | SOURCE | refined.py:12:25:12:30 | SOURCE | +| refined | __file__ | refined.py:14:6:14:13 | __file__ | +| refined | check | refined.py:12:1:12:5 | check | +| refined | enter | refined.py:2:1:2:5 | enter | +| refined | exit | refined.py:14:1:14:4 | exit | +| refined | globals | refined.py:12:33:12:39 | globals | +| refined | object | refined.py:4:14:4:19 | object | +| simplistic_reexport | __file__ | simplistic_reexport.py:19:6:19:13 | __file__ | +| simplistic_reexport | bar_attr | simplistic_reexport.py:6:17:6:24 | After ImportMember | +| simplistic_reexport | bar_attr | simplistic_reexport.py:10:19:10:26 | bar_attr | +| simplistic_reexport | baz_attr | baz.py:4:1:4:8 | baz_attr | +| simplistic_reexport | baz_attr | simplistic_reexport.py:17:19:17:26 | baz_attr | +| simplistic_reexport | check | simplistic_reexport.py:17:1:17:5 | check | +| simplistic_reexport | enter | baz.py:2:1:2:5 | enter | +| simplistic_reexport | enter | simplistic_reexport.py:4:1:4:5 | enter | +| simplistic_reexport | exit | baz.py:6:1:6:4 | exit | +| simplistic_reexport | exit | simplistic_reexport.py:19:1:19:4 | exit | +| simplistic_reexport | globals | simplistic_reexport.py:17:44:17:50 | globals | diff --git a/python/ql/test/experimental/import-resolution/importflow.ql b/python/ql/test/experimental/import-resolution/importflow.ql index a3e20123fc7..4fbc782abf5 100644 --- a/python/ql/test/experimental/import-resolution/importflow.ql +++ b/python/ql/test/experimental/import-resolution/importflow.ql @@ -3,6 +3,7 @@ import semmle.python.dataflow.new.DataFlow import semmle.python.ApiGraphs import utils.test.InlineExpectationsTest import semmle.python.dataflow.new.internal.ImportResolution +private import semmle.python.controlflow.internal.Cfg as Cfg /** A string that appears on the right hand side of an assignment. */ private class SourceString extends DataFlow::Node { @@ -45,13 +46,15 @@ private class VersionGuardedNode extends DataFlow::Node { VersionGuardedNode() { version in [2, 3] and - exists(If parent, CompareNode c | parent.getBody().contains(this.asExpr()) | + exists(If parent, Cfg::CompareNode c, Cfg::ControlFlowNode litCfg | + parent.getBody().contains(this.asExpr()) and + litCfg.getNode() = any(IntegerLiteral lit | lit.getValue() = version) + | c.operands(API::moduleImport("sys") .getMember("version_info") .getASubscript() .asSource() - .asCfgNode(), any(Eq eq), - any(IntegerLiteral lit | lit.getValue() = version).getAFlowNode()) + .asCfgNode(), any(Eq eq), litCfg) ) } diff --git a/python/ql/test/library-tests/ControlFlow/PointsToSupport/UseFromDefinition.ql b/python/ql/test/library-tests/ControlFlow/PointsToSupport/UseFromDefinition.ql index 8b52244478f..6173331a2dd 100644 --- a/python/ql/test/library-tests/ControlFlow/PointsToSupport/UseFromDefinition.ql +++ b/python/ql/test/library-tests/ControlFlow/PointsToSupport/UseFromDefinition.ql @@ -9,7 +9,7 @@ Expr assignedValue(Name n) { from Name def, DefinitionNode d where - d = def.getAFlowNode() and + d.getNode() = def and exists(assignedValue(def)) and not d.getValue().getNode() = assignedValue(def) select def.toString(), assignedValue(def) diff --git a/python/ql/test/library-tests/ControlFlow/splitting/NodeCount.ql b/python/ql/test/library-tests/ControlFlow/splitting/NodeCount.ql index c51707a65ff..e41f73f5b88 100644 --- a/python/ql/test/library-tests/ControlFlow/splitting/NodeCount.ql +++ b/python/ql/test/library-tests/ControlFlow/splitting/NodeCount.ql @@ -8,4 +8,4 @@ where not a instanceof ExprStmt and a.getScope() = s and s instanceof Function -select a.getLocation().getStartLine(), s.getName(), a, count(a.getAFlowNode()) +select a.getLocation().getStartLine(), s.getName(), a, count(ControlFlowNode n | n.getNode() = a) diff --git a/python/ql/test/library-tests/dataflow/tainttracking/TestTaintLib.qll b/python/ql/test/library-tests/dataflow/tainttracking/TestTaintLib.qll index f46f08aa509..cb014631208 100644 --- a/python/ql/test/library-tests/dataflow/tainttracking/TestTaintLib.qll +++ b/python/ql/test/library-tests/dataflow/tainttracking/TestTaintLib.qll @@ -44,7 +44,7 @@ query predicate test_taint(string arg_location, string test_res, string scope_na // TODO: Replace with `hasFlowToExpr` once that is working if TestTaintTrackingFlow::flowTo(any(DataFlow::Node n | - n.(DataFlow::CfgNode).getNode() = arg.getAFlowNode() + n.(DataFlow::CfgNode).getNode().getNode() = arg )) then has_taint = true else has_taint = false