diff options
Diffstat (limited to 'numpy')
| -rw-r--r-- | numpy/core/src/multiarray/ctors.c | 127 | ||||
| -rw-r--r-- | numpy/core/tests/test_multiarray.py | 10 |
2 files changed, 71 insertions, 66 deletions
diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c index 7907fb930..671ce49e4 100644 --- a/numpy/core/src/multiarray/ctors.c +++ b/numpy/core/src/multiarray/ctors.c @@ -665,13 +665,11 @@ PyArray_NewFromDescr_int( int allow_emptystring) { PyArrayObject_fields *fa; - int i; npy_intp nbytes; - if ((unsigned int)nd > (unsigned int)NPY_MAXDIMS) { + if (nd > NPY_MAXDIMS || nd < 0) { PyErr_Format(PyExc_ValueError, - "number of dimensions must be within [0, %d]", - NPY_MAXDIMS); + "number of dimensions must be within [0, %d]", NPY_MAXDIMS); Py_DECREF(descr); return NULL; } @@ -718,39 +716,6 @@ PyArray_NewFromDescr_int( } } - /* Check dimensions and multiply them to nbytes */ - for (i = 0; i < nd; i++) { - npy_intp dim = dims[i]; - - if (dim == 0) { - /* - * Compare to PyArray_OverflowMultiplyList that - * returns 0 in this case. - */ - continue; - } - - if (dim < 0) { - PyErr_SetString(PyExc_ValueError, - "negative dimensions are not allowed"); - Py_DECREF(descr); - return NULL; - } - - /* - * Care needs to be taken to avoid integer overflow when - * multiplying the dimensions together to get the total size of the - * array. - */ - if (npy_mul_with_overflow_intp(&nbytes, nbytes, dim)) { - PyErr_SetString(PyExc_ValueError, - "array is too big; `arr.size * arr.dtype.itemsize` " - "is larger than the maximum possible size."); - Py_DECREF(descr); - return NULL; - } - } - fa = (PyArrayObject_fields *) subtype->tp_alloc(subtype, 0); if (fa == NULL) { Py_DECREF(descr); @@ -786,26 +751,57 @@ PyArray_NewFromDescr_int( goto fail; } fa->strides = fa->dimensions + nd; - if (nd) { - memcpy(fa->dimensions, dims, sizeof(npy_intp)*nd); + + /* Copy dimensions, check them, and find total array size `nbytes` */ + for (int i = 0; i < nd; i++) { + fa->dimensions[i] = dims[i]; + + if (fa->dimensions[i] == 0) { + /* + * Compare to PyArray_OverflowMultiplyList that + * returns 0 in this case. + */ + continue; + } + + if (fa->dimensions[i] < 0) { + PyErr_SetString(PyExc_ValueError, + "negative dimensions are not allowed"); + goto fail; + } + + /* + * Care needs to be taken to avoid integer overflow when multiplying + * the dimensions together to get the total size of the array. + */ + if (npy_mul_with_overflow_intp(&nbytes, nbytes, fa->dimensions[i])) { + PyErr_SetString(PyExc_ValueError, + "array is too big; `arr.size * arr.dtype.itemsize` " + "is larger than the maximum possible size."); + goto fail; + } } - if (strides == NULL) { /* fill it in */ + + /* Fill the strides (or copy them if they were passed in) */ + if (strides == NULL) { + /* fill the strides and set the contiguity flags */ _array_fill_strides(fa->strides, dims, nd, descr->elsize, flags, &(fa->flags)); } else { - /* - * we allow strides even when we create - * the memory, but be careful with this... - */ - if (nd) { - memcpy(fa->strides, strides, sizeof(npy_intp)*nd); + /* User to provided strides (user is responsible for correctness) */ + for (int i = 0; i < nd; i++) { + fa->strides[i] = strides[i]; } + /* Since the strides were passed in must update contiguity */ + PyArray_UpdateFlags((PyArrayObject *)fa, + NPY_ARRAY_C_CONTIGUOUS|NPY_ARRAY_F_CONTIGUOUS); } } else { - fa->dimensions = fa->strides = NULL; - fa->flags |= NPY_ARRAY_F_CONTIGUOUS; + fa->dimensions = NULL; + fa->strides = NULL; + fa->flags |= NPY_ARRAY_C_CONTIGUOUS|NPY_ARRAY_F_CONTIGUOUS; } if (data == NULL) { @@ -844,12 +840,11 @@ PyArray_NewFromDescr_int( fa->data = data; /* - * always update the flags to get the right CONTIGUOUS, ALIGN properties - * not owned data and input strides may not be aligned and on some - * platforms (debian sparc) malloc does not provide enough alignment for - * long double types + * Always update the aligned flag. Not owned data or input strides may + * not be aligned. Also on some platforms (debian sparc) malloc does not + * provide enough alignment for long double types. */ - PyArray_UpdateFlags((PyArrayObject *)fa, NPY_ARRAY_UPDATE_ALL); + PyArray_UpdateFlags((PyArrayObject *)fa, NPY_ARRAY_ALIGNED); /* Set the base object. It's important to do it here so that * __array_finalize__ below receives it @@ -862,15 +857,20 @@ PyArray_NewFromDescr_int( } /* - * call the __array_finalize__ - * method if a subtype. - * If obj is NULL, then call method with Py_None + * call the __array_finalize__ method if a subtype was requested. + * If obj is NULL use Py_None for the Python callback. */ - if ((subtype != &PyArray_Type)) { - PyObject *res, *func, *args; + if (subtype != &PyArray_Type) { + PyObject *res, *func; func = PyObject_GetAttr((PyObject *)fa, npy_ma_str_array_finalize); - if (func && func != Py_None) { + if (func == NULL) { + goto fail; + } + else if (func == Py_None) { + Py_DECREF(func); + } + else { if (PyCapsule_CheckExact(func)) { /* A C-function is stored here */ PyArray_FinalizeFunc *cfunc; @@ -884,14 +884,10 @@ PyArray_NewFromDescr_int( } } else { - args = PyTuple_New(1); if (obj == NULL) { - obj=Py_None; + obj = Py_None; } - Py_INCREF(obj); - PyTuple_SET_ITEM(args, 0, obj); - res = PyObject_Call(func, args, NULL); - Py_DECREF(args); + res = PyObject_CallFunctionObjArgs(func, obj, NULL); Py_DECREF(func); if (res == NULL) { goto fail; @@ -901,7 +897,6 @@ PyArray_NewFromDescr_int( } } } - else Py_XDECREF(func); } return (PyObject *)fa; diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index 5c91cb9ea..d567653f5 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -5982,6 +5982,7 @@ class TestStats: res = dat.var(1) assert_(res.info == dat.info) + class TestVdot: def test_basic(self): dt_numeric = np.typecodes['AllFloat'] + np.typecodes['AllInteger'] @@ -8700,6 +8701,15 @@ class TestArrayFinalize: a = np.array(1).view(SavesBase) assert_(a.saved_base is a.base) + def test_bad_finalize(self): + class BadAttributeArray(np.ndarray): + @property + def __array_finalize__(self): + raise RuntimeError("boohoo!") + + with pytest.raises(RuntimeError, match="boohoo!"): + np.arange(10).view(BadAttributeArray) + def test_lifetime_on_error(self): # gh-11237 class RaisesInFinalize(np.ndarray): |
