summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--numpy/core/src/multiarray/methods.c9
-rw-r--r--numpy/core/tests/test_indexing.py51
2 files changed, 56 insertions, 4 deletions
diff --git a/numpy/core/src/multiarray/methods.c b/numpy/core/src/multiarray/methods.c
index 3f461b375..2c958989f 100644
--- a/numpy/core/src/multiarray/methods.c
+++ b/numpy/core/src/multiarray/methods.c
@@ -2452,7 +2452,7 @@ array_complex(PyArrayObject *self, PyObject *NPY_UNUSED(args))
static PyObject *
array_getslice(PyArrayObject *self, PyObject *args)
{
- PyObject *start, *stop, *slice;
+ PyObject *start, *stop, *slice, *result;
if (!PyArg_ParseTuple(args, "OO:__getslice__", &start, &stop)) {
return NULL;
}
@@ -2463,7 +2463,9 @@ array_getslice(PyArrayObject *self, PyObject *args)
}
/* Deliberately delegate to subclasses */
- return PyObject_GetItem((PyObject *)self, slice);
+ result = PyObject_GetItem((PyObject *)self, slice);
+ Py_DECREF(slice);
+ return result;
}
static PyObject *
@@ -2481,9 +2483,10 @@ array_setslice(PyArrayObject *self, PyObject *args)
/* Deliberately delegate to subclasses */
if (PyObject_SetItem((PyObject *)self, slice, value) < 0) {
+ Py_DECREF(slice);
return NULL;
}
-
+ Py_DECREF(slice);
Py_RETURN_NONE;
}
diff --git a/numpy/core/tests/test_indexing.py b/numpy/core/tests/test_indexing.py
index 7cfb81da7..df9eca627 100644
--- a/numpy/core/tests/test_indexing.py
+++ b/numpy/core/tests/test_indexing.py
@@ -10,7 +10,7 @@ from numpy.core.multiarray_tests import array_indexing
from itertools import product
from numpy.testing import (
run_module_suite, assert_, assert_equal, assert_raises,
- assert_array_equal, assert_warns, HAS_REFCOUNT
+ assert_array_equal, assert_warns, dec, HAS_REFCOUNT, suppress_warnings,
)
@@ -622,6 +622,55 @@ class TestSubclasses(object):
assert_array_equal(new_s.finalize_status, new_s)
assert_array_equal(new_s.old, s)
+ @dec.skipif(not HAS_REFCOUNT)
+ def test_slice_decref_getsetslice(self):
+ # See gh-10066, a temporary slice object should be discarted.
+ # This test is only really interesting on Python 2 since
+ # it goes through `__set/getslice__` here and can probably be
+ # removed. Use 0:7 to make sure it is never None:7.
+ class KeepIndexObject(np.ndarray):
+ def __getitem__(self, indx):
+ self.indx = indx
+ if indx == slice(0, 7):
+ raise ValueError
+
+ def __setitem__(self, indx, val):
+ self.indx = indx
+ if indx == slice(0, 4):
+ raise ValueError
+
+ k = np.array([1]).view(KeepIndexObject)
+ k[0:5]
+ assert_equal(k.indx, slice(0, 5))
+ assert_equal(sys.getrefcount(k.indx), 2)
+ try:
+ k[0:7]
+ raise AssertionError
+ except ValueError:
+ # The exception holds a reference to the slice so clear on Py2
+ if hasattr(sys, 'exc_clear'):
+ with suppress_warnings() as sup:
+ sup.filter(DeprecationWarning)
+ sys.exc_clear()
+ assert_equal(k.indx, slice(0, 7))
+ assert_equal(sys.getrefcount(k.indx), 2)
+
+ k[0:3] = 6
+ assert_equal(k.indx, slice(0, 3))
+ assert_equal(sys.getrefcount(k.indx), 2)
+ try:
+ k[0:4] = 2
+ raise AssertionError
+ except ValueError:
+ # The exception holds a reference to the slice so clear on Py2
+ if hasattr(sys, 'exc_clear'):
+ with suppress_warnings() as sup:
+ sup.filter(DeprecationWarning)
+ sys.exc_clear()
+ assert_equal(k.indx, slice(0, 4))
+ assert_equal(sys.getrefcount(k.indx), 2)
+
+
class TestFancyIndexingCast(object):
def test_boolean_index_cast_assign(self):
# Setup the boolean index and float arrays.