[prev in list] [next in list] [prev in thread] [next in thread]
List: pypy-svn
Subject: [pypy-commit] cffi default: Fix: the condition "offsetof == sizeof" for being a var-sized array
From: arigo <pypy.commits () gmail ! com>
Date: 2016-10-29 14:00:27
Message-ID: 5814ab7b.0d8d1c0a.28d05.8da4 () mx ! google ! com
[Download RAW message or body]
Author: Armin Rigo <arigo@tunes.org>
Branch:
Changeset: r2802:d1bbb5f82640
Date: 2016-10-29 15:57 +0200
http://bitbucket.org/cffi/cffi/changeset/d1bbb5f82640/
Log: Fix: the condition "offsetof == sizeof" for being a var-sized array
is bogus. See test for a case where it is not the case because of
alignment.
diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -2431,6 +2431,7 @@
if (cf != NULL) {
/* read the field 'cf' */
char *data = cd->c_data + cf->cf_offset;
+ Py_ssize_t array_len, size;
if (cf->cf_bitshift == BS_REGULAR) {
return convert_to_object(data, cf->cf_type);
@@ -2439,16 +2440,13 @@
return convert_to_object_bitfield(data, cf);
}
- if (cf->cf_offset == ct->ct_size) {
- /* variable-length array */
- /* if reading variable length array from variable length
- struct, calculate array type from allocated length */
- Py_ssize_t array_len, size = _cdata_var_byte_size(cd);
- size -= ct->ct_size;
- if (size >= 0) {
- array_len = size / cf->cf_type->ct_itemdescr->ct_size;
- return new_sized_cdata(data, cf->cf_type, array_len);
- }
+ /* variable-length array: */
+ /* if reading variable length array from variable length
+ struct, calculate array type from allocated length */
+ size = _cdata_var_byte_size(cd) - cf->cf_offset;
+ if (size >= 0) {
+ array_len = size / cf->cf_type->ct_itemdescr->ct_size;
+ return new_sized_cdata(data, cf->cf_type, array_len);
}
return new_simple_cdata(data,
(CTypeDescrObject *)cf->cf_type->ct_stuff);
@@ -5489,7 +5487,9 @@
if (cd->c_type->ct_flags & CT_ARRAY)
size = get_array_length(cd) * cd->c_type->ct_itemdescr->ct_size;
else {
- size = _cdata_var_byte_size(cd);
+ size = -1;
+ if (cd->c_type->ct_flags & (CT_STRUCT | CT_UNION))
+ size = _cdata_var_byte_size(cd);
if (size < 0)
size = cd->c_type->ct_size;
}
diff --git a/c/test_c.py b/c/test_c.py
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -3299,6 +3299,33 @@
assert p.x[5] == 60
assert p.x[6] == 70
+def test_struct_array_not_aligned():
+ # struct a { int x; char y; char z[]; };
+ # ends up of size 8, but 'z' is at offset 5
+ BChar = new_primitive_type("char")
+ BInt = new_primitive_type("int")
+ BCharP = new_pointer_type(BChar)
+ BArray = new_array_type(BCharP, None)
+ BStruct = new_struct_type("foo")
+ complete_struct_or_union(BStruct, [('x', BInt),
+ ('y', BChar),
+ ('z', BArray)])
+ assert sizeof(BStruct) == 2 * size_of_int()
+ def offsetof(BType, fieldname):
+ return typeoffsetof(BType, fieldname)[1]
+ base = offsetof(BStruct, 'z')
+ assert base == size_of_int() + 1
+ #
+ p = newp(new_pointer_type(BStruct), {'z': 3})
+ assert sizeof(p[0]) == base + 3
+ q = newp(new_pointer_type(BStruct), {'z': size_of_int()})
+ assert sizeof(q) == size_of_ptr()
+ assert sizeof(q[0]) == base + size_of_int()
+ assert len(p.z) == 3
+ assert len(p[0].z) == 3
+ assert len(q.z) == size_of_int()
+ assert len(q[0].z) == size_of_int()
+
def test_ass_slice():
BChar = new_primitive_type("char")
BArray = new_array_type(new_pointer_type(BChar), None)
diff --git a/testing/cffi0/test_verify.py b/testing/cffi0/test_verify.py
--- a/testing/cffi0/test_verify.py
+++ b/testing/cffi0/test_verify.py
@@ -561,7 +561,8 @@
"int bar(struct foo_s *f) { return f->a[14]; }\n")
assert ffi.sizeof('struct foo_s') == 19 * ffi.sizeof('int')
s = ffi.new("struct foo_s *")
- assert ffi.typeof(s.a) is ffi.typeof('int *') # because no length
+ assert ffi.typeof(s.a) is ffi.typeof('int[]') # implicit max length
+ assert len(s.a) == 18 # max length, computed from the size and start offset
s.a[14] = 4242
assert lib.bar(s) == 4242
# with no declared length, out-of-bound accesses are not detected
diff --git a/testing/cffi1/test_recompiler.py b/testing/cffi1/test_recompiler.py
--- a/testing/cffi1/test_recompiler.py
+++ b/testing/cffi1/test_recompiler.py
@@ -414,8 +414,10 @@
verify(ffi, 'test_open_array_in_struct',
"struct foo_s { int b; int a[]; };")
assert ffi.sizeof("struct foo_s") == 4
- p = ffi.new("struct foo_s *", [5, [10, 20, 30]])
+ p = ffi.new("struct foo_s *", [5, [10, 20, 30, 40]])
assert p.a[2] == 30
+ assert ffi.sizeof(p) == ffi.sizeof("void *")
+ assert ffi.sizeof(p[0]) == 5 * ffi.sizeof("int")
def test_math_sin_type():
ffi = FFI()
@@ -1001,6 +1003,7 @@
"struct foo_s { int x; int a[5][8]; int y; };")
assert ffi.sizeof('struct foo_s') == 42 * ffi.sizeof('int')
s = ffi.new("struct foo_s *")
+ assert ffi.typeof(s.a) == ffi.typeof("int[5][8]")
assert ffi.sizeof(s.a) == 40 * ffi.sizeof('int')
assert s.a[4][7] == 0
py.test.raises(IndexError, 's.a[4][8]')
@@ -1015,7 +1018,7 @@
"struct foo_s { int x; int a[5][7]; int y; };")
assert ffi.sizeof('struct foo_s') == 37 * ffi.sizeof('int')
s = ffi.new("struct foo_s *")
- assert ffi.typeof(s.a) == ffi.typeof("int(*)[7]")
+ assert ffi.typeof(s.a) == ffi.typeof("int[][7]")
assert s.a[4][6] == 0
py.test.raises(IndexError, 's.a[4][7]')
assert ffi.typeof(s.a[0]) == ffi.typeof("int[7]")
diff --git a/testing/cffi1/test_verify1.py b/testing/cffi1/test_verify1.py
--- a/testing/cffi1/test_verify1.py
+++ b/testing/cffi1/test_verify1.py
@@ -546,7 +546,8 @@
"int bar(struct foo_s *f) { return f->a[14]; }\n")
assert ffi.sizeof('struct foo_s') == 19 * ffi.sizeof('int')
s = ffi.new("struct foo_s *")
- assert ffi.typeof(s.a) is ffi.typeof('int *') # because no length
+ assert ffi.typeof(s.a) is ffi.typeof('int[]') # implicit max length
+ assert len(s.a) == 18 # max length, computed from the size and start offset
s.a[14] = 4242
assert lib.bar(s) == 4242
# with no declared length, out-of-bound accesses are not detected
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic