summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
authorseberg <sebastian@sipsolutions.net>2013-01-06 02:40:54 -0800
committerseberg <sebastian@sipsolutions.net>2013-01-06 02:40:54 -0800
commit161bfe73e006af7c71db373aa99bdecce32f9e2a (patch)
treec2ed9a6b59f1d62821e2f2c809624c10da2d8090 /numpy
parent22ad3acca6cb4c029e544f6a060a864a0191087e (diff)
parent1981d0640d6a598a043379be43d19dcf590823f1 (diff)
downloadnumpy-161bfe73e006af7c71db373aa99bdecce32f9e2a.tar.gz
Merge pull request #2882 from seberg/issue2503
BUG: Fix CheckStrides and strides setter checks for available memory
Diffstat (limited to 'numpy')
-rw-r--r--numpy/core/src/multiarray/arrayobject.c21
-rw-r--r--numpy/core/src/multiarray/common.c30
-rw-r--r--numpy/core/src/multiarray/common.h5
-rw-r--r--numpy/core/src/multiarray/getset.c16
-rw-r--r--numpy/core/tests/test_multiarray.py24
5 files changed, 77 insertions, 19 deletions
diff --git a/numpy/core/src/multiarray/arrayobject.c b/numpy/core/src/multiarray/arrayobject.c
index 78afcc77f..10b750cdb 100644
--- a/numpy/core/src/multiarray/arrayobject.c
+++ b/numpy/core/src/multiarray/arrayobject.c
@@ -1464,20 +1464,23 @@ 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 lower_offset;
+ npy_intp upper_offset;
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;
- }
+ end = numbytes - offset;
+
+ offset_bounds_from_strides(elsize, nd, dims, newstrides,
+ &lower_offset, &upper_offset);
+
+ if ((upper_offset > end) || (lower_offset < begin)) {
+ return NPY_FALSE;
}
return NPY_TRUE;
}
diff --git a/numpy/core/src/multiarray/common.c b/numpy/core/src/multiarray/common.c
index 09b452f45..64ca352a5 100644
--- a/numpy/core/src/multiarray/common.c
+++ b/numpy/core/src/multiarray/common.c
@@ -674,3 +674,33 @@ _IsWriteable(PyArrayObject *ap)
}
return NPY_TRUE;
}
+
+
+NPY_NO_EXPORT void
+offset_bounds_from_strides(const int itemsize, const int nd,
+ const npy_intp *dims, const npy_intp *strides,
+ npy_intp *lower_offset, npy_intp *upper_offset) {
+ npy_intp max_axis_offset;
+ npy_intp lower = 0;
+ npy_intp upper = 0;
+ int i;
+
+ for (i = 0; i < nd; i++) {
+ if (dims[i] == 0) {
+ /* Empty array special case */
+ *lower_offset = 0;
+ *upper_offset = 0;
+ return;
+ }
+ max_axis_offset = strides[i] * (dims[i] - 1);
+ if (max_axis_offset > 0) {
+ upper += max_axis_offset;
+ }
+ else {
+ lower += max_axis_offset;
+ }
+ }
+ upper += itemsize;
+ *lower_offset = lower;
+ *upper_offset = upper;
+}
diff --git a/numpy/core/src/multiarray/common.h b/numpy/core/src/multiarray/common.h
index b68d4286b..a474cf820 100644
--- a/numpy/core/src/multiarray/common.h
+++ b/numpy/core/src/multiarray/common.h
@@ -57,6 +57,11 @@ _IsAligned(PyArrayObject *ap);
NPY_NO_EXPORT npy_bool
_IsWriteable(PyArrayObject *ap);
+NPY_NO_EXPORT void
+offset_bounds_from_strides(const int itemsize, const int nd,
+ const npy_intp *dims, const npy_intp *strides,
+ npy_intp *lower_offset, npy_intp *upper_offset);
+
#include "ucsnarrow.h"
#endif
diff --git a/numpy/core/src/multiarray/getset.c b/numpy/core/src/multiarray/getset.c
index 7788663be..6ad4cc13a 100644
--- a/numpy/core/src/multiarray/getset.c
+++ b/numpy/core/src/multiarray/getset.c
@@ -102,6 +102,8 @@ array_strides_set(PyArrayObject *self, PyObject *obj)
PyArrayObject *new;
npy_intp numbytes = 0;
npy_intp offset = 0;
+ npy_intp lower_offset = 0;
+ npy_intp upper_offset = 0;
Py_ssize_t buf_len;
char *buf;
@@ -136,13 +138,17 @@ 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);
+ offset_bounds_from_strides(PyArray_ITEMSIZE(new), PyArray_NDIM(new),
+ PyArray_DIMS(new), PyArray_STRIDES(new),
+ &lower_offset, &upper_offset);
+
+ offset = PyArray_BYTES(self) - (PyArray_BYTES(new) + lower_offset);
+ numbytes = upper_offset - lower_offset;
}
- if (!PyArray_CheckStrides(PyArray_DESCR(self)->elsize, PyArray_NDIM(self), numbytes,
- offset,
+ /* numbytes == 0 is special here, but the 0-size array case always works */
+ if (!PyArray_CheckStrides(PyArray_ITEMSIZE(self), PyArray_NDIM(self),
+ numbytes, offset,
PyArray_DIMS(self), 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 dfa5bb2b2..3d5bae220 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,20 @@ 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))
+
+ # Test for offset calculations:
+ x = np.lib.stride_tricks.as_strided(np.arange(10, dtype=np.int8)[-1],
+ shape=(10,), strides=(-1,))
+ self.assertRaises(ValueError, set_strides, x[::-1], -1)
+ a = x[::-1]
+ a.strides = 1
+ a[::2].strides = 2
def test_fill(self):
for t in "?bhilqpBHILQPfdgFDGO":