diff options
author | Eric Wieser <wieser.eric@gmail.com> | 2017-04-22 14:54:54 +0100 |
---|---|---|
committer | Eric Wieser <wieser.eric@gmail.com> | 2017-10-01 16:46:19 -0700 |
commit | 0e9e205c3b1d90dc6782bd21bb428d17aded0e90 (patch) | |
tree | 04fa3c3bbb088ee014364160a214370222567c0d /numpy/core | |
parent | eb514b1c87d8d2c0e2ae159cf24046d490b2c448 (diff) | |
download | python-numpy-0e9e205c3b1d90dc6782bd21bb428d17aded0e90.tar.gz python-numpy-0e9e205c3b1d90dc6782bd21bb428d17aded0e90.tar.bz2 python-numpy-0e9e205c3b1d90dc6782bd21bb428d17aded0e90.zip |
BUG: Prevent ValueError when resizing V0 arrays
Diffstat (limited to 'numpy/core')
-rw-r--r-- | numpy/core/src/multiarray/shape.c | 43 | ||||
-rw-r--r-- | numpy/core/tests/test_multiarray.py | 11 |
2 files changed, 29 insertions, 25 deletions
diff --git a/numpy/core/src/multiarray/shape.c b/numpy/core/src/multiarray/shape.c index 07ab9b626..dac3c960a 100644 --- a/numpy/core/src/multiarray/shape.c +++ b/numpy/core/src/multiarray/shape.c @@ -41,15 +41,14 @@ NPY_NO_EXPORT PyObject * PyArray_Resize(PyArrayObject *self, PyArray_Dims *newshape, int refcheck, NPY_ORDER order) { + npy_intp oldnbytes, newnbytes; npy_intp oldsize, newsize; int new_nd=newshape->len, k, n, elsize; int refcnt; npy_intp* new_dimensions=newshape->ptr; npy_intp new_strides[NPY_MAXDIMS]; - size_t sd; npy_intp *dimptr; char *new_data; - npy_intp largest; if (!PyArray_ISONESEGMENT(self)) { PyErr_SetString(PyExc_ValueError, @@ -57,13 +56,9 @@ PyArray_Resize(PyArrayObject *self, PyArray_Dims *newshape, int refcheck, return NULL; } - if (PyArray_DESCR(self)->elsize == 0) { - PyErr_SetString(PyExc_ValueError, - "Bad data-type size."); - return NULL; - } + /* Compute total size of old and new arrays. The new size might overflow */ + oldsize = PyArray_SIZE(self); newsize = 1; - largest = NPY_MAX_INTP / PyArray_DESCR(self)->elsize; for(k = 0; k < new_nd; k++) { if (new_dimensions[k] == 0) { break; @@ -73,14 +68,19 @@ PyArray_Resize(PyArrayObject *self, PyArray_Dims *newshape, int refcheck, "negative dimensions not allowed"); return NULL; } - newsize *= new_dimensions[k]; - if (newsize <= 0 || newsize > largest) { + if (npy_mul_with_overflow_intp(&newsize, newsize, new_dimensions[k])) { return PyErr_NoMemory(); } } - oldsize = PyArray_SIZE(self); - if (oldsize != newsize) { + /* Convert to number of bytes. The new count might overflow */ + elsize = PyArray_DESCR(self)->elsize; + oldnbytes = oldsize * elsize; + if (npy_mul_with_overflow_intp(&newnbytes, newsize, elsize)) { + return PyErr_NoMemory(); + } + + if (oldnbytes != newnbytes) { if (!(PyArray_FLAGS(self) & NPY_ARRAY_OWNDATA)) { PyErr_SetString(PyExc_ValueError, "cannot resize this array: it does not own its data"); @@ -92,7 +92,6 @@ PyArray_Resize(PyArrayObject *self, PyArray_Dims *newshape, int refcheck, PyErr_SetString(PyExc_ValueError, "cannot resize an array with refcheck=True on PyPy.\n" "Use the resize function or refcheck=False"); - return NULL; #else refcnt = PyArray_REFCOUNT(self); @@ -111,14 +110,9 @@ PyArray_Resize(PyArrayObject *self, PyArray_Dims *newshape, int refcheck, return NULL; } - if (newsize == 0) { - sd = PyArray_DESCR(self)->elsize; - } - else { - sd = newsize*PyArray_DESCR(self)->elsize; - } - /* Reallocate space if needed */ - new_data = PyDataMem_RENEW(PyArray_DATA(self), sd); + /* Reallocate space if needed - allocating 0 is forbidden */ + new_data = PyDataMem_RENEW( + PyArray_DATA(self), newnbytes == 0 ? elsize : newnbytes); if (new_data == NULL) { PyErr_SetString(PyExc_MemoryError, "cannot allocate memory for array"); @@ -127,13 +121,12 @@ PyArray_Resize(PyArrayObject *self, PyArray_Dims *newshape, int refcheck, ((PyArrayObject_fields *)self)->data = new_data; } - if ((newsize > oldsize) && PyArray_ISWRITEABLE(self)) { + if (newnbytes > oldnbytes && PyArray_ISWRITEABLE(self)) { /* Fill new memory with zeros */ - elsize = PyArray_DESCR(self)->elsize; if (PyDataType_FLAGCHK(PyArray_DESCR(self), NPY_ITEM_REFCOUNT)) { PyObject *zero = PyInt_FromLong(0); char *optr; - optr = PyArray_BYTES(self) + oldsize*elsize; + optr = PyArray_BYTES(self) + oldnbytes; n = newsize - oldsize; for (k = 0; k < n; k++) { _putzero((char *)optr, zero, PyArray_DESCR(self)); @@ -142,7 +135,7 @@ PyArray_Resize(PyArrayObject *self, PyArray_Dims *newshape, int refcheck, Py_DECREF(zero); } else{ - memset(PyArray_BYTES(self)+oldsize*elsize, 0, (newsize-oldsize)*elsize); + memset(PyArray_BYTES(self) + oldnbytes, 0, newnbytes - oldnbytes); } } diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index 9703fdbb5..8ab2c97f5 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -1207,6 +1207,10 @@ class TestBool(object): class TestZeroSizeFlexible(object): @staticmethod def _zeros(shape, dtype=str): + dtype = np.dtype(dtype) + if dtype == np.void: + return np.zeros(shape, dtype=(dtype, 0)) + # not constructable directly dtype = np.dtype([('x', dtype, 0)]) return np.zeros(shape, dtype=dtype)['x'] @@ -1241,6 +1245,13 @@ class TestZeroSizeFlexible(object): def test_argpartition(self): self._test_sort_partition('argpartition', kinds=['introselect'], kth=2) + def test_resize(self): + # previously an error + for dt in [bytes, np.void, unicode]: + zs = self._zeros(10, dt) + zs.resize(25) + zs.resize((10, 10)) + class TestMethods(object): def test_compress(self): |