8000 BUG: Fix decref before incref for in-place accumulate · jaimefrio/numpy@e2684d0 · GitHub
[go: up one dir, main page]

Skip to content

Commit e2684d0

Browse files
sebergjaimefrio
authored andcommitted
BUG: Fix decref before incref for in-place accumulate
closes numpygh-7402
1 parent d2d8dd4 commit e2684d0

File tree

2 files changed

+30
-3
lines changed

2 files changed

+30
-3
lines changed

numpy/core/src/umath/ufunc_object.c

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3270,17 +3270,22 @@ PyUFunc_Accumulate(PyUFuncObject *ufunc, PyArrayObject *arr, PyArrayObject *out,
32703270
NPY_BEGIN_THREADS_NDITER(iter);
32713271

32723272
do {
3273-
32743273
dataptr_copy[0] = dataptr[0];
32753274
dataptr_copy[1] = dataptr[1];
32763275
dataptr_copy[2] = dataptr[0];
32773276

32783277
/* Copy the first element to start the reduction */
32793278
if (otype == NPY_OBJECT) {
3279+
/*
3280+
* Input (dataptr[0]) and output (dataptr[1]) may point
3281+
* to the same memory (i.e. np.add.accumulate(a, out=a)).
3282+
* In that case need to incref before decref to avoid the
3283+
* possibility of the reference count being zero temporarily.
3284+
*/
3285+
Py_XINCREF(*(PyObject **)dataptr_copy[1]);
32803286
Py_XDECREF(*(PyObject **)dataptr_copy[0]);
32813287
*(PyObject **)dataptr_copy[0] =
32823288
*(PyObject **)dataptr_copy[1];
3283-
Py_XINCREF(*(PyObject **)dataptr_copy[0]);
32843289
}
32853290
else {
32863291
memcpy(dataptr_copy[0], dataptr_copy[1], itemsize);
@@ -3333,10 +3338,16 @@ PyUFunc_Accumulate(PyUFuncObject *ufunc, PyArrayObject *arr, PyArrayObject *out,
33333338

33343339
/* Copy the first element to start the reduction */
33353340
if (otype == NPY_OBJECT) {
3341+
/*
3342+
* Input (dataptr[0]) and output (dataptr[1]) may point
3343+
* to the same memory (i.e. np.add.accumulate(a, out=a, axis=0)).
3344+
* In that case need to incref before decref to avoid the
3345+
* possibility of the reference count being zero temporarily.
3346+
*/
3347+
Py_XINCREF(*(PyObject **)dataptr_copy[1]);
33363348
Py_XDECREF(*(PyObject **)dataptr_copy[0]);
33373349
*(PyObject **)dataptr_copy[0] =
33383350
*(PyObject **)dataptr_copy[1];
3339-
Py_XINCREF(*(PyObject **)dataptr_copy[0]);
33403351
}
33413352
else {
33423353
memcpy(dataptr_copy[0], dataptr_copy[1], itemsize);

numpy/core/tests/test_ufunc.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,22 @@ def test_object_array_reduction(self):
649649
assert_equal(np.array([[1]], dtype=object).sum(), 1)
650650
assert_equal(np.array([[[1, 2]]], dtype=object).sum((0, 1)), [1, 2])
651651

652+
def test_object_array_accumulate_inplace(self):
653+
# Checks that in-place accumulates work, see also gh-7402
654+
arr = np.ones(4, dtype=object)
655+
arr[:] = [[1] for i in range(4)]
656+
# Twice reproduced also for tuples:
657+
np.add.accumulate(arr, out=arr)
658+
np.add.accumulate(arr, out=arr)
659+
assert_array_equal(arr, np.array([[1]*i for i in [1, 3, 6, 10]]))
660+
661+
# And the same if the axis argument is used
662+
arr = np.ones((2, 4), dtype=object)
663+
arr[0, :] = [[2] for i in range(4)]
664+
np.add.accumulate(arr, out=arr, axis=-1)
665+
np.add.accumulate(arr, out=arr, axis=-1)
666+
assert_array_equal(arr[0, :], np.array([[2]*i for i in [1, 3, 6, 10]]))
667+
652668
def test_object_scalar_multiply(self):
653669
# Tickets #2469 and #4482
654670
arr = np.matrix([1, 2], dtype=object)

0 commit comments

Comments
 (0)
0