[pypy-commit] cffi default: Fix the issue by declaring it illegal. See comment in _cffi_backend.c for why.

arigo noreply at buildbot.pypy.org
Thu Jun 28 12:46:32 CEST 2012


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r552:3b32cfd7e182
Date: 2012-06-28 12:40 +0200
http://bitbucket.org/cffi/cffi/changeset/3b32cfd7e182/

Log:	Fix the issue by declaring it illegal. See comment in
	_cffi_backend.c for why.

diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -41,6 +41,7 @@
 #define CT_PRIMITIVE_FITS_LONG   2048
 #define CT_IS_OPAQUE             4096
 #define CT_IS_ENUM               8192
+#define CT_CUSTOM_FIELD_POS     16384
 #define CT_PRIMITIVE_ANY  (CT_PRIMITIVE_SIGNED |        \
                            CT_PRIMITIVE_UNSIGNED |      \
                            CT_PRIMITIVE_CHAR |          \
@@ -2467,12 +2468,16 @@
         if (alignment < falign)
             alignment = falign;
 
-        if (foffset < 0) {
-            /* align this field to its own 'falign' by inserting padding */
-            offset = (offset + falign - 1) & ~(falign-1);
+        /* align this field to its own 'falign' by inserting padding */
+        offset = (offset + falign - 1) & ~(falign-1);
+
+        if (foffset >= 0) {
+            /* a forced field position: ignore the offset just computed,
+               except to know if we must set CT_CUSTOM_FIELD_POS */
+            if (offset != foffset)
+                ct->ct_flags |= CT_CUSTOM_FIELD_POS;
+            offset = foffset;
         }
-        else
-            offset = foffset;
 
         if (fbitsize < 0 || (fbitsize == 8 * ftype->ct_size &&
                              !(ftype->ct_flags & CT_PRIMITIVE_CHAR))) {
@@ -2665,8 +2670,21 @@
         Py_ssize_t i, n;
         CFieldObject *cf;
 
-        /* XXX check if the field positions match; if necessary,
-           insert dummy fields */
+        /* We can't pass a struct that was completed by verify().
+           Issue: assume verify() is given "struct { long b; ...; }".
+           Then it will complete it in the same way whether it is actually
+           "struct { long a, b; }" or "struct { double a; long b; }".
+           But on 64-bit UNIX, these two structs are passed by value
+           differently: e.g. on x86-64, "b" ends up in "rsi" in the
+           first case and "rdi" on the second case.
+        */
+        if (ct->ct_flags & CT_CUSTOM_FIELD_POS) {
+            PyErr_SetString(PyExc_TypeError,
+                "cannot pass as a argument a struct that was completed "
+                "with verify() (see _cffi_backend.c for details of why)");
+            return NULL;
+        }
+
         n = PyDict_Size(ct->ct_stuff);
         elements = fb_alloc(fb, (n + 1) * sizeof(ffi_type*));
         cf = (CFieldObject *)ct->ct_extra;
@@ -3420,6 +3438,7 @@
     case 7: f = &_testfunc7; break;
     case 8: f = stderr; break;
     case 9: f = &_testfunc9; break;
+    case 10: f = &_testfunc10; break;
     default:
         PyErr_SetNone(PyExc_ValueError);
         return NULL;
diff --git a/c/test_c.py b/c/test_c.py
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -783,6 +783,18 @@
     py.test.raises(TypeError, f, 1, 42)
     py.test.raises(TypeError, f, 2, None)
 
+def test_cannot_call_with_a_autocompleted_struct():
+    BSChar = new_primitive_type("signed char")
+    BDouble = new_primitive_type("double")
+    BStruct = new_struct_type("foo")
+    BStructPtr = new_pointer_type(BStruct)
+    complete_struct_or_union(BStruct, [('c', BDouble, -1, 8),
+                                       ('a', BSChar, -1, 2),
+                                       ('b', BSChar, -1, 0)])
+    e = py.test.raises(TypeError, new_function_type, (BStruct,), BDouble)
+    msg = 'cannot pass as a argument a struct that was completed with verify()'
+    assert msg in str(e.value)
+
 def test_new_charp():
     BChar = new_primitive_type("char")
     BCharP = new_pointer_type(BChar)
diff --git a/testing/test_verify.py b/testing/test_verify.py
--- a/testing/test_verify.py
+++ b/testing/test_verify.py
@@ -562,9 +562,9 @@
 
 def test_autofilled_struct_as_argument_dynamic():
     ffi = FFI()
-    ffi.cdef("struct foo_s { long a; double b; ...; };\n"
+    ffi.cdef("struct foo_s { long a; ...; };\n"
              "int (*foo)(struct foo_s);")
-    lib = ffi.verify("""
+    e = py.test.raises(TypeError, ffi.verify, """
         struct foo_s {
             double b;
             long a;
@@ -574,5 +574,5 @@
         }
         int (*foo)(struct foo_s s) = &foo1;
     """)
-    s = ffi.new("struct foo_s", [100, 1.9])
-    assert lib.foo(s[0]) == 99
+    msg = 'cannot pass as a argument a struct that was completed with verify()'
+    assert msg in str(e.value)


More information about the pypy-commit mailing list