]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
qa/lsan.supp: suppress CPython 3.10 interpreter shutdown leaks 68615/head
authorKefu Chai <k.chai@proxmox.com>
Sat, 25 Apr 2026 09:36:37 +0000 (17:36 +0800)
committerKefu Chai <k.chai@proxmox.com>
Sat, 25 Apr 2026 13:44:44 +0000 (21:44 +0800)
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>
qa/lsan.supp

index 9418cc5de214474619b30023fbd453202fb1c9c7..329389e5b5f3c239525eeaa9a6e60f8d506be6f3 100644 (file)
@@ -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