Skip to content

Commit 020e847

Browse files
authored
Merge pull request numpy#26025 from ngoldbaum/fix-__array__-reference-leak
BUG: fix reference count leak in __array__ internals
2 parents 99511e0 + c7db120 commit 020e847

File tree

2 files changed

+26
-1
lines changed

2 files changed

+26
-1
lines changed

numpy/_core/src/multiarray/ctors.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2466,6 +2466,9 @@ PyArray_FromArrayAttr_int(
24662466

24672467
if (new == NULL) {
24682468
if (npy_ma_str_array_err_msg_substr == NULL) {
2469+
Py_DECREF(array_meth);
2470+
Py_DECREF(args);
2471+
Py_DECREF(kwargs);
24692472
return NULL;
24702473
}
24712474
PyObject *type, *value, *traceback;
@@ -2481,6 +2484,7 @@ PyArray_FromArrayAttr_int(
24812484
"__array__ should implement 'dtype' and "
24822485
"'copy' keywords", 1) < 0) {
24832486
Py_DECREF(str_value);
2487+
Py_DECREF(array_meth);
24842488
Py_DECREF(args);
24852489
Py_DECREF(kwargs);
24862490
return NULL;
@@ -2490,6 +2494,7 @@ PyArray_FromArrayAttr_int(
24902494
new = PyObject_Call(array_meth, args, kwargs);
24912495
if (new == NULL) {
24922496
Py_DECREF(str_value);
2497+
Py_DECREF(array_meth);
24932498
Py_DECREF(args);
24942499
Py_DECREF(kwargs);
24952500
return NULL;
@@ -2500,15 +2505,16 @@ PyArray_FromArrayAttr_int(
25002505
}
25012506
if (new == NULL) {
25022507
PyErr_Restore(type, value, traceback);
2508+
Py_DECREF(array_meth);
25032509
Py_DECREF(args);
25042510
Py_DECREF(kwargs);
25052511
return NULL;
25062512
}
25072513
}
25082514

2515+
Py_DECREF(array_meth);
25092516
Py_DECREF(args);
25102517
Py_DECREF(kwargs);
2511-
Py_DECREF(array_meth);
25122518

25132519
if (!PyArray_Check(new)) {
25142520
PyErr_SetString(PyExc_ValueError,

numpy/_core/tests/test_multiarray.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8492,6 +8492,25 @@ def __array__(self, dtype=None):
84928492
"and 'copy' keywords")):
84938493
np.array(a, copy=False)
84948494

8495+
@pytest.mark.skipif(not HAS_REFCOUNT, reason="Python lacks refcounts")
8496+
def test__array__reference_leak(self):
8497+
class NotAnArray:
8498+
def __array__(self):
8499+
raise NotImplementedError()
8500+
8501+
x = NotAnArray()
8502+
8503+
refcount = sys.getrefcount(x)
8504+
8505+
try:
8506+
np.array(x)
8507+
except NotImplementedError:
8508+
pass
8509+
8510+
gc.collect()
8511+
8512+
assert refcount == sys.getrefcount(x)
8513+
84958514
@pytest.mark.parametrize(
84968515
"arr", [np.ones(()), np.arange(81).reshape((9, 9))])
84978516
@pytest.mark.parametrize("order1", ["C", "F", None])

0 commit comments

Comments
 (0)