Skip to content

BUG: memleak in iter_ass_subscript / PyArray_IterNew #30508

@msalle

Description

@msalle

Describe the issue:

numpy 2.4.0 introduces a memory leak that ultimately traces to ites_ass_subscript() and PyArray_IterNew(). Running the same code with 2.3.5 does not show any definitely lost bytes.

Reproduce the code example:

# Run the below using `valgrind --leak-check=full --show-leak-kinds=definite python myproblem.py`

import numpy as np

for _ in range(42):
    matrix = np.eye(10, dtype=np.complex128)

Error message:

With 2.3.5, valgrind shows no definitely lost, while for 2.4.0:


==26907== HEAP SUMMARY:
==26907==     in use at exit: 1,795,829 bytes in 1,168 blocks
==26907==   total heap usage: 10,563 allocs, 9,395 frees, 22,379,641 bytes allocated
==26907== 
==26907== 110,544 bytes in 42 blocks are definitely lost in loss record 301 of 305
==26907==    at 0x4841984: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==26907==    by 0x5997D59: PyArray_IterNew (in /tmp/numpy_test/lib/python3.11/site-packages/numpy/_core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so)
==26907==    by 0x5999174: iter_ass_subscript (in /tmp/numpy_test/lib/python3.11/site-packages/numpy/_core/_multiarray_umath.cpython-311-x86_64-linux-gnu.so)
==26907==    by 0x4A75AD8: _PyEval_EvalFrameDefault (in /usr/lib64/libpython3.11.so.1.0)
==26907==    by 0x4B484F9: PyEval_EvalCode (in /usr/lib64/libpython3.11.so.1.0)
==26907==    by 0x4BD3F4C: ??? (in /usr/lib64/libpython3.11.so.1.0)
==26907==    by 0x4BD3FEB: ??? (in /usr/lib64/libpython3.11.so.1.0)
==26907==    by 0x4BD40C2: ??? (in /usr/lib64/libpython3.11.so.1.0)
==26907==    by 0x4BD43A4: _PyRun_SimpleFileObject (in /usr/lib64/libpython3.11.so.1.0)
==26907==    by 0x4BD4493: _PyRun_AnyFileObject (in /usr/lib64/libpython3.11.so.1.0)
==26907==    by 0x4BD47EA: Py_RunMain (in /usr/lib64/libpython3.11.so.1.0)
==26907==    by 0x4BD5528: Py_BytesMain (in /usr/lib64/libpython3.11.so.1.0)
==26907== 
==26907== LEAK SUMMARY:
==26907==    definitely lost: 110,544 bytes in 42 blocks
==26907==    indirectly lost: 0 bytes in 0 blocks
==26907==      possibly lost: 183,992 bytes in 103 blocks
==26907==    still reachable: 1,501,261 bytes in 1,022 blocks
==26907==         suppressed: 32 bytes in 1 blocks
==26907== Reachable blocks (those to which a pointer was found) are not shown.
==26907== To see them, rerun with: --leak-check=full --show-leak-kinds=all


Using instead conda-forge based python3.14.2 shows a very identical output with the same leaks:

==27653== HEAP SUMMARY:
==27653==     in use at exit: 1,378,468 bytes in 830 blocks
==27653==   total heap usage: 27,163 allocs, 26,333 frees, 181,204,009 bytes allocated
==27653== 
==27653== 110,544 bytes in 42 blocks are definitely lost in loss record 235 of 239
==27653==    at 0x4841984: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==27653==    by 0x8D5FF89: PyArray_IterNew (in /tmp/miniforge3/envs/finesse3/lib/python3.14/site-packages/numpy/_core/_multiarray_umath.cpython-314-x86_64-linux-gnu.so)
==27653==    by 0x8D6142B: iter_ass_subscript (in /tmp/miniforge3/envs/finesse3/lib/python3.14/site-packages/numpy/_core/_multiarray_umath.cpython-314-x86_64-linux-gnu.so)
==27653==    by 0x2F6925: _PyEval_EvalFrameDefault (generated_cases.c.h:11500)
==27653==    by 0x2ED947: UnknownInlinedFun (pycore_ceval.h:121)
==27653==    by 0x2ED947: _PyEval_Vector (ceval.c:2083)
==27653==    by 0x3C9494: PyEval_EvalCode (ceval.c:975)
==27653==    by 0x409EAC: run_mod.lto_priv.0 (pythonrun.c:1459)
==27653==    by 0x408AB7: pyrun_file.lto_priv.0 (pythonrun.c:1293)
==27653==    by 0x4087FE: _PyRun_SimpleFileObject (pythonrun.c:521)
==27653==    by 0x4084BC: _PyRun_AnyFileObject (pythonrun.c:81)
==27653==    by 0x3BE020: UnknownInlinedFun (main.c:410)
==27653==    by 0x3BE020: UnknownInlinedFun (main.c:429)
==27653==    by 0x3BE020: UnknownInlinedFun (main.c:694)
==27653==    by 0x3BE020: Py_RunMain (main.c:775)
==27653==    by 0x3B8046: Py_BytesMain (main.c:829)
==27653== 
==27653== LEAK SUMMARY:
==27653==    definitely lost: 110,544 bytes in 42 blocks
==27653==    indirectly lost: 0 bytes in 0 blocks
==27653==      possibly lost: 172,240 bytes in 95 blocks
==27653==    still reachable: 1,095,652 bytes in 692 blocks
==27653==         suppressed: 32 bytes in 1 blocks
==27653== Reachable blocks (those to which a pointer was found) are not shown.
==27653== To see them, rerun with: --leak-check=full --show-leak-kinds=all

Python and NumPy Versions:

OpenSUSE LEAP with python3.11 (using venv and pip to install numpy 2.4.0 or 2.3.5)
2.4.0
3.11.14 (main, Nov 20 2025, 22:16:35) [GCC]

Likewise for a 3.14.2 based conda (using pip to install 2.4.0 or 2.3.5)
2.4.0
3.14.2 | packaged by conda-forge | (main, Dec 6 2025, 11:21:58) [GCC 14.3.0]

Runtime Environment:

[{'numpy_version': '2.4.0',
  'python': '3.11.14 (main, Nov 20 2025, 22:16:35) [GCC]',
  'uname': uname_result(system='Linux', node='XXXXXX', release='6.18.0-lp156.12.g2fafc8d-default', version='#1 SMP PREEMPT_DYNAMIC Wed Dec  3 02:59:05 UTC 2025 (2fafc8d)', machine='x86_64')},
 {'simd_extensions': {'baseline': ['X86_V2'],
                      'found': ['X86_V3', 'X86_V4', 'AVX512_ICL'],
                      'not_found': ['AVX512_SPR']}},
 {'ignore_floating_point_errors_in_matmul': False},
 {'architecture': 'SkylakeX',
  'filepath': '/tmp/numpy_test/lib/python3.11/site-packages/numpy.libs/libscipy_openblas64_-fdde5778.so',
  'internal_api': 'openblas',
  'num_threads': 8,
  'prefix': 'libscipy_openblas',
  'threading_layer': 'pthreads',
  'user_api': 'blas',
  'version': '0.3.30'}]

How does this issue affect you or how did you find it:

We found a memleak test in our code https://gitlab.com/ifosim/finesse/finesse3 starting to fail when moving to numpy 2.4.0. For now the test is disabled, but that's obviously suboptimal.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions