[pypy-commit] cffi default: Workaround: allow out-of-bound array indexes if the array is 'type[0]'.
arigo
noreply at buildbot.pypy.org
Sun Aug 5 09:44:46 CEST 2012
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r784:0d5efadab0ac
Date: 2012-08-05 09:44 +0200
http://bitbucket.org/cffi/cffi/changeset/0d5efadab0ac/
Log: Workaround: allow out-of-bound array indexes if the array is
'type[0]'.
diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -1388,7 +1388,7 @@
"negative index not supported");
return NULL;
}
- if (i >= get_array_length(cd)) {
+ if (i >= get_array_length(cd) && cd->c_type->ct_length != 0) {
PyErr_Format(PyExc_IndexError,
"index too large for cdata '%s' (expected %zd < %zd)",
cd->c_type->ct_name,
diff --git a/c/test_c.py b/c/test_c.py
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -1837,3 +1837,16 @@
if not py_py:
assert repr(x).endswith("E+902>")
assert float(x) == float("inf")
+
+def test_array_of_length_zero():
+ p = new_pointer_type(new_primitive_type("int"))
+ p0 = new_array_type(p, 0)
+ p3 = new_array_type(p, 3)
+ a1 = newp(p3, [61, 62, 63])
+ a2 = cast(p0, a1)
+ assert a2[0] == 61
+ assert a2[1] == 62
+ assert a2[2] == 63
+ a2[2] = 64
+ assert list(a1) == [61, 62, 64]
+ assert list(a2) == []
diff --git a/cffi/backend_ctypes.py b/cffi/backend_ctypes.py
--- a/cffi/backend_ctypes.py
+++ b/cffi/backend_ctypes.py
@@ -583,14 +583,22 @@
return len(self._blob)
def __getitem__(self, index):
- if not (0 <= index < len(self._blob)):
+ if 0 <= index < len(self._blob):
+ x = self._blob[index]
+ elif len(self._blob) == 0:
+ x = ctypes.cast(self._blob, CTypesPtr._ctype)[index]
+ else:
raise IndexError
- return BItem._from_ctypes(self._blob[index])
+ return BItem._from_ctypes(x)
def __setitem__(self, index, value):
- if not (0 <= index < len(self._blob)):
+ x = BItem._to_ctypes(value)
+ if 0 <= index < len(self._blob):
+ self._blob[index] = x
+ elif len(self._blob) == 0:
+ ctypes.cast(self._blob, CTypesPtr._ctype)[index] = x
+ else:
raise IndexError
- self._blob[index] = BItem._to_ctypes(value)
if kind == 'char' or kind == 'byte':
def _to_string(self, maxlen):
diff --git a/doc/source/index.rst b/doc/source/index.rst
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -919,6 +919,11 @@
* Thread-local variables (access them via getter/setter functions)
+* Variable-length structures, i.e. whose last field is a variable-length
+ array (work around like in C, e.g. by declaring it as an array of
+ length 0, allocating a ``char[]`` of the correct size, and casting
+ it to a struct pointer)
+
Reference: conversions
----------------------
diff --git a/testing/backend_tests.py b/testing/backend_tests.py
--- a/testing/backend_tests.py
+++ b/testing/backend_tests.py
@@ -144,7 +144,8 @@
assert repr(p) == "<cdata 'int[]' owning %d bytes>" % (2*SIZE_OF_INT)
#
p = ffi.new("int[]", 0)
- py.test.raises(IndexError, "p[0]")
+ #py.test.raises(IndexError, "p[0]") ---
+ # actually works, for test_struct_containing_array_varsize_workaround
py.test.raises(ValueError, ffi.new, "int[]", -1)
assert repr(p) == "<cdata 'int[]' owning 0 bytes>"
@@ -1121,6 +1122,16 @@
f.close()
os.unlink(filename)
+ def test_struct_containing_array_varsize_workaround(self):
+ ffi = FFI(backend=self.Backend())
+ ffi.cdef("struct foo_s { int len; short data[0]; };")
+ p = ffi.new("char[]", ffi.sizeof("struct foo_s") + 7 * SIZE_OF_SHORT)
+ q = ffi.cast("struct foo_s *", p)
+ assert q.len == 0
+ assert q.data[6] == 0
+ q.data[6] = 15
+ assert q.data[6] == 15
+
def test_new_struct_containing_array_varsize(self):
py.test.skip("later?")
ffi = FFI(backend=self.Backend())
More information about the pypy-commit
mailing list