diff options
author | Marten van Kerkwijk <mhvk@astro.utoronto.ca> | 2018-01-01 18:24:00 -0500 |
---|---|---|
committer | Marten van Kerkwijk <mhvk@astro.utoronto.ca> | 2018-02-27 20:03:26 -0500 |
commit | 05a420af6504efa21f99f968b2c66de62c1668d7 (patch) | |
tree | 096e84317ef75dba1a15bd12fdf37e9cb1499f92 | |
parent | d525cc102f26026fd3b42bd73357203ca14dd14b (diff) | |
download | numpy-05a420af6504efa21f99f968b2c66de62c1668d7.tar.gz |
MAINT: Check operand sizes before doing anything with them
This ensures we do not have to guard against any operand having
fewer dimensions than required by the ufunc in, e.g.,
_parse_axes_argument.
-rw-r--r-- | numpy/core/src/umath/ufunc_object.c | 36 | ||||
-rw-r--r-- | numpy/core/tests/test_ufunc.py | 6 |
2 files changed, 25 insertions, 17 deletions
diff --git a/numpy/core/src/umath/ufunc_object.c b/numpy/core/src/umath/ufunc_object.c index 1ffecb1a6..bf5a4ead3 100644 --- a/numpy/core/src/umath/ufunc_object.c +++ b/numpy/core/src/umath/ufunc_object.c @@ -1960,19 +1960,6 @@ _get_coredim_sizes(PyUFuncObject *ufunc, PyArrayObject **op, int dim_offset = ufunc->core_offsets[i]; int num_dims = ufunc->core_num_dims[i]; int core_start_dim = PyArray_NDIM(op[i]) - num_dims; - - /* Check if operands have enough dimensions */ - if (core_start_dim < 0) { - PyErr_Format(PyExc_ValueError, - "%s: %s operand %d does not have enough " - "dimensions (has %d, gufunc core with " - "signature %s requires %d)", - ufunc_get_name_cstr(ufunc), i < nin ? "Input" : "Output", - i < nin ? i : i - nin, PyArray_NDIM(op[i]), - ufunc->core_signature, num_dims); - return -1; - } - /* * Make sure every core dimension exactly matches all other core * dimensions with the same label. @@ -2162,6 +2149,24 @@ PyUFunc_GeneralizedFunction(PyUFuncObject *ufunc, } /* + * Check that operands have the minimum dimensions required. + * (Just checks core; broadcast dimensions are tested by the iterator.) + */ + for (i = 0; i < nop; i++) { + if (op[i] != NULL && PyArray_NDIM(op[i]) < ufunc->core_num_dims[i]) { + PyErr_Format(PyExc_ValueError, + "%s: %s operand %d does not have enough " + "dimensions (has %d, gufunc core with " + "signature %s requires %d)", + ufunc_get_name_cstr(ufunc), + i < nin ? "Input" : "Output", + i < nin ? i : i - nin, PyArray_NDIM(op[i]), + ufunc->core_signature, ufunc->core_num_dims[i]); + goto fail; + } + } + + /* * Figure out the number of iteration dimensions, which * is the broadcast result of all the input non-core * dimensions. @@ -2194,9 +2199,6 @@ PyUFunc_GeneralizedFunction(PyUFuncObject *ufunc, /* Possibly remap axes. */ if (axes) { - /* - * possibly remap axes, using newly allocated memory. - */ remap_axis = PyArray_malloc(sizeof(remap_axis[0]) * nop); remap_axis_memory = PyArray_malloc(sizeof(remap_axis_memory[0]) * nop * NPY_MAXDIMS); @@ -2212,7 +2214,7 @@ PyUFunc_GeneralizedFunction(PyUFuncObject *ufunc, if(retval < 0) { goto fail; } - } /* end of if(axis) */ + } /* Collect the lengths of the labelled core dimensions */ retval = _get_coredim_sizes(ufunc, op, core_dim_sizes, remap_axis); diff --git a/numpy/core/tests/test_ufunc.py b/numpy/core/tests/test_ufunc.py index 239e8bc64..7e1bfbdbe 100644 --- a/numpy/core/tests/test_ufunc.py +++ b/numpy/core/tests/test_ufunc.py @@ -689,6 +689,12 @@ class TestUfunc(object): assert_raises(TypeError, mm, a, b, axes=[(-2, -1), (-2, -1), None]) # tuples should not have duplicated values assert_raises(ValueError, mm, a, b, axes=[(-2, -1), (-2, -1), (-2, -2)]) + # arrays should have enough axes. + z = np.zeros((2, 2)) + assert_raises(ValueError, mm, z, z[0]) + assert_raises(ValueError, mm, z, z, out=z[:, 0]) + assert_raises(ValueError, mm, z[1], z, axes=[0, 1]) + assert_raises(ValueError, mm, z, z, out=z[0], axes=[0, 1]) def test_innerwt(self): a = np.arange(6).reshape((2, 3)) |