Skip to content

mimalloc thread metadata leak #151065

Closed
Closed

Description

@lunixbochs

Bug report

Bug description:

Summary

This issue is in mi_thread_data_zalloc(), triaged on commit 57d4446 by Xint Code.

The function writes td->memid = memid; and then, if !is_zero, zeroes the entire mi_thread_data_t via _mi_memzero_aligned(td, sizeof(*td)), which clears td->memid (cpython/Objects/mimalloc/init.c:227-235).

Later frees use td->memid to decide how to return memory to the OS: _mi_os_free(tdfree, sizeof(mi_thread_data_t), tdfree->memid, ...) (cpython/Objects/mimalloc/init.c:251) and in cache collection _mi_os_free(td, sizeof(mi_thread_data_t), td->memid, ...) (cpython/Objects/mimalloc/init.c:261).

If memid was zeroed, _mi_os_free_ex treats it as MI_MEM_NONE and does nothing (cpython/Objects/mimalloc/os.c:159-183), leaking the thread metadata. The enum shows MI_MEM_NONE is zero (cpython/Include/internal/mimalloc/mimalloc/types.h:425-460).

Conditions

Pre-conditions:

  • CPython built with mimalloc support (WITH_MIMALLOC) and selected at runtime (e.g., PYTHONMALLOC=mimalloc), or built with Py_GIL_DISABLED which uses mimalloc by default (cpython/Include/internal/pycore_pymem_init.h:21-38, cpython/Objects/obmalloc.c:786-793).
  • Application creates threads that perform allocations, invoking mimalloc's per-thread initialization (cpython/Objects/mimalloc/init.c:267-286).

Data flow:

  1. Thread A starts; mi_thread_data_zalloc allocates td from the OS, sets td->memid = memid, with is_zero = memid.initially_zero (likely true) and returns without zeroing (cpython/Objects/mimalloc/init.c:215-231).
  2. Thread A ends; mi_thread_data_free inserts td into the td_cache (cpython/Objects/mimalloc/init.c:239-247).
  3. Thread B starts; mi_thread_data_zalloc fetches td from td_cache with is_zero still false and zeroes the entire struct, clearing td->memid (cpython/Objects/mimalloc/init.c:200-211, cpython/Objects/mimalloc/init.c:233-235).
  4. Thread B ends; if td_cache is full, mi_thread_data_free attempts direct free: _mi_os_free(tdfree, sizeof(mi_thread_data_t), tdfree->memid, ...) with tdfree->memid == MI_MEM_NONE, so _mi_os_free_ex no-ops (cpython/Objects/mimalloc/init.c:239-251, cpython/Objects/mimalloc/os.c:159-183), leaking td.
  5. Alternatively, if kept cached, at process shutdown mi_process_done -> mi_collect(true) -> _mi_thread_data_collect tries to free cached entries with a zeroed memid, again leaking (cpython/Objects/mimalloc/init.c:595-612, cpython/Objects/mimalloc/heap.c:178-182, cpython/Objects/mimalloc/init.c:254-265, cpython/Objects/mimalloc/os.c:159-183).

Reproduction

If you run 81.py with PYTHONMALLOC=mimalloc (or a free-threaded build), it shows rss growth due to the leak.
If you run with PYTHONMALLOC=malloc, there is no rss growth shown.

Script: 81.py

% PYTHONMALLOC=malloc python3.14 81.py
PYTHONMALLOC=malloc
batches=300 width=128 total_threads=38400
start_rss=20.8 MiB
batch=  50 rss=25.6 MiB delta=4.8 MiB
batch= 100 rss=25.6 MiB delta=4.9 MiB
batch= 150 rss=25.7 MiB delta=5.0 MiB
batch= 200 rss=25.7 MiB delta=5.0 MiB
batch= 250 rss=25.7 MiB delta=5.0 MiB
batch= 300 rss=25.7 MiB delta=5.0 MiB
done

% PYTHONMALLOC=mimalloc python3.14 81.py
PYTHONMALLOC=mimalloc
batches=300 width=128 total_threads=38400
start_rss=19.7 MiB
batch=  50 rss=41.3 MiB delta=21.6 MiB
batch= 100 rss=42.7 MiB delta=23.1 MiB
batch= 150 rss=43.9 MiB delta=24.2 MiB
batch= 200 rss=45.1 MiB delta=25.4 MiB
batch= 250 rss=46.2 MiB delta=26.6 MiB
batch= 300 rss=47.4 MiB delta=27.8 MiB
done

CPython versions tested on:

3.14

Operating systems tested on:

macOS

Linked PRs

Activity

  1. ZeroIntensity commented on Jun 8, 2026

    @ZeroIntensity
    Member

    Looks like an upstream issue in mimalloc; see microsoft/mimalloc#748. Let's move the discussion over there.

  2. ZeroIntensity commented on Jun 8, 2026

    @ZeroIntensity
    Member

    Ah, wait, it seems they already fixed it and forgot to close the issue. We just need to cherry-pick the fix.

  3. added 4 commits that reference this issue on Jun 11, 2026
  4. added a commit that references this issue on Jun 17, 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

    interpreter-core(Objects, Python, Grammar, and Parser dirs)type-bugAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions