From 183c61973bf81fc918b07ef55fc376db1763c7e1 Mon Sep 17 00:00:00 2001 From: yoff Date: Wed, 19 Aug 2026 13:05:03 +0200 Subject: [PATCH 1/2] Python: test shared CFG exception reachability Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../ExceptionReachabilityTest.expected | 0 .../ExceptionReachabilityTest.ql | 29 +++++++++++++++++++ .../ControlFlow/shared-cfg-exceptions/test.py | 12 ++++++++ 3 files changed, 41 insertions(+) create mode 100644 python/ql/test/library-tests/ControlFlow/shared-cfg-exceptions/ExceptionReachabilityTest.expected create mode 100644 python/ql/test/library-tests/ControlFlow/shared-cfg-exceptions/ExceptionReachabilityTest.ql create mode 100644 python/ql/test/library-tests/ControlFlow/shared-cfg-exceptions/test.py diff --git a/python/ql/test/library-tests/ControlFlow/shared-cfg-exceptions/ExceptionReachabilityTest.expected b/python/ql/test/library-tests/ControlFlow/shared-cfg-exceptions/ExceptionReachabilityTest.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/ql/test/library-tests/ControlFlow/shared-cfg-exceptions/ExceptionReachabilityTest.ql b/python/ql/test/library-tests/ControlFlow/shared-cfg-exceptions/ExceptionReachabilityTest.ql new file mode 100644 index 000000000000..c98e73336676 --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/shared-cfg-exceptions/ExceptionReachabilityTest.ql @@ -0,0 +1,29 @@ +/** + * Inline-expectations test for exception-handler reachability in the shared CFG. + */ + +import python +import semmle.python.controlflow.internal.AstNodeImpl as CfgImpl +import semmle.python.controlflow.internal.Cfg as Cfg +import utils.test.InlineExpectationsTest + +module ExceptionReachabilityTest implements TestSig { + string getARelevantTag() { result = "exception-handler" } + + predicate hasActualResult(Location location, string element, string tag, string value) { + exists( + Expr source, ExceptStmt handler, Cfg::ControlFlowNode sourceCfg, + Cfg::ControlFlowNode handlerEntry + | + sourceCfg.getNode() = source and + handlerEntry = sourceCfg.getAnExceptionalSuccessor() and + CfgImpl::astNodeToPyNode(handlerEntry.getAstNode()) = handler and + location = source.getLocation() and + element = source.toString() and + tag = "exception-handler" and + value = handler.getType().toString() + ) + } +} + +import MakeTest diff --git a/python/ql/test/library-tests/ControlFlow/shared-cfg-exceptions/test.py b/python/ql/test/library-tests/ControlFlow/shared-cfg-exceptions/test.py new file mode 100644 index 000000000000..3a0cbb23abaf --- /dev/null +++ b/python/ql/test/library-tests/ControlFlow/shared-cfg-exceptions/test.py @@ -0,0 +1,12 @@ +def generator(): + try: + yield # $ MISSING: exception-handler=GeneratorExit + except GeneratorExit: + return + + +def load_module(): + try: + import unavailable_module # $ MISSING: exception-handler=ImportError + except ImportError: + return None From a93d631037cfe16fea2eefd57e5f0090b1a05963 Mon Sep 17 00:00:00 2001 From: yoff Date: Wed, 19 Aug 2026 13:05:33 +0200 Subject: [PATCH 2/2] Python: wire leaf exceptions to catch entries Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll | 2 +- .../library-tests/ControlFlow/shared-cfg-exceptions/test.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll b/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll index 78218f489215..e4666b74d172 100644 --- a/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll +++ b/python/ql/lib/semmle/python/controlflow/internal/AstNodeImpl.qll @@ -1724,7 +1724,7 @@ private module Input implements InputSig1, InputSig2 { always = true or mayThrow(ast) and - n.isIn(ast) and + n.injects(ast) and c.asSimpleAbruptCompletion() instanceof ExceptionSuccessor and always = false } diff --git a/python/ql/test/library-tests/ControlFlow/shared-cfg-exceptions/test.py b/python/ql/test/library-tests/ControlFlow/shared-cfg-exceptions/test.py index 3a0cbb23abaf..0e55eba97407 100644 --- a/python/ql/test/library-tests/ControlFlow/shared-cfg-exceptions/test.py +++ b/python/ql/test/library-tests/ControlFlow/shared-cfg-exceptions/test.py @@ -1,12 +1,12 @@ def generator(): try: - yield # $ MISSING: exception-handler=GeneratorExit + yield # $ exception-handler=GeneratorExit except GeneratorExit: return def load_module(): try: - import unavailable_module # $ MISSING: exception-handler=ImportError + import unavailable_module # $ exception-handler=ImportError except ImportError: return None