[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