[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