From 47023c20627520d37fe2ed361546da86fb2636e0 Mon Sep 17 00:00:00 2001 From: yoff Date: Thu, 20 Aug 2026 11:11:44 +0200 Subject: [PATCH] Python: test closure instance cross-talk Add an inline type-tracking regression for two closures created from the same wrapper AST with different captured callables. Keep positive controls for the sensitive callable and ordinary captured data while marking the safe closure result as the current spurious flow. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../dataflow/typetracking/test.py | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/python/ql/test/library-tests/dataflow/typetracking/test.py b/python/ql/test/library-tests/dataflow/typetracking/test.py index 19d5bd76f5fa..1aee5b67d4f5 100644 --- a/python/ql/test/library-tests/dataflow/typetracking/test.py +++ b/python/ql/test/library-tests/dataflow/typetracking/test.py @@ -107,6 +107,28 @@ def use_funcs_with_decorators(): x = get_tracked2() # $ tracked y = unrelated_func() # $ SPURIOUS: tracked +# A decorator factory creates a distinct closure each time it is called. The captured +# callable and data therefore belong to that closure instance, even though every +# instance comes from the same wrapper AST. +def make_capturing_wrapper(func, captured): # $ tracked + def wrapper(): + print(captured) # $ tracked + return func() # $ tracked + return wrapper + +def closure_sensitive_func(): + return tracked # $ tracked + +def closure_safe_func(): + return "safe" + +closure_sensitive = make_capturing_wrapper(closure_sensitive_func, tracked) # $ tracked +closure_safe = make_capturing_wrapper(closure_safe_func, "safe") + +def use_capturing_wrappers(): + sensitive = closure_sensitive() # $ tracked + safe = closure_safe() # $ SPURIOUS: tracked + # ------------------------------------------------------------------------------ def expects_int(x): # $ int