summaryrefslogtreecommitdiff
path: root/numpy/core
diff options
context:
space:
mode:
authorEric Wieser <wieser.eric@gmail.com>2017-04-22 14:54:54 +0100
committerEric Wieser <wieser.eric@gmail.com>2017-10-01 16:46:19 -0700
commit0e9e205c3b1d90dc6782bd21bb428d17aded0e90 (patch)
tree04fa3c3bbb088ee014364160a214370222567c0d /numpy/core
parenteb514b1c87d8d2c0e2ae159cf24046d490b2c448 (diff)
downloadpython-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.c43
-rw-r--r--numpy/core/tests/test_multiarray.py11
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):