summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
authorSebastian Berg <sebastian@sipsolutions.net>2013-01-03 16:42:48 +0100
committerSebastian Berg <sebastian@sipsolutions.net>2013-01-03 17:40:00 +0100
commit2be873f9590d1c68f8cf2357cd0a1c72bd5874ed (patch)
tree573e2fadf7e7da2d1dd1332f8bc49d64d9cc824c /numpy
parentc74586282e4598e70b9b2473ee987785e2a61477 (diff)
downloadnumpy-2be873f9590d1c68f8cf2357cd0a1c72bd5874ed.tar.gz
BUG: Fix CheckStrides and strides setter checks for available memory
This changes the logic of PyArray_CheckStrides to really check the full extent the new array will have. It also changes the stride setting to calculate the full real extent of the underlying array without assuming (usually correctly) that the strides of the base array are regular. Add some tests for cases that previously failed. This "closes Issue gh-2503"
Diffstat (limited to 'numpy')
-rw-r--r--numpy/core/src/multiarray/arrayobject.c26
-rw-r--r--numpy/core/src/multiarray/getset.c28
-rw-r--r--numpy/core/tests/test_multiarray.py16
3 files changed, 55 insertions, 15 deletions
diff --git a/numpy/core/src/multiarray/arrayobject.c b/numpy/core/src/multiarray/arrayobject.c
index 78afcc77f..a7f3e8d4b 100644
--- a/numpy/core/src/multiarray/arrayobject.c
+++ b/numpy/core/src/multiarray/arrayobject.c
@@ -1464,20 +1464,34 @@ PyArray_CheckStrides(int elsize, int nd, npy_intp numbytes, npy_intp offset,
npy_intp *dims, npy_intp *newstrides)
{
int i;
- npy_intp byte_begin;
- npy_intp begin;
- npy_intp end;
+ npy_intp max_axis_offset;
+ npy_intp begin, end;
+ npy_intp min_offset = 0;
+ npy_intp max_offset = 0;
if (numbytes == 0) {
numbytes = PyArray_MultiplyList(dims, nd) * elsize;
}
+
begin = -offset;
end = numbytes - offset - elsize;
for (i = 0; i < nd; i++) {
- byte_begin = newstrides[i]*(dims[i] - 1);
- if ((byte_begin < begin) || (byte_begin > end)) {
- return NPY_FALSE;
+ if (dims[i] == 0) {
+ /* Empty array. Validate offset in any case */
+ max_offset = 0;
+ min_offset = 0;
+ break;
+ }
+ max_axis_offset = newstrides[i] * (dims[i] - 1);
+ if (max_axis_offset > 0) {
+ max_offset += max_axis_offset;
}
+ else {
+ min_offset += max_axis_offset;
+ }
+ }
+ if ((max_offset > end) || (min_offset < begin)) {
+ return NPY_FALSE;
}
return NPY_TRUE;
}
diff --git a/numpy/core/src/multiarray/getset.c b/numpy/core/src/multiarray/getset.c
index 95830a625..4cd31d8bf 100644
--- a/numpy/core/src/multiarray/getset.c
+++ b/numpy/core/src/multiarray/getset.c
@@ -102,7 +102,11 @@ array_strides_set(PyArrayObject *self, PyObject *obj)
PyArrayObject *new;
npy_intp numbytes = 0;
npy_intp offset = 0;
+ npy_intp max_axis_offset;
+ npy_intp min_offset = 0;
+ npy_intp max_offset = 0;
Py_ssize_t buf_len;
+ int i;
char *buf;
if (obj == NULL) {
@@ -136,12 +140,28 @@ array_strides_set(PyArrayObject *self, PyObject *obj)
}
else {
PyErr_Clear();
- numbytes = PyArray_MultiplyList(PyArray_DIMS(new),
- PyArray_NDIM(new))*PyArray_DESCR(new)->elsize;
- offset = PyArray_BYTES(self) - PyArray_BYTES(new);
+ /* Find the true extent of the base array, similar to CheckStrides */
+ for (i = 0; i < PyArray_NDIM(new); i++) {
+ if (PyArray_DIMS(new)[i] == 0) {
+ /* Since all arrays must be empty here, this works */
+ max_offset = 0;
+ min_offset = 0;
+ break;
+ }
+ max_axis_offset = PyArray_STRIDES(new)[i] * (PyArray_DIMS(new)[i] - 1);
+ if (max_axis_offset > 0) {
+ max_offset += max_axis_offset;
+ }
+ else {
+ min_offset += max_axis_offset;
+ }
+ }
+
+ offset = -min_offset + PyArray_BYTES(self) - PyArray_BYTES(new);
+ numbytes = max_offset - min_offset + PyArray_ITEMSIZE(new);
}
- if (!PyArray_CheckStrides(PyArray_DESCR(self)->elsize, PyArray_NDIM(self), numbytes,
+ if (!PyArray_CheckStrides(PyArray_ITEMSIZE(self), PyArray_NDIM(self), numbytes,
offset,
PyArray_DIMS(self), newstrides.ptr)) {
PyErr_SetString(PyExc_ValueError, "strides is not "\
diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py
index dfa5bb2b2..f2cab2904 100644
--- a/numpy/core/tests/test_multiarray.py
+++ b/numpy/core/tests/test_multiarray.py
@@ -97,16 +97,17 @@ class TestAttributes(TestCase):
def test_stridesattr(self):
x = self.one
def make_array(size, offset, strides):
- return ndarray([size], buffer=x, dtype=int,
+ return ndarray(size, buffer=x, dtype=int,
offset=offset*x.itemsize,
strides=strides*x.itemsize)
assert_equal(make_array(4, 4, -1), array([4, 3, 2, 1]))
self.assertRaises(ValueError, make_array, 4, 4, -2)
self.assertRaises(ValueError, make_array, 4, 2, -1)
self.assertRaises(ValueError, make_array, 8, 3, 1)
- #self.assertRaises(ValueError, make_array, 8, 3, 0)
- #self.assertRaises(ValueError, lambda: ndarray([1], strides=4))
-
+ assert_equal(make_array(8, 3, 0), np.array([3]*8))
+ # Check behavior reported in gh-2503:
+ self.assertRaises(ValueError, make_array, (2, 3), 5, array([-2, -3]))
+ make_array(0, 0, 10)
def test_set_stridesattr(self):
x = self.one
@@ -122,7 +123,12 @@ class TestAttributes(TestCase):
self.assertRaises(ValueError, make_array, 4, 4, -2)
self.assertRaises(ValueError, make_array, 4, 2, -1)
self.assertRaises(RuntimeError, make_array, 8, 3, 1)
- #self.assertRaises(ValueError, make_array, 8, 3, 0)
+ # Check that the true extent of the array is used.
+ # Test relies on as_strided base not exposing a buffer.
+ x = np.lib.stride_tricks.as_strided(arange(1), (10,10), (0,0))
+ def set_strides(arr, strides):
+ arr.strides = strides
+ self.assertRaises(ValueError, set_strides, x, (10*x.itemsize, x.itemsize))
def test_fill(self):
for t in "?bhilqpBHILQPfdgFDGO":