diff options
Diffstat (limited to 'numpy')
-rw-r--r-- | numpy/core/include/numpy/arrayobject.h | 2 | ||||
-rw-r--r-- | numpy/core/src/arrayobject.c | 40 | ||||
-rw-r--r-- | numpy/core/tests/test_multiarray.py | 28 |
3 files changed, 61 insertions, 9 deletions
diff --git a/numpy/core/include/numpy/arrayobject.h b/numpy/core/include/numpy/arrayobject.h index d5eb9aacb..30a804807 100644 --- a/numpy/core/include/numpy/arrayobject.h +++ b/numpy/core/include/numpy/arrayobject.h @@ -74,7 +74,7 @@ extern "C" { #define PY_SUCCEED 1 /* Helpful to distinguish what is installed */ -#define NDARRAY_VERSION 0x00090403 +#define NDARRAY_VERSION 0x00090404 /* Some platforms don't define bool, long long, or long double. Handle that here. diff --git a/numpy/core/src/arrayobject.c b/numpy/core/src/arrayobject.c index 6f60f6cf0..961304e68 100644 --- a/numpy/core/src/arrayobject.c +++ b/numpy/core/src/arrayobject.c @@ -3514,10 +3514,15 @@ PyArray_UpdateFlags(PyArrayObject *ret, int flagmask) walk outside of the memory implied by a single segment array of the provided dimensions and element size. If numbytes is 0 it will be calculated from the provided shape and element size. + + For axes with a positive stride this function checks for a walk + beyond the right end of the buffer, for axes with a negative stride, + it checks for a walk beyond the left end of the buffer. Zero strides + are disallowed. */ /*OBJECT_API*/ static Bool -PyArray_CheckStrides(int elsize, int nd, intp numbytes, +PyArray_CheckStrides(int elsize, int nd, intp numbytes, intp offset, intp *dims, intp *newstrides) { int i; @@ -3526,7 +3531,27 @@ PyArray_CheckStrides(int elsize, int nd, intp numbytes, numbytes = PyArray_MultiplyList(dims, nd) * elsize; for (i=0; i<nd; i++) { - if (newstrides[i]*(dims[i]-1)+elsize > numbytes) { + intp stride = newstrides[i]; + if (stride > 0) { + /* The last stride does not need to be fully inside + the buffer, only its first elsize bytes */ + if (offset + stride*(dims[i]-1)+elsize > numbytes) { + return FALSE; + } + } + else if (stride < 0) { + if (offset + stride*dims[i] < 0) { + return FALSE; + } + } else { + /* XXX: Zero strides may be useful, but currently + XXX: allowing them would lead to strange results, + XXX: for example : + XXX: >>> x = arange(5) + XXX: >>> x.strides = 0 + XXX: >>> x += 1 + XXX: >>> x + XXX: array([5, 5, 5, 5, 5]) */ return FALSE; } } @@ -4064,10 +4089,8 @@ array_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds) } } else { /* buffer given -- use it */ - buffer.len -= offset; - buffer.ptr += offset; if (dims.len == 1 && dims.ptr[0] == -1) { - dims.ptr[0] = buffer.len / itemsize; + dims.ptr[offset] = buffer.len / itemsize; } else if (buffer.len < itemsize* \ PyArray_MultiplyList(dims.ptr, dims.len)) { @@ -4084,7 +4107,7 @@ array_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds) goto fail; } if (!PyArray_CheckStrides(itemsize, strides.len, - buffer.len, + buffer.len, offset, dims.ptr, strides.ptr)) { PyErr_SetString(PyExc_ValueError, "strides is incompatible "\ @@ -4104,7 +4127,7 @@ array_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds) PyArray_NewFromDescr(subtype, descr, dims.len, dims.ptr, strides.ptr, - (char *)buffer.ptr, + offset + (char *)buffer.ptr, buffer.flags, NULL); if (ret == NULL) {descr=NULL; goto fail;} PyArray_UpdateFlags(ret, UPDATE_ALL_FLAGS); @@ -4222,7 +4245,8 @@ array_strides_set(PyArrayObject *self, PyObject *obj) numbytes = PyArray_MultiplyList(new->dimensions, new->nd)*new->descr->elsize; - if (!PyArray_CheckStrides(self->descr->elsize, self->nd, numbytes, + if (!PyArray_CheckStrides(self->descr->elsize, self->nd, numbytes, + self->data - new->data, self->dimensions, newstrides.ptr)) { PyErr_SetString(PyExc_ValueError, "strides is not "\ "compatible with available memory"); diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index bf593c845..70c978cbc 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -62,6 +62,34 @@ class test_attributes(ScipyTestCase): assert_equal(self.one.dtype.str[1], 'i') assert_equal(self.three.dtype.str[1], 'f') + def check_stridesattr(self): + x = self.one + def make_array(size, offset, strides): + return ndarray([size], buffer=x, + offset=offset*x.itemsize, + strides=strides*x.itemsize) + assert_equal(make_array(4, 4, -1), array([4, 3, 2, 1])) + self.failUnlessRaises(ValueError, make_array, 4, 4, -2) + self.failUnlessRaises(ValueError, make_array, 4, 3, -1) + self.failUnlessRaises(ValueError, make_array, 8, 3, 1) + self.failUnlessRaises(ValueError, make_array, 8, 3, 0) + + def check_set_stridesattr(self): + x = self.one + def make_array(size, offset, strides): + try: + r = ndarray([size], buffer=x, offset=offset*x.itemsize) + except: + pass + r.strides = strides=strides*x.itemsize + return r + assert_equal(make_array(4, 4, -1), array([4, 3, 2, 1])) + self.failUnlessRaises(ValueError, make_array, 4, 4, -2) + self.failUnlessRaises(ValueError, make_array, 4, 3, -1) + self.failUnlessRaises(ValueError, make_array, 8, 3, 1) + self.failUnlessRaises(ValueError, make_array, 8, 3, 0) + + class test_dtypedescr(ScipyTestCase): def check_construction(self): d1 = dtype('i4') |