From: Kefu Chai Date: Sat, 25 Apr 2026 09:36:37 +0000 (+0800) Subject: qa/lsan.supp: suppress CPython 3.10 interpreter shutdown leaks X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=42b648ebf206474d439d1e9089e0c95cecc06608;p=ceph.git qa/lsan.supp: suppress CPython 3.10 interpreter shutdown leaks When building with ASan, it reports leaks in five tests that exercise CPython 3.10 either as an external process (bin/ceph) or embedded in unittests: #36 smoke.sh (timeout, via bin/ceph) #205 unittest_mgr_pyformatter (libpython3.10.so embedded) #206 unittest_mgr_pyutil (libpython3.10.so embedded) #210 mgr-dashboard-smoke.sh (via bin/ceph) #225 safe-to-destroy.sh (via bin/ceph) A representative stack from #210: Direct leak of 25846 byte(s) in 28 object(s) allocated from: #0 malloc #1 /usr/bin/python3.10+0x16d7be Direct leak of 20456 byte(s) in 29 object(s): #1 PyDict_Copy /usr/bin/python3.10+0x16ae06 Direct leak of 8456 byte(s) in 14 object(s): #1 _PyObject_GC_NewVar /usr/bin/python3.10+0x14fc57 The unittests show the same shape against /lib/.../libpython3.10.so. These are CPython 3.10 runtime artefacts, not Ceph bugs. In CPython 3.10, Py_FinalizeEx() leaves a set of interpreter-internal allocations (module namespace dict copies, GC-tracked variable-size containers, type-method caches, interned strings) heap-allocated until process exit; the OS reclaims them. PEP 683 (Immortal Objects, accepted for Python 3.12) extends pylifecycle.c::finalize_modules() to deallocate these remaining objects during runtime shutdown: "During runtime shutdown, the strategy will be to first let the runtime try to do its best effort of deallocating these instances normally. Most of the module deallocation will now be handled by pylifecycle.c:finalize_modules() where we clean up the remaining modules as best as we can." -- PEP 683, https://peps.python.org/pep-0683/ The qa/lsan.supp file has carried the empirical note "python3.12 doesn't leak anything" since the file was introduced (commit 8c099a534044bf, "asan: add qa/lsan.supp for leak sanitizer suppressions", Mar 2023). An empirical reproduction with a minimal Py_Initialize()/Py_FinalizeEx() program built against Python 3.13 under -fsanitize=address reports zero leaks; the same minimal test against Python 3.10 (CI environment) reports the leaks shown above. Add three suppressions to qa/lsan.supp's existing 3.9-3.11 block: - leak:^PyDict_Copy and leak:^_PyObject_GC_NewVar match the two exported CPython functions visible in the leak stacks. - leak:python3.10 substring-matches the module path in the stack frame, catching unsymbolised offsets in both the /usr/bin/python3.10 binary and the libpython3.10.so.1.0 shared object. Mirrors the existing leak:libsqlite3.so pattern earlier in the file. The whole block (including the existing PyMem_Malloc entry above) can be removed once CI runs on Python >= 3.12. Signed-off-by: Kefu Chai --- diff --git a/qa/lsan.supp b/qa/lsan.supp index 9418cc5de214..329389e5b5f3 100644 --- a/qa/lsan.supp +++ b/qa/lsan.supp @@ -27,6 +27,16 @@ leak:^PyMem_Calloc leak:^PyUnicode_New # python3.9, 3.10, 3.11 leak:^PyMem_Malloc +leak:^PyDict_Copy +leak:^_PyObject_GC_NewVar +# Catch unsymbolised interpreter frames in both the standalone +# /usr/bin/python3.10 binary (used by the bin/ceph wrapper) and the +# /lib/.../libpython3.10.so.1.0 embedded by C++ unittests such as +# unittest_mgr_pyformatter / unittest_mgr_pyutil. Not all CPython +# 3.10 internal helpers are exported in .dynsym, so function-name +# matches above don't cover everything; this substring-matches the +# module path in the stack frame. Remove when CI moves to >= 3.12. +leak:python3.10 # python3.12 doesn't leak anything # python3.13 leak:^PyModule_ExecDef