From f6eae726c545ff2a9db6e073a18ab8ffc69f0eb5 Mon Sep 17 00:00:00 2001 From: Brittany Reynoso Date: Fri, 16 Oct 2026 20:05:23 -0400 Subject: [PATCH] gh-159538: Fix deep chain leak in test_deeply_dotted_name (GH-159576) test_deeply_dotted_name() builds a 10,000-deep chain of lazy import placeholders in a thread with a 256 KiB C stack. Freeing the chain there defers most deallocations to the trashcan, which only drains them once the stack margin recovers. With a stack that small the margin never does, so the deferred objects were leaked when the thread exited, which -R reports as a reference leak on platforms with larger frames such as PPC64LE. Clear the namespace in a cleanup, which runs on the main thread. (cherry picked from commit c84d4b5953f18871ef37b2a95c93de84c66950ef) Co-authored-by: Brittany Reynoso --- Lib/test/test_lazy_import/__init__.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Lib/test/test_lazy_import/__init__.py b/Lib/test/test_lazy_import/__init__.py index a4adf50899a760..59ff1dee53ba50 100644 --- a/Lib/test/test_lazy_import/__init__.py +++ b/Lib/test/test_lazy_import/__init__.py @@ -325,6 +325,9 @@ def test_deeply_dotted_name(self): m.m = m ns = {"__builtins__": {"__lazy_import__": __lazy_import__, "__import__": lambda *args: m}} + # Free the chain on the main thread: a thread with a small C stack + # postpones deep deallocations and never gets back to them. + self.addCleanup(ns.clear) exec("lazy import " + ".".join(["m"] * 10_000) + " as x", ns) with contextlib.suppress(RecursionError): ns["x"].resolve()