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 <k.chai@proxmox.com>