Skip to content

BUG: fix leak in reductions when a ufunc override errors or is not found - #31731

Merged
seberg merged 4 commits into
numpy:mainfrom
ikrommyd:fix-leak-reductions-override
Jun 24, 2026
Merged

seberg merged 4 commits into
numpy:mainfrom
ikrommyd:fix-leak-reductions-override

Conversation

@ikrommyd

@ikrommyd ikrommyd commented Jun 23, 2026 •

Copy link
Copy Markdown
Member

PR summary

Closes #31677

Just another thing I noticed while reading reduction code and realised there's an open issue for it already.
One can see this memory leak by doing something like the following and memory profiling that (with memray for example) and will notice the memory is just growing.

import numpy as np

class Array:
    data = np.array([1,2,3])
    def __array_ufunc__(ufunc, method, *inputs, **kwargs):
        return NotImplemented

arr = Array()

if __name__ == "__main__":
    for _ in range(1_000_000):
        try:
            np.add.reduce(arr)
        except Exception as e:
            pass

I think goto fail is probably nicer than

Py_XDECREF(full_args.in);
Py_XDECREF(full_args.out);

and I believe it's safe. Only the else if (override) branch right bellow cannot use goto fail as it needs to return the override and not NULL.

I don't think there is a way to have a test regarding the ref count in the python side because full_args is created internally in the function in C. But we could have a test that is just the above without the loop and a sanitizer would probably capture the leak. Let me know if you want that. cc @seberg because you wanted a similar test in #31699.

First time committer introduction

N/A

AI Disclosure

No AI

@jorenham jorenham changed the title Fix leak reductions override BUG: Fix leak reductions override Jun 23, 2026
@ikrommyd ikrommyd changed the title BUG: Fix leak reductions override BUG: fix leak in reductions when a ufunc override errors or is not found Jun 23, 2026
@ikrommyd

ikrommyd commented Jun 23, 2026 •

Copy link
Copy Markdown
Member Author

Just pasting the results of profiling the snippet above with memray (with native traces too) on main:
image
image
With this PR, it becomes flat:
image

@seberg

seberg commented Jun 24, 2026

Copy link
Copy Markdown
Member

Yeah, just out of principle. Seems like a simple test to add and I expect leak sanitizer or so will find it even without a loop.

Signed-off-by: Iason Krommydas <[email protected]>
@ikrommyd

Copy link
Copy Markdown
Member Author

Yeah, just out of principle. Seems like a simple test to add and I expect leak sanitizer or so will find it even without a loop.

Done

@ikrommyd

Copy link
Copy Markdown
Member Author

The BLAS tests failure should be unrelated

@seberg seberg left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, for adding the test, good enough, let's put it in.

a = A()
assert_raises(TypeError, np.add.reduce, a)
assert_raises(TypeError, np.add.accumulate, a)
assert_raises(TypeError, np.add.reduceat, a, [0])

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

N.B. I generally prefer with pytest.raises() even if it a lot of old tests use assert_raises.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah thanks. Noted for the future. I intuitively tend to follow existing patterns and I literally just copied it from the tests right above it

@seberg
seberg merged commit 4d85561 into numpy:main Jun 24, 2026
96 of 98 checks passed
@seberg seberg added the 09 - Backport-Candidate PRs tagged should be backported label Jun 24, 2026
@ikrommyd
ikrommyd deleted the fix-leak-reductions-override branch June 24, 2026 12:59
@charris charris removed the 09 - Backport-Candidate PRs tagged should be backported label Jul 2, 2026
charris pushed a commit that referenced this pull request Jul 3, 2026
charris added a commit that referenced this pull request Jul 3, 2026
BUG: fix leak in reductions when a ufunc override errors or is not found (#31731)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BUG: Reference leak in PyUFunc_GenericReduction on CheckOverride error

4 participants