summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
Diffstat (limited to 'numpy')
-rw-r--r--numpy/core/include/numpy/arrayobject.h2
-rw-r--r--numpy/core/src/arrayobject.c40
-rw-r--r--numpy/core/tests/test_multiarray.py28
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')