[pypy-commit] cffi linux-only: In-progress: verify fully-declared structs.
arigo
noreply at buildbot.pypy.org
Tue Jun 12 11:33:49 CEST 2012
Author: Armin Rigo <arigo at tunes.org>
Branch: linux-only
Changeset: r282:369b47a0aaf7
Date: 2012-06-12 10:35 +0200
http://bitbucket.org/cffi/cffi/changeset/369b47a0aaf7/
Log: In-progress: verify fully-declared structs.
diff --git a/c/_ffi_backend.c b/c/_ffi_backend.c
--- a/c/_ffi_backend.c
+++ b/c/_ffi_backend.c
@@ -3005,40 +3005,35 @@
return PyInt_FromLong(align);
}
-static PyObject *b_sizeof_type(PyObject *self, PyObject *arg)
+static PyObject *b_sizeof(PyObject *self, PyObject *arg)
{
- if (!CTypeDescr_Check(arg)) {
- PyErr_SetString(PyExc_TypeError, "expected a 'ctype' object");
+ Py_ssize_t size;
+
+ if (CData_Check(arg)) {
+ CDataObject *cd = (CDataObject *)arg;
+
+ if (cd->c_type->ct_flags & CT_ARRAY)
+ size = get_array_length(cd) * cd->c_type->ct_itemdescr->ct_size;
+ else
+ size = cd->c_type->ct_size;
+ }
+ else if (CTypeDescr_Check(arg)) {
+ if (((CTypeDescrObject *)arg)->ct_size < 0) {
+ PyErr_Format(PyExc_ValueError, "ctype '%s' is of unknown size",
+ ((CTypeDescrObject *)arg)->ct_name);
+ return NULL;
+ }
+ size = ((CTypeDescrObject *)arg)->ct_size;
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError,
+ "expected a 'cdata' or 'ctype' object");
return NULL;
}
- if (((CTypeDescrObject *)arg)->ct_size < 0) {
- PyErr_Format(PyExc_ValueError, "ctype '%s' is of unknown size",
- ((CTypeDescrObject *)arg)->ct_name);
- return NULL;
- }
- return PyInt_FromSsize_t(((CTypeDescrObject *)arg)->ct_size);
-}
-
-static PyObject *b_sizeof_instance(PyObject *self, PyObject *arg)
-{
- CDataObject *cd;
- Py_ssize_t size;
-
- if (!CData_Check(arg)) {
- PyErr_SetString(PyExc_TypeError, "expected a 'cdata' object");
- return NULL;
- }
- cd = (CDataObject *)arg;
-
- if (cd->c_type->ct_flags & CT_ARRAY)
- size = get_array_length(cd) * cd->c_type->ct_itemdescr->ct_size;
- else
- size = cd->c_type->ct_size;
-
return PyInt_FromSsize_t(size);
}
-static PyObject *b_typeof_instance(PyObject *self, PyObject *arg)
+static PyObject *b_typeof(PyObject *self, PyObject *arg)
{
PyObject *res;
@@ -3230,9 +3225,8 @@
{"cast", b_cast, METH_VARARGS},
{"callback", b_callback, METH_VARARGS},
{"alignof", b_alignof, METH_O},
- {"sizeof_type", b_sizeof_type, METH_O},
- {"sizeof_instance", b_sizeof_instance, METH_O},
- {"typeof_instance", b_typeof_instance, METH_O},
+ {"sizeof", b_sizeof, METH_O},
+ {"typeof", b_typeof, METH_O},
{"offsetof", b_offsetof, METH_VARARGS},
{"string", b_string, METH_VARARGS},
{"get_errno", b_get_errno, METH_NOARGS},
diff --git a/cffi/api.py b/cffi/api.py
--- a/cffi/api.py
+++ b/cffi/api.py
@@ -93,7 +93,7 @@
self._parsed_types[cdecl] = btype
return btype
else:
- return self._backend.typeof_instance(cdecl)
+ return self._backend.typeof(cdecl)
def sizeof(self, cdecl):
"""Return the size in bytes of the argument. It can be a
@@ -101,9 +101,9 @@
"""
if isinstance(cdecl, (str, unicode)):
BType = self.typeof(cdecl)
- return self._backend.sizeof_type(BType)
+ return self._backend.sizeof(BType)
else:
- return self._backend.sizeof_instance(cdecl)
+ return self._backend.sizeof(cdecl)
def alignof(self, cdecl):
"""Return the natural alignment size in bytes of the C type
@@ -182,7 +182,7 @@
""" Verify that the current ffi signatures compile on this machine
"""
from .verifier import Verifier
- return Verifier().verify(self, preamble, **kwargs)
+ return Verifier(self).verify(preamble, **kwargs)
def _make_ffi_library(ffi, libname):
name = libname
diff --git a/cffi/backend_ctypes.py b/cffi/backend_ctypes.py
--- a/cffi/backend_ctypes.py
+++ b/cffi/backend_ctypes.py
@@ -760,13 +760,12 @@
p = ctypes.cast(bptr._as_ctype_ptr, ctypes.POINTER(ctypes.c_char))
return ''.join([p[i] for i in range(length)])
- def sizeof_type(self, BType):
- assert issubclass(BType, CTypesData)
- return BType._get_size()
-
- def sizeof_instance(self, cdata):
- assert isinstance(cdata, CTypesData)
- return cdata._get_size_of_instance()
+ def sizeof(self, cdata_or_BType):
+ if isinstance(cdata_or_BType, CTypesData):
+ return cdata_or_BType._get_size_of_instance()
+ else:
+ assert issubclass(cdata_or_BType, CTypesData)
+ return cdata_or_BType._get_size()
def alignof(self, BType):
assert issubclass(BType, CTypesData)
@@ -785,7 +784,7 @@
def callback(self, BType, source):
return BType(source)
- typeof_instance = type
+ typeof = type
class CTypesLibrary(object):
diff --git a/cffi/cparser.py b/cffi/cparser.py
--- a/cffi/cparser.py
+++ b/cffi/cparser.py
@@ -300,7 +300,7 @@
nextenumvalue += 1
enumvalues = tuple(enumvalues)
tp = model.EnumType(name, enumerators, enumvalues)
- self._declarations[key] = tp
+ self._declare(key, tp)
else: # opaque enum
enumerators = ()
enumvalues = ()
diff --git a/cffi/model.py b/cffi/model.py
--- a/cffi/model.py
+++ b/cffi/model.py
@@ -170,9 +170,20 @@
return ffi._backend.new_struct_type(self.name)
def verifier_declare_struct(self, verifier, name):
- if self.fldnames is None:
- assert not self.partial
- return
+ if self.partial:
+ self.verifier_decl_partial(verifier, name)
+ else:
+ self.verifier_decl_notpartial(verifier, name)
+
+ def verifier_decl_notpartial(self, verifier, name):
+ if self.fldnames is None: # not partial, but fully opaque:
+ return # cannot really test even for existence
+ struct = verifier.ffi._get_cached_btype(self)
+ verifier.write('__sameconstant__(sizeof(struct %s), %d)' % (
+ name, verifier.ffi.sizeof(struct)))
+
+ def verifier_decl_partial(self, verifier, name):
+ assert self.fldnames is not None
verifier.write('{')
verifier.write('struct __aligncheck__ { char x; struct %s y; };' %
self.name)
diff --git a/cffi/verifier.py b/cffi/verifier.py
--- a/cffi/verifier.py
+++ b/cffi/verifier.py
@@ -3,6 +3,9 @@
class Verifier(object):
+ def __init__(self, ffi):
+ self.ffi = ffi
+
def write(self, what):
print >> self.f, ' ' + what
@@ -14,25 +17,30 @@
print >> self.f, ' printf("%s\\n", %s);' % (
what, ', '.join(args))
- def verify(self, ffi, preamble, **kwargs):
+ def verify(self, preamble, **kwargs):
tst_file_base = ffiplatform._get_test_file_base()
self.has_printf = False
with open(tst_file_base + '.c', 'w') as f:
- f.write('#include <stdio.h>\n')
- f.write('#include <stdint.h>\n')
- f.write('#include <stddef.h>\n')
- f.write('#include <unistd.h>\n')
+ f.write('#include <stdio.h>\n'
+ '#include <stdint.h>\n'
+ '#include <stddef.h>\n'
+ '#include <unistd.h>\n'
+ '\n'
+ '#define __sameconstant__(x, y) \\\n'
+ ' { int result[1-2*((x)-(y))*((x)-(y))]; }\n'
+ '\n'
+ )
f.write(preamble + "\n\n")
f.write('int main() {\n')
self.f = f
- for name, tp in ffi._parser._declarations.iteritems():
+ for name, tp in self.ffi._parser._declarations.iteritems():
kind, realname = name.split(' ', 1)
method = getattr(tp, 'verifier_declare_' + kind)
method(self, realname)
del self.f
f.write(' return 0;\n')
f.write('}\n')
- err = os.system('gcc -Werror -c %s.c -o %s.o' %
+ err = os.system('gcc -Werror -S %s.c -o %s.s' %
(tst_file_base, tst_file_base))
if err:
raise ffiplatform.VerificationError(
diff --git a/testing/backend_tests.py b/testing/backend_tests.py
--- a/testing/backend_tests.py
+++ b/testing/backend_tests.py
@@ -6,7 +6,7 @@
SIZE_OF_LONG = ctypes.sizeof(ctypes.c_long)
SIZE_OF_SHORT = ctypes.sizeof(ctypes.c_short)
SIZE_OF_PTR = ctypes.sizeof(ctypes.c_void_p)
-SIZE_OF_WCHAR = ctypes.sizeof(ctypes.c_wchar)
+#SIZE_OF_WCHAR = ctypes.sizeof(ctypes.c_wchar)
class BackendTests:
@@ -41,7 +41,7 @@
self._test_int_type(ffi, 'ptrdiff_t', SIZE_OF_PTR, False)
self._test_int_type(ffi, 'size_t', SIZE_OF_PTR, True)
self._test_int_type(ffi, 'ssize_t', SIZE_OF_PTR, False)
- self._test_int_type(ffi, 'wchar_t', SIZE_OF_WCHAR, True)
+ #self._test_int_type(ffi, 'wchar_t', SIZE_OF_WCHAR, True)
def _test_int_type(self, ffi, c_decl, size, unsigned):
if unsigned:
diff --git a/testing/test_cdata.py b/testing/test_cdata.py
--- a/testing/test_cdata.py
+++ b/testing/test_cdata.py
@@ -6,7 +6,7 @@
def nonstandard_integer_types(self):
return {}
- def sizeof_type(self, name):
+ def sizeof(self, name):
return 1
def load_library(self, path):
diff --git a/testing/test_parsing.py b/testing/test_parsing.py
--- a/testing/test_parsing.py
+++ b/testing/test_parsing.py
@@ -5,7 +5,7 @@
def nonstandard_integer_types(self):
return {}
- def sizeof_type(self, name):
+ def sizeof(self, name):
return 1
def load_library(self, name):
diff --git a/testing/test_verify.py b/testing/test_verify.py
--- a/testing/test_verify.py
+++ b/testing/test_verify.py
@@ -37,6 +37,25 @@
"typedef %s foo_t;" % real)
+def test_ffi_full_struct():
+ ffi = FFI()
+ ffi.cdef("struct foo_s { char x; int y; long *z; };")
+ ffi.verify("struct foo_s { char x; int y; long *z; };")
+ #
+ for real in [
+ "struct foo_s { char x; int y; int *z; };",
+ "struct foo_s { char x; long *z; int y; };",
+ "struct foo_s { int y; long *z; };",
+ "struct foo_s { char x; int y; long *z; char extra; };",
+ ]:
+ py.test.raises(VerificationError, ffi.verify, real)
+ #
+ # a corner case that we cannot really detect, but where it has no
+ # bad consequences: the size is the same, but there is an extra field
+ # that replaces what is just padding in our declaration above
+ ffi.verify("struct foo_s { char x, extra; int y; long *z; };")
+
+
def test_ffi_nonfull_struct():
py.test.skip("XXX")
ffi = FFI()
More information about the pypy-commit
mailing list