Skip to content

Commit db022e2

Browse files
authored
Merge pull request #29414 from charris/backport-29358
BUG: Fix reference leakage for output arrays in reduction functions
2 parents 428649e + 5339c80 commit db022e2

File tree

2 files changed

+43
-0
lines changed

2 files changed

+43
-0
lines changed

numpy/_core/src/umath/ufunc_object.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3727,6 +3727,8 @@ PyUFunc_GenericReduction(PyUFuncObject *ufunc,
37273727
if (ret == NULL) {
37283728
goto fail;
37293729
}
3730+
3731+
Py_XDECREF(out);
37303732

37313733
Py_DECREF(signature[0]);
37323734
Py_DECREF(signature[1]);
@@ -3753,6 +3755,8 @@ PyUFunc_GenericReduction(PyUFuncObject *ufunc,
37533755
return wrapped_result;
37543756

37553757
fail:
3758+
Py_XDECREF(out);
3759+
37563760
Py_XDECREF(signature[0]);
37573761
Py_XDECREF(signature[1]);
37583762
Py_XDECREF(signature[2]);

numpy/_core/tests/test_ufunc.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3005,6 +3005,45 @@ def test_reduce_casterrors(offset):
30053005
assert out[()] < value * offset
30063006

30073007

3008+
@pytest.mark.skipif(not HAS_REFCOUNT, reason="Python lacks refcounts")
3009+
def test_reduction_no_reference_leak():
3010+
# Test that the generic reduction does not leak references.
3011+
# gh-29358
3012+
arr = np.array([1, 2, 3], dtype=np.int32)
3013+
count = sys.getrefcount(arr)
3014+
3015+
np.add.reduce(arr, dtype=np.int32, initial=0)
3016+
assert count == sys.getrefcount(arr)
3017+
3018+
np.add.accumulate(arr, dtype=np.int32)
3019+
assert count == sys.getrefcount(arr)
3020+
3021+
np.add.reduceat(arr, [0, 1], dtype=np.int32)
3022+
assert count == sys.getrefcount(arr)
3023+
3024+
# with `out=` the reference count is not changed
3025+
out = np.empty((), dtype=np.int32)
3026+
out_count = sys.getrefcount(out)
3027+
3028+
np.add.reduce(arr, dtype=np.int32, out=out, initial=0)
3029+
assert count == sys.getrefcount(arr)
3030+
assert out_count == sys.getrefcount(out)
3031+
3032+
out = np.empty(arr.shape, dtype=np.int32)
3033+
out_count = sys.getrefcount(out)
3034+
3035+
np.add.accumulate(arr, dtype=np.int32, out=out)
3036+
assert count == sys.getrefcount(arr)
3037+
assert out_count == sys.getrefcount(out)
3038+
3039+
out = np.empty((2,), dtype=np.int32)
3040+
out_count = sys.getrefcount(out)
3041+
3042+
np.add.reduceat(arr, [0, 1], dtype=np.int32, out=out)
3043+
assert count == sys.getrefcount(arr)
3044+
assert out_count == sys.getrefcount(out)
3045+
3046+
30083047
def test_object_reduce_cleanup_on_failure():
30093048
# Test cleanup, including of the initial value (manually provided or not)
30103049
with pytest.raises(TypeError):

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy