python / python/cpython

Memory leak with `threading.local` when tracing is active

Open
#140,798 1 comment 0 reactions 1 assignee View on GitHub

@efimov-mikhail is already working on this.

Since Oct 31, 2025.

3.13 3.14 3.15 extension-modules interpreter-core type-bug
Dominant language
Python
Stars
77.2k
Forks
35.9k
PR merge metrics
PR metrics pending

Description

Bug report

Bug description:
import threading

events = []

def tracer(frame, event, arg):
    try:
        func_name = frame.f_code.co_name
    except Exception:
        func_name = 1.7976931348623157e308
    events.append((threading.current_thread().name, event, func_name))
    return tracer

def callback():
    for _ in range(3):
        try:
            next(callback.g)
        except StopIteration:
            break

callback.g = iter(range(3))

old_threading_trace = getattr(threading, "_trace_hook", Ellipsis)
try:
    threading.settrace(tracer)
    t = threading.Thread(target=callback, name="child-thread")
    t.start()
    t.join()
finally:
    threading.settrace(old_threading_trace)
=================================================================
==1247377==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 24 byte(s) in 1 object(s) allocated from:
    #0 0x79ebcdce99c7 in malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69
    #1 0x6021cf14b8fe in _PyObject_MallocWithType ../Include/internal/pycore_object_alloc.h:46
    #2 0x6021cf14b8fe in _PyType_AllocNoTrack ../Objects/typeobject.c:2505
    #3 0x6021cf14bb64 in PyType_GenericAlloc ../Objects/typeobject.c:2536
    #4 0x6021cf6a925f in create_localdummies ../Modules/_threadmodule.c:1617
    #5 0x6021cf6a925f in _ldict ../Modules/_threadmodule.c:1694
    #6 0x6021cf6a974b in local_setattro ../Modules/_threadmodule.c:1751
    #7 0x6021cf0c4421 in PyObject_SetAttr ../Objects/object.c:1476
    #8 0x6021cee5f3c8 in _PyEval_EvalFrameDefault ../Python/generated_cases.c.h:10750
    #9 0x6021cf324785 in _PyEval_EvalFrame ../Include/internal/pycore_ceval.h:121
    #10 0x6021cf324785 in _PyEval_Vector ../Python/ceval.c:2005
    #11 0x6021cf516c34 in _PyObject_VectorcallTstate ../Include/internal/pycore_call.h:169
    #12 0x6021cf516c34 in call_trampoline ../Python/sysmodule.c:1080
    #13 0x6021cf516c34 in trace_trampoline ../Python/sysmodule.c:1116
    #14 0x6021cf419ff9 in _Py_call_instrumentation_line ../Python/instrumentation.c:1349
    #15 0x6021cee66880 in _PyEval_EvalFrameDefault ../Python/generated_cases.c.h:7024
    #16 0x6021cf324785 in _PyEval_EvalFrame ../Include/internal/pycore_ceval.h:121
    #17 0x6021cf324785 in _PyEval_Vector ../Python/ceval.c:2005
    #18 0x6021cefa39bd in _PyObject_VectorcallTstate ../Include/internal/pycore_call.h:169
    #19 0x6021cefa39bd in PyObject_CallOneArg ../Objects/call.c:395
    #20 0x6021cf152065 in call_unbound_noarg ../Objects/typeobject.c:3041
    #21 0x6021cf152065 in slot_tp_finalize ../Objects/typeobject.c:10879
    #22 0x6021cf0c3e50 in PyObject_CallFinalizer ../Objects/object.c:585
    #23 0x6021cf0c3e50 in PyObject_CallFinalizerFromDealloc ../Objects/object.c:603
    #24 0x6021cf141200 in subtype_dealloc ../Objects/typeobject.c:2775
    #25 0x6021cf0c1ef1 in _Py_Dealloc ../Objects/object.c:3200
    #26 0x6021cf0721f0 in Py_DECREF ../Include/refcount.h:420
    #27 0x6021cf0721f0 in Py_XDECREF ../Include/refcount.h:513
    #28 0x6021cf0721f0 in dictkeys_decref ../Objects/dictobject.c:462
    #29 0x6021cf0721f0 in dictkeys_decref ../Objects/dictobject.c:446
    #30 0x6021cf0721f0 in dict_dealloc ../Objects/dictobject.c:3354
    #31 0x6021cf0721f0 in dict_dealloc ../Objects/dictobject.c:3328
    #32 0x6021cf0c1ef1 in _Py_Dealloc ../Objects/object.c:3200
    #33 0x6021cf08570b in Py_DECREF ../Include/refcount.h:420
    #34 0x6021cf08570b in _PyDict_Pop_KnownHash ../Objects/dictobject.c:3115
    #35 0x6021cf08570b in pop_lock_held ../Objects/dictobject.c:3149
    #36 0x6021cf08570b in PyDict_Pop ../Objects/dictobject.c:3157
    #37 0x6021cf6a2bdc in clear_locals ../Modules/_threadmodule.c:1860
    #38 0x6021cefa39bd in _PyObject_VectorcallTstate ../Include/internal/pycore_call.h:169
    #39 0x6021cefa39bd in PyObject_CallOneArg ../Objects/call.c:395
    #40 0x6021cf254d4f in handle_callback ../Objects/weakrefobject.c:989
    #41 0x6021cf254d4f in PyObject_ClearWeakRefs ../Objects/weakrefobject.c:1080
    #42 0x6021cf6a2ce4 in localdummy_dealloc ../Modules/_threadmodule.c:1421
    #43 0x6021cf0c1ef1 in _Py_Dealloc ../Objects/object.c:3200
    #44 0x6021cf4db134 in Py_DECREF ../Include/refcount.h:420
    #45 0x6021cf4db134 in PyThreadState_Clear ../Python/pystate.c:1673
    #46 0x6021cf6aa15a in thread_run ../Modules/_threadmodule.c:404
    #47 0x6021cf5260af in pythread_wrapper ../Python/thread_pthread.h:234
    #48 0x79ebcdc4aa41 in asan_thread_start ../../../../src/libsanitizer/asan/asan_interceptors.cpp:234
    #49 0x79ebcd98daa3  (/lib/x86_64-linux-gnu/libc.so.6+0x9caa3) (BuildId: 282c2c16e7b6600b0b22ea0c99010d2795752b5f)

Direct leak of 24 byte(s) in 1 object(s) allocated from:
    #0 0x79ebcdce99c7 in malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69
    #1 0x6021cf14b8fe in _PyObject_MallocWithType ../Include/internal/pycore_object_alloc.h:46
    #2 0x6021cf14b8fe in _PyType_AllocNoTrack ../Objects/typeobject.c:2505
    #3 0x6021cf14bb64 in PyType_GenericAlloc ../Objects/typeobject.c:2536
    #4 0x6021cf6a9210 in create_localdummies ../Modules/_threadmodule.c:1612
    #5 0x6021cf6a9210 in _ldict ../Modules/_threadmodule.c:1694
    #6 0x6021cf6a974b in local_setattro ../Modules/_threadmodule.c:1751
    #7 0x6021cf0c4421 in PyObject_SetAttr ../Objects/object.c:1476
    #8 0x6021cee5f3c8 in _PyEval_EvalFrameDefault ../Python/generated_cases.c.h:10750
    #9 0x6021cf324785 in _PyEval_EvalFrame ../Include/internal/pycore_ceval.h:121
    #10 0x6021cf324785 in _PyEval_Vector ../Python/ceval.c:2005
    #11 0x6021cf516c34 in _PyObject_VectorcallTstate ../Include/internal/pycore_call.h:169
    #12 0x6021cf516c34 in call_trampoline ../Python/sysmodule.c:1080
    #13 0x6021cf516c34 in trace_trampoline ../Python/sysmodule.c:1116
    #14 0x6021cf419ff9 in _Py_call_instrumentation_line ../Python/instrumentation.c:1349
    #15 0x6021cee66880 in _PyEval_EvalFrameDefault ../Python/generated_cases.c.h:7024
    #16 0x6021cf324785 in _PyEval_EvalFrame ../Include/internal/pycore_ceval.h:121
    #17 0x6021cf324785 in _PyEval_Vector ../Python/ceval.c:2005
    #18 0x6021cefa39bd in _PyObject_VectorcallTstate ../Include/internal/pycore_call.h:169
    #19 0x6021cefa39bd in PyObject_CallOneArg ../Objects/call.c:395
    #20 0x6021cf152065 in call_unbound_noarg ../Objects/typeobject.c:3041
    #21 0x6021cf152065 in slot_tp_finalize ../Objects/typeobject.c:10879
    #22 0x6021cf0c3e50 in PyObject_CallFinalizer ../Objects/object.c:585
    #23 0x6021cf0c3e50 in PyObject_CallFinalizerFromDealloc ../Objects/object.c:603
    #24 0x6021cf141200 in subtype_dealloc ../Objects/typeobject.c:2775
    #25 0x6021cf0c1ef1 in _Py_Dealloc ../Objects/object.c:3200
    #26 0x6021cf0721f0 in Py_DECREF ../Include/refcount.h:420
    #27 0x6021cf0721f0 in Py_XDECREF ../Include/refcount.h:513
    #28 0x6021cf0721f0 in dictkeys_decref ../Objects/dictobject.c:462
    #29 0x6021cf0721f0 in dictkeys_decref ../Objects/dictobject.c:446
    #30 0x6021cf0721f0 in dict_dealloc ../Objects/dictobject.c:3354
    #31 0x6021cf0721f0 in dict_dealloc ../Objects/dictobject.c:3328
    #32 0x6021cf0c1ef1 in _Py_Dealloc ../Objects/object.c:3200
    #33 0x6021cf08570b in Py_DECREF ../Include/refcount.h:420
    #34 0x6021cf08570b in _PyDict_Pop_KnownHash ../Objects/dictobject.c:3115
    #35 0x6021cf08570b in pop_lock_held ../Objects/dictobject.c:3149
    #36 0x6021cf08570b in PyDict_Pop ../Objects/dictobject.c:3157
    #37 0x6021cf6a2bdc in clear_locals ../Modules/_threadmodule.c:1860
    #38 0x6021cefa39bd in _PyObject_VectorcallTstate ../Include/internal/pycore_call.h:169
    #39 0x6021cefa39bd in PyObject_CallOneArg ../Objects/call.c:395
    #40 0x6021cf254d4f in handle_callback ../Objects/weakrefobject.c:989
    #41 0x6021cf254d4f in PyObject_ClearWeakRefs ../Objects/weakrefobject.c:1080
    #42 0x6021cf6a2ce4 in localdummy_dealloc ../Modules/_threadmodule.c:1421
    #43 0x6021cf0c1ef1 in _Py_Dealloc ../Objects/object.c:3200
    #44 0x6021cf4db134 in Py_DECREF ../Include/refcount.h:420
    #45 0x6021cf4db134 in PyThreadState_Clear ../Python/pystate.c:1673
    #46 0x6021cf6aa15a in thread_run ../Modules/_threadmodule.c:404
    #47 0x6021cf5260af in pythread_wrapper ../Python/thread_pthread.h:234
    #48 0x79ebcdc4aa41 in asan_thread_start ../../../../src/libsanitizer/asan/asan_interceptors.cpp:234
    #49 0x79ebcd98daa3  (/lib/x86_64-linux-gnu/libc.so.6+0x9caa3) (BuildId: 282c2c16e7b6600b0b22ea0c99010d2795752b5f)

SUMMARY: AddressSanitizer: 48 byte(s) leaked in 2 allocation(s).
CPython versions tested on:

CPython main branch

Operating systems tested on:

Linux

Linked PRs
  • gh-140836

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.