Sitelet https://github.com/python/cpython/issues/157176
Skip to content

Memory leak on interpreter shutdown when reference cycle exists between structseq type and its instance #157176

Description

@ashm-dev

Bug report

Bug description:

Environment

  • Commit/Branch: main (rev: 2d9fb5f2f70b18ce9e5d9f7f76fd5ef3f118d838)
  • OS: Linux
  • Build flags:
    CC=clang CXX=clang++ LDFLAGS='-fuse-ld=lld' ./configure --with-address-sanitizer --with-undefined-behavior-sanitizer --with-pydebug && make -j$(nproc)

Steps to reproduce

Run:

./python -c "import time; t = time.gmtime(); type(t).refcyle = t;"

Note: Explicitly breaking the cycle avoids the leak:

./python -c "import time; t = time.gmtime(); type(t).refcyle = t; del type(t).refcyle"

Expected behavior

The garbage collector or interpreter finalization breaks the reference cycle during shutdown; no memory leaks reported by LeakSanitizer.

Actual behavior

LeakSanitizer detects memory leaks (indirect leaks of the type, its dict, descriptors, and the instance):

=================================================================
==1164172==ERROR: LeakSanitizer: detected memory leaks

Indirect leak of 1472 byte(s) in 1 object(s) allocated from:
    #0 0x55571ba2f651 in malloc
    #1 0x55571c0c8db7 in _PyMem_DebugRawAlloc Objects/obmalloc.c:3103:24
    #2 0x55571c130728 in _PyObject_MallocWithType Include/internal/pycore_object_alloc.h:46:17
    #3 0x55571c130728 in _PyType_AllocNoTrack Objects/typeobject.c:2495:19
    #4 0x55571c13040d in PyType_GenericAlloc Objects/typeobject.c:2526:21
    #5 0x55571c1357f9 in type_from_slots_or_spec Objects/typeobject.c:5591:30
    #6 0x55571c1148ec in _PyStructSequence_NewType Objects/structseq.c:780:28
    #7 0x55571ca6ea5c in time_exec Modules/timemodule.c:2113:31
...
Indirect leak of 176 byte(s) in 1 object(s) allocated from:
    #0 0x55571ba2f651 in malloc
    #1 0x55571c0c8db7 in _PyMem_DebugRawAlloc Objects/obmalloc.c:3103:24
    #2 0x55571c5d4028 in _PyObject_MallocWithType Include/internal/pycore_object_alloc.h:46:17
    #3 0x55571c5d4028 in gc_alloc Python/gc.c:2013:17
    #4 0x55571c5d4440 in _PyObject_GC_NewVar Python/gc.c:2055:25
    #5 0x55571c110247 in PyStructSequence_New Objects/structseq.c:77:11
    #6 0x55571ca69e1d in tmtotuple Modules/timemodule.c:463:19
    #7 0x55571ca67616 in time_gmtime Modules/timemodule.c:541:12
...
SUMMARY: AddressSanitizer: 6946 byte(s) leaked in 50 allocation(s).

Full LeakSanitizer output - logs.txt

CPython versions tested on:

CPython main branch

Operating systems tested on:

Linux

Linked PRs

Activity

  1. sergey-miryanov commented on Sep 8, 2026

    @sergey-miryanov
    Contributor

    Does this affect 3.14, 3.15 branches?

  2. ashm-dev commented on Sep 8, 2026

    @ashm-dev
    ContributorAuthor

    @sergey-miryanov It reproduces on 3.15 and 3.14, but 3.13, 3.12, 3.11, and 3.10 failed with ASan/UBSan errors during the build.

  3. added
    3.14bugs and security fixes
    3.15pre-release feature fixes, bugs and security fixes
    3.16new features, bugs and security fixes
    on Sep 8, 2026
  4. methane commented on Sep 15, 2026

    @methane
    Member

    How about adding Py_TPFLAGS_IMMUTABLETYPE to struct_time?

  5. vstinner commented on Oct 5, 2026

    @vstinner
    Member

    How about adding Py_TPFLAGS_IMMUTABLETYPE to struct_time?

    IMO it's perfectly reasonable to make the type immutable. I don't see why someone would want to modify the type.

    -    state->struct_time_type = PyStructSequence_NewType(&struct_time_type_desc);
    +    state->struct_time_type = _PyStructSequence_NewType(&struct_time_type_desc, Py_TPFLAGS_IMMUTABLETYPE);

    I tested this change and it works as expected.

  6. added 2 commits that reference this issue on Oct 7, 2026
  7. vstinner commented on Oct 7, 2026

    @vstinner
    Member

    type(time.gmtime()) has been made immutable, so it's no longer possible to create circular dependencies:

    $ ./python -c "import time; t = time.gmtime(); type(t).refcyle = t;"
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
        import time; t = time.gmtime(); type(t).refcyle = t;
                                        ^^^^^^^^^^^^^^^
    TypeError: cannot set 'refcyle' attribute of immutable type 'time.struct_time'
    

    I don't think that this issue is important enough to justify a backport. Making a type immutable is a backward incompatible change, so it's only done in Python 3.16 (main branch).

    I close the issue.

  8. added a commit that references this issue on Oct 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.14bugs and security fixes3.15pre-release feature fixes, bugs and security fixes3.16new features, bugs and security fixestype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions