summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArmin Rigo <arigo@tunes.org>2016-07-31 15:07:56 +0200
committerArmin Rigo <arigo@tunes.org>2016-07-31 15:07:56 +0200
commit9e68ee5e7c7824f5744f7f222c844885468c443e (patch)
tree5bdd7f2290655dab557227811cb9448fae4c7e82
parentbbae5839c3c0ae7f1ee6792ef2e4adf63f9acbc2 (diff)
downloadcffi-9e68ee5e7c7824f5744f7f222c844885468c443e.tar.gz
Test and fix: refuse to 'recompile' a cdef that declares a struct
with an opaque struct as a field
-rw-r--r--cffi/recompiler.py9
-rw-r--r--testing/cffi1/test_recompiler.py32
2 files changed, 41 insertions, 0 deletions
diff --git a/cffi/recompiler.py b/cffi/recompiler.py
index 0aed988..eb7c891 100644
--- a/cffi/recompiler.py
+++ b/cffi/recompiler.py
@@ -862,6 +862,8 @@ class Recompiler:
enumfields = list(tp.enumfields())
for fldname, fldtype, fbitsize, fqual in enumfields:
fldtype = self._field_type(tp, fldname, fldtype)
+ self._check_not_opaque(fldtype,
+ "field '%s.%s'" % (tp.name, fldname))
# cname is None for _add_missing_struct_unions() only
op = OP_NOOP
if fbitsize >= 0:
@@ -911,6 +913,13 @@ class Recompiler:
first_field_index, c_fields))
self._seen_struct_unions.add(tp)
+ def _check_not_opaque(self, tp, location):
+ while isinstance(tp, model.ArrayType):
+ tp = tp.item
+ if isinstance(tp, model.StructOrUnion) and tp.fldtypes is None:
+ raise TypeError(
+ "%s is of an opaque type (not declared in cdef())" % location)
+
def _add_missing_struct_unions(self):
# not very nice, but some struct declarations might be missing
# because they don't have any known C name. Check that they are
diff --git a/testing/cffi1/test_recompiler.py b/testing/cffi1/test_recompiler.py
index 1bd1da2..d1fadfc 100644
--- a/testing/cffi1/test_recompiler.py
+++ b/testing/cffi1/test_recompiler.py
@@ -1918,3 +1918,35 @@ def test_bool_in_cpp():
ffi.cdef("bool f(void);")
lib = verify(ffi, "test_bool_in_cpp", "char f(void) { return 2; }")
assert lib.f() == 1
+
+def test_struct_field_opaque():
+ ffi = FFI()
+ ffi.cdef("struct a { struct b b; };")
+ e = py.test.raises(TypeError, verify,
+ ffi, "test_struct_field_opaque", "?")
+ assert str(e.value) == ("struct a: field 'a.b' is of an opaque"
+ " type (not declared in cdef())")
+ ffi = FFI()
+ ffi.cdef("struct a { struct b b[2]; };")
+ e = py.test.raises(TypeError, verify,
+ ffi, "test_struct_field_opaque", "?")
+ assert str(e.value) == ("struct a: field 'a.b' is of an opaque"
+ " type (not declared in cdef())")
+ ffi = FFI()
+ ffi.cdef("struct a { struct b b[]; };")
+ e = py.test.raises(TypeError, verify,
+ ffi, "test_struct_field_opaque", "?")
+ assert str(e.value) == ("struct a: field 'a.b' is of an opaque"
+ " type (not declared in cdef())")
+
+def test_function_arg_opaque():
+ py.test.skip("can currently declare a function with an opaque struct "
+ "as argument, but AFAICT it's impossible to call it later")
+
+def test_function_returns_opaque():
+ ffi = FFI()
+ ffi.cdef("struct a foo(int);")
+ e = py.test.raises(TypeError, verify,
+ ffi, "test_function_returns_opaque", "?")
+ assert str(e.value) == ("function foo: 'struct a' is used as result type,"
+ " but is opaque")