[pypy-commit] pypy default: check strides, shape agains buf_len when creating array with a buffer
mattip
noreply at buildbot.pypy.org
Tue Dec 2 18:15:11 CET 2014
Author: mattip <matti.picus at gmail.com>
Branch:
Changeset: r74785:46e91c62f6b8
Date: 2014-12-02 19:13 +0200
http://bitbucket.org/pypy/pypy/changeset/46e91c62f6b8/
Log: check strides, shape agains buf_len when creating array with a
buffer
diff --git a/pypy/module/micronumpy/base.py b/pypy/module/micronumpy/base.py
--- a/pypy/module/micronumpy/base.py
+++ b/pypy/module/micronumpy/base.py
@@ -1,7 +1,7 @@
from pypy.interpreter.baseobjspace import W_Root
-from pypy.interpreter.error import OperationError
+from pypy.interpreter.error import OperationError, oefmt
from rpython.tool.pairtype import extendabletype
-
+from pypy.module.micronumpy import support
def wrap_impl(space, w_cls, w_instance, impl):
if w_cls is None or space.is_w(w_cls, space.gettypefor(W_NDimArray)):
@@ -44,15 +44,31 @@
return W_NDimArray(impl)
@staticmethod
- def from_shape_and_storage(space, shape, storage, dtype, order='C',
- owning=False, w_subtype=None, w_base=None,
- writable=True, strides=None):
+ def from_shape_and_storage(space, shape, storage, dtype, storage_bytes=-1,
+ order='C', owning=False, w_subtype=None,
+ w_base=None, writable=True, strides=None):
from pypy.module.micronumpy import concrete
from pypy.module.micronumpy.strides import (calc_strides,
calc_backstrides)
+ isize = dtype.elsize
+ if storage_bytes > 0 :
+ totalsize = support.product(shape) * isize
+ if totalsize > storage_bytes:
+ raise OperationError(space.w_TypeError, space.wrap(
+ "buffer is too small for requested array"))
+ else:
+ storage_bytes = support.product(shape) * isize
if strides is None:
strides, backstrides = calc_strides(shape, dtype, order)
else:
+ if len(strides) != len(shape):
+ raise oefmt(space.w_ValueError,
+ 'strides, if given, must be the same length as shape')
+ for i in range(len(strides)):
+ if strides[i] < 0 or strides[i]*shape[i] > storage_bytes:
+ raise oefmt(space.w_ValueError,
+ 'strides is incompatible with shape of requested '
+ 'array and size of buffer')
backstrides = calc_backstrides(strides, shape)
if w_base is not None:
if owning:
diff --git a/pypy/module/micronumpy/ctors.py b/pypy/module/micronumpy/ctors.py
--- a/pypy/module/micronumpy/ctors.py
+++ b/pypy/module/micronumpy/ctors.py
@@ -302,5 +302,5 @@
return a
else:
writable = not buf.readonly
- return W_NDimArray.from_shape_and_storage(space, [n], storage, dtype=dtype,
- w_base=w_buffer, writable=writable)
+ return W_NDimArray.from_shape_and_storage(space, [n], storage, storage_bytes=s,
+ dtype=dtype, w_base=w_buffer, writable=writable)
diff --git a/pypy/module/micronumpy/ndarray.py b/pypy/module/micronumpy/ndarray.py
--- a/pypy/module/micronumpy/ndarray.py
+++ b/pypy/module/micronumpy/ndarray.py
@@ -529,9 +529,10 @@
"__array__(dtype) not implemented"))
if type(self) is W_NDimArray:
return self
+ sz = support.product(self.get_shape()) * self.get_dtype().elsize
return W_NDimArray.from_shape_and_storage(
space, self.get_shape(), self.implementation.storage,
- self.get_dtype(), w_base=self)
+ self.get_dtype(), storage_bytes=sz, w_base=self)
def descr_array_iface(self, space):
addr = self.implementation.get_storage_as_int(space)
@@ -1188,8 +1189,8 @@
"improper dtype '%R'", dtype)
self.implementation = W_NDimArray.from_shape_and_storage(
space, [space.int_w(i) for i in space.listview(shape)],
- rffi.str2charp(space.str_w(storage), track_allocation=False),
- dtype, owning=True).implementation
+ rffi.str2charp(space.str_w(storage), track_allocation=False),
+ dtype, storage_bytes=space.len_w(storage), owning=True).implementation
def descr___array_finalize__(self, space, w_obj):
pass
@@ -1230,15 +1231,12 @@
if not shape:
raise OperationError(space.w_TypeError, space.wrap(
"numpy scalars from buffers not supported yet"))
- totalsize = support.product(shape) * dtype.elsize
- if totalsize + offset > buf.getlength():
- raise OperationError(space.w_TypeError, space.wrap(
- "buffer is too small for requested array"))
storage = rffi.cast(RAW_STORAGE_PTR, raw_ptr)
storage = rffi.ptradd(storage, offset)
- return W_NDimArray.from_shape_and_storage(space, shape, storage, dtype,
+ return W_NDimArray.from_shape_and_storage(space, shape, storage,
+ dtype, w_base=w_buffer,
+ storage_bytes=buf.getlength()-offset,
w_subtype=w_subtype,
- w_base=w_buffer,
writable=not buf.readonly,
strides=strides)
@@ -1258,9 +1256,12 @@
return w_ret
- at unwrap_spec(addr=int)
-def descr__from_shape_and_storage(space, w_cls, w_shape, addr, w_dtype, w_subtype=None, w_strides=None):
+ at unwrap_spec(addr=int, buf_len=int)
+def descr__from_shape_and_storage(space, w_cls, w_shape, addr, w_dtype,
+ buf_len=-1, w_subtype=None, w_strides=None):
"""
+ _from_shape_and_storage(shape, addr, dtype, buf_len,
+ subtype=None, strides=None)
Create an array from an existing buffer, given its address as int.
PyPy-only implementation detail.
"""
@@ -1278,10 +1279,11 @@
raise OperationError(space.w_ValueError, space.wrap(
"subtype must be a subtype of ndarray, not a class instance"))
return W_NDimArray.from_shape_and_storage(space, shape, storage, dtype,
- 'C', False, w_subtype,
+ buf_len, 'C', False, w_subtype,
strides=strides)
else:
return W_NDimArray.from_shape_and_storage(space, shape, storage, dtype,
+ storage_bytes=buf_len,
strides=strides)
app_take = applevel(r"""
diff --git a/pypy/module/micronumpy/test/test_ndarray.py b/pypy/module/micronumpy/test/test_ndarray.py
--- a/pypy/module/micronumpy/test/test_ndarray.py
+++ b/pypy/module/micronumpy/test/test_ndarray.py
@@ -186,7 +186,8 @@
#
dtypes = get_dtype_cache(self.space)
w_array = W_NDimArray.from_shape_and_storage(self.space, [2, 2],
- storage, dtypes.w_int8dtype)
+ storage, dtypes.w_int8dtype,
+ storage_bytes=4)
def get(i, j):
return w_array.getitem(self.space, [i, j]).value
assert get(0, 0) == 0
@@ -3423,8 +3424,12 @@
assert a[1] == 2
a = ndarray((4,), buffer=base, dtype=int, strides=[base.strides[0]])
assert a[1] == 2
- a = ndarray((4,), buffer=base, dtype=int, strides=[2 * base.strides[0]])
+ a = ndarray((2,), buffer=base, dtype=int, strides=[2 * base.strides[0]])
assert a[1] == 3
+ exc = raises(ValueError, ndarray, (4,), buffer=base, dtype=int, strides=[2 * base.strides[0]])
+ assert exc.value[0] == 'strides is incompatible with shape of requested array and size of buffer'
+ exc = raises(ValueError, ndarray, (2, 1), buffer=base, dtype=int, strides=[base.strides[0]])
+ assert exc.value[0] == 'strides, if given, must be the same length as shape'
@@ -3918,13 +3923,14 @@
from numpypy import array, ndarray
x = array([1, 2, 3, 4])
addr, _ = x.__array_interface__['data']
- y = ndarray._from_shape_and_storage([2, 2], addr, x.dtype)
+ sz = x.size * x.dtype.itemsize
+ y = ndarray._from_shape_and_storage([2, 2], addr, x.dtype, sz)
assert y[0, 1] == 2
y[0, 1] = 42
assert x[1] == 42
class C(ndarray):
pass
- z = ndarray._from_shape_and_storage([4, 1], addr, x.dtype, C)
+ z = ndarray._from_shape_and_storage([4, 1], addr, x.dtype, sz, C)
assert isinstance(z, C)
assert z.shape == (4, 1)
assert z[1, 0] == 42
@@ -3943,11 +3949,12 @@
from numpy import ndarray, array
base = array([1, 2, 3, 4], dtype=int)
addr, _ = base.__array_interface__['data']
- a = ndarray._from_shape_and_storage((4,), addr, int)
+ sz = base.size * base.dtype.itemsize
+ a = ndarray._from_shape_and_storage((4,), addr, int, sz)
assert a[1] == 2
- a = ndarray._from_shape_and_storage((4,), addr, int,
+ a = ndarray._from_shape_and_storage((4,), addr, int, sz,
strides=[base.strides[0]])
assert a[1] == 2
- a = ndarray._from_shape_and_storage((4,), addr, int,
+ a = ndarray._from_shape_and_storage((2,), addr, int, sz,
strides=[2 * base.strides[0]])
assert a[1] == 3
More information about the pypy-commit
mailing list