Author: Armin Rigo <ar...@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