From 6b9e15f0ad50915ac9d0f2a37fe769ca0a41a447 Mon Sep 17 00:00:00 2001 From: Julian Taylor Date: Thu, 20 Apr 2017 12:21:07 +0200 Subject: BUG: don't create array with invalid memory in where When creating the tuple view of np.where, make sure the arrays point to valid memory when they are empty. Numpy assumes that even empty arrays have valid memory, e.g. in the source stride == 0 assignments. Closes gh-8922. --- numpy/core/src/multiarray/item_selection.c | 12 +++++++++++- numpy/core/tests/test_multiarray.py | 8 ++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/numpy/core/src/multiarray/item_selection.c b/numpy/core/src/multiarray/item_selection.c index 3c0f0782e..c88cdfdcb 100644 --- a/numpy/core/src/multiarray/item_selection.c +++ b/numpy/core/src/multiarray/item_selection.c @@ -2176,6 +2176,7 @@ PyArray_Nonzero(PyArrayObject *self) NpyIter_IterNextFunc *iternext; NpyIter_GetMultiIndexFunc *get_multi_index; char **dataptr; + int is_empty = 0; /* * First count the number of non-zeros in 'self'. @@ -2329,13 +2330,22 @@ finish: return NULL; } + for (i = 0; i < ndim; ++i) { + if (PyArray_DIMS(ret)[i] == 0) { + is_empty = 1; + break; + } + } + /* Create views into ret, one for each dimension */ for (i = 0; i < ndim; ++i) { npy_intp stride = ndim * NPY_SIZEOF_INTP; + /* the result is an empty array, the view must point to valid memory */ + npy_intp data_offset = is_empty ? 0 : i * NPY_SIZEOF_INTP; PyArrayObject *view = (PyArrayObject *)PyArray_New(Py_TYPE(ret), 1, &nonzero_count, NPY_INTP, &stride, - PyArray_BYTES(ret) + i*NPY_SIZEOF_INTP, + PyArray_BYTES(ret) + data_offset, 0, PyArray_FLAGS(ret), (PyObject *)ret); if (view == NULL) { Py_DECREF(ret); diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index 213ae7a52..19946d1d1 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -6619,6 +6619,14 @@ class TestWhere(TestCase): assert_equal(np.where(True, a, b), "abcd") assert_equal(np.where(False, b, a), "abcd") + def test_empty_result(self): + # pass empty where result through an assignment which reads the data of + # empty arrays, error detectable with valgrind, see gh-8922 + x = np.zeros((1, 1)) + ibad = np.vstack(np.where(x == 99.)) + assert_array_equal(ibad, + np.atleast_2d(np.array([[],[]], dtype=np.intp))) + if not IS_PYPY: # sys.getsizeof() is not valid on PyPy -- cgit v1.2.3 From a16f16b94b61fc35b887d9e9f2e12c817c2819b6 Mon Sep 17 00:00:00 2001 From: Julian Taylor Date: Thu, 20 Apr 2017 13:36:53 +0200 Subject: BUG: do not try to read data from empty src-stride 0 arrays --- numpy/core/src/multiarray/lowlevel_strided_loops.c.src | 3 +++ 1 file changed, 3 insertions(+) diff --git a/numpy/core/src/multiarray/lowlevel_strided_loops.c.src b/numpy/core/src/multiarray/lowlevel_strided_loops.c.src index 9a5c3004d..397aaf209 100644 --- a/numpy/core/src/multiarray/lowlevel_strided_loops.c.src +++ b/numpy/core/src/multiarray/lowlevel_strided_loops.c.src @@ -206,6 +206,9 @@ static NPY_GCC_OPT_3 void #else npy_uint64 temp0, temp1; #endif + if (N == 0) { + return; + } #if @is_aligned@ && @elsize@ != 16 /* sanity check */ assert(npy_is_aligned(dst, _ALIGN(@type@))); -- cgit v1.2.3