diff options
-rw-r--r-- | numpy/core/src/multiarray/methods.c | 9 | ||||
-rw-r--r-- | numpy/core/tests/test_indexing.py | 51 |
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. |