Skip to content

Commit

Permalink
BUG: INCREF before DECREF when copying object arrays.
Browse files Browse the repository at this point in the history
Only the change in dtype_transfer actually seems to be
related to the simple np.copyto(a, a) bug, when a is a scalar
object array.
It seemed however safer to me, to generally turn around the
logic, even if it may not be necessary and in one place
requires an extra temporary variable.

Closes gh-3787
  • Loading branch information
seberg committed Sep 23, 2013
1 parent 372d9ca commit ed7e9ab
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 10 deletions.
17 changes: 10 additions & 7 deletions numpy/core/src/multiarray/arraytypes.c.src
Expand Up @@ -501,9 +501,10 @@ OBJECT_setitem(PyObject *op, char *ov, PyArrayObject *ap)
PyObject *obj;

NPY_COPY_PYOBJECT_PTR(&obj, ov);
Py_XDECREF(obj);

Py_INCREF(op);
Py_XDECREF(obj);

NPY_COPY_PYOBJECT_PTR(ov, &op);

return PyErr_Occurred() ? -1 : 0;
Expand Down Expand Up @@ -1158,9 +1159,11 @@ static void
{
npy_intp i;
int skip = @skip@;
PyObject *tmp;
for (i = 0; i < n; i++, ip +=skip, op++) {
Py_XDECREF(*op);
tmp = *op;
*op = @FROMTYPE@_getitem((char *)ip, aip);
Py_XDECREF(tmp);
}
}
/**end repeat**/
Expand Down Expand Up @@ -1866,10 +1869,10 @@ OBJECT_copyswapn(PyObject **dst, npy_intp dstride, PyObject **src,
dstp = (unsigned char*)dst;
srcp = (unsigned char*)src;
for (i = 0; i < n; i++) {
NPY_COPY_PYOBJECT_PTR(&tmp, dstp);
Py_XDECREF(tmp);
NPY_COPY_PYOBJECT_PTR(&tmp, srcp);
Py_XINCREF(tmp);
NPY_COPY_PYOBJECT_PTR(&tmp, dstp);
Py_XDECREF(tmp);
NPY_COPY_PYOBJECT_PTR(dstp, srcp);
dstp += dstride;
srcp += sstride;
Expand All @@ -1894,10 +1897,10 @@ OBJECT_copyswap(PyObject **dst, PyObject **src, int NPY_UNUSED(swap),
}
else {
PyObject *tmp;
NPY_COPY_PYOBJECT_PTR(&tmp, dst);
Py_XDECREF(tmp);
NPY_COPY_PYOBJECT_PTR(&tmp, src);
Py_XINCREF(tmp);
NPY_COPY_PYOBJECT_PTR(&tmp, dst);
Py_XDECREF(tmp);
NPY_COPY_PYOBJECT_PTR(dst, src);
}
}
Expand Down Expand Up @@ -3222,8 +3225,8 @@ OBJECT_fillwithscalar(PyObject **buffer, npy_intp length, PyObject **value,
npy_intp i;
PyObject *val = *value;
for (i = 0; i < length; i++) {
Py_XDECREF(buffer[i]);
Py_XINCREF(val);
Py_XDECREF(buffer[i]);
buffer[i] = val;
}
}
Expand Down
6 changes: 3 additions & 3 deletions numpy/core/src/multiarray/dtype_transfer.c
Expand Up @@ -127,14 +127,14 @@ _strided_to_strided_copy_references(char *dst, npy_intp dst_stride,
NPY_COPY_PYOBJECT_PTR(&src_ref, src);
NPY_COPY_PYOBJECT_PTR(&dst_ref, dst);

/* Release the reference in dst */
NPY_DT_DBG_REFTRACE("dec dst ref", dst_ref);
Py_XDECREF(dst_ref);
/* Copy the reference */
NPY_DT_DBG_REFTRACE("copy src ref", src_ref);
NPY_COPY_PYOBJECT_PTR(dst, &src_ref);
/* Claim the reference */
Py_XINCREF(src_ref);
/* Release the reference in dst */
NPY_DT_DBG_REFTRACE("dec dst ref", dst_ref);
Py_XDECREF(dst_ref);

src += src_stride;
dst += dst_stride;
Expand Down
8 changes: 8 additions & 0 deletions numpy/core/tests/test_regression.py
Expand Up @@ -1665,6 +1665,14 @@ def test_object_array_self_reference(self):
a[...] += 1
assert_equal(a, 1)

def test_object_array_self_copy(self):
# An object array being copied into itself DECREF'ed before INCREF'ing
# causing segmentation faults (gh-3787)
a = np.array(object(), dtype=object)
np.copyto(a, a)
assert_equal(sys.getrefcount(a[()]), 2)
a[()].__class__ # will segfault if object was deleted

def test_zerosize_accumulate(self):
"Ticket #1733"
x = np.array([[42, 0]], dtype=np.uint32)
Expand Down

0 comments on commit ed7e9ab

Please sign in to comment.