[pypy-commit] cffi default: Some sort of simplification of the logic of discovering field
arigo
noreply at buildbot.pypy.org
Sun Aug 26 17:42:36 CEST 2012
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r899:46b206cf2436
Date: 2012-08-26 17:42 +0200
http://bitbucket.org/cffi/cffi/changeset/46b206cf2436/
Log: Some sort of simplification of the logic of discovering field
offsets. It allows us to give much better error messages.
diff --git a/cffi/vengine_cpy.py b/cffi/vengine_cpy.py
--- a/cffi/vengine_cpy.py
+++ b/cffi/vengine_cpy.py
@@ -389,44 +389,17 @@
prnt('%s(PyObject *self, PyObject *noarg)' % (layoutfuncname,))
prnt('{')
prnt(' struct _cffi_aligncheck { char x; %s y; };' % cname)
- if isinstance(tp, model.StructType) and tp.partial:
- prnt(' static Py_ssize_t nums[] = {')
- prnt(' sizeof(%s),' % cname)
- prnt(' offsetof(struct _cffi_aligncheck, y),')
- for fname, _, fbitsize in tp.enumfields():
- assert fbitsize < 0
- prnt(' offsetof(%s, %s),' % (cname, fname))
- prnt(' sizeof(((%s *)0)->%s),' % (cname, fname))
- prnt(' -1')
- prnt(' };')
- prnt(' return _cffi_get_struct_layout(nums);')
- else:
- ffi = self.ffi
- BStruct = ffi._get_cached_btype(tp)
- conditions = [
- 'sizeof(%s) != %d' % (cname, ffi.sizeof(BStruct)),
- 'offsetof(struct _cffi_aligncheck, y) != %d' % (
- ffi.alignof(BStruct),)]
- for fname, ftype, fbitsize in tp.enumfields():
- if fbitsize >= 0:
- continue # xxx ignore fbitsize for now
- BField = ffi._get_cached_btype(ftype)
- conditions += [
- 'offsetof(%s, %s) != %d' % (
- cname, fname, ffi.offsetof(BStruct, fname)),
- 'sizeof(((%s *)0)->%s) != %d' % (
- cname, fname, ffi.sizeof(BField))]
- prnt(' if (%s ||' % conditions[0])
- for i in range(1, len(conditions)-1):
- prnt(' %s ||' % conditions[i])
- prnt(' %s) {' % conditions[-1])
- prnt(' Py_INCREF(Py_False);')
- prnt(' return Py_False;')
- prnt(' }')
- prnt(' else {')
- prnt(' Py_INCREF(Py_True);')
- prnt(' return Py_True;')
- prnt(' }')
+ prnt(' static Py_ssize_t nums[] = {')
+ prnt(' sizeof(%s),' % cname)
+ prnt(' offsetof(struct _cffi_aligncheck, y),')
+ for fname, _, fbitsize in tp.enumfields():
+ if fbitsize >= 0:
+ continue # xxx ignore fbitsize for now
+ prnt(' offsetof(%s, %s),' % (cname, fname))
+ prnt(' sizeof(((%s *)0)->%s),' % (cname, fname))
+ prnt(' -1')
+ prnt(' };')
+ prnt(' return _cffi_get_struct_layout(nums);')
prnt(' /* the next line is not executed, but compiled */')
prnt(' %s(0);' % (checkfuncname,))
prnt('}')
@@ -447,12 +420,9 @@
#
function = getattr(module, layoutfuncname)
layout = function()
- if layout is False:
- raise ffiplatform.VerificationError(
- "incompatible layout for %s" % cname)
- elif layout is True:
- assert isinstance(tp, model.UnionType) or not tp.partial
- else:
+ if isinstance(tp, model.StructType) and tp.partial:
+ # use the function()'s sizes and offsets to guide the
+ # layout of the struct
totalsize = layout[0]
totalalignment = layout[1]
fieldofs = layout[2::2]
@@ -460,6 +430,29 @@
tp.force_flatten()
assert len(fieldofs) == len(fieldsize) == len(tp.fldnames)
tp.fixedlayout = fieldofs, fieldsize, totalsize, totalalignment
+ else:
+ # check that the function()'s sizes and offsets match
+ # the real ones
+ def check(realvalue, expectedvalue, msg):
+ if realvalue != expectedvalue:
+ raise ffiplatform.VerificationError(
+ "in %s: %s (we have %d, but C compiler says %d)"
+ % (cname, msg, expectedvalue, realvalue))
+ ffi = self.ffi
+ BStruct = ffi._get_cached_btype(tp)
+ check(layout[0], ffi.sizeof(BStruct), "wrong total size")
+ check(layout[1], ffi.alignof(BStruct), "wrong total alignment")
+ i = 2
+ for fname, ftype, fbitsize in tp.enumfields():
+ if fbitsize >= 0:
+ continue # xxx ignore fbitsize for now
+ check(layout[i], ffi.offsetof(BStruct, fname),
+ "wrong offset for field %r" % (fname,))
+ BField = ffi._get_cached_btype(ftype)
+ check(layout[i+1], ffi.sizeof(BField),
+ "wrong size for field %r" % (fname,))
+ i += 2
+ assert i == len(layout)
def _loaded_struct_or_union(self, tp):
if tp.fldnames is None:
diff --git a/cffi/vengine_gen.py b/cffi/vengine_gen.py
--- a/cffi/vengine_gen.py
+++ b/cffi/vengine_gen.py
@@ -212,42 +212,17 @@
prnt('ssize_t %s(ssize_t i)' % (layoutfuncname,))
prnt('{')
prnt(' struct _cffi_aligncheck { char x; %s y; };' % cname)
- if isinstance(tp, model.StructType) and tp.partial:
- prnt(' static ssize_t nums[] = {')
- prnt(' 1, sizeof(%s),' % cname)
- prnt(' offsetof(struct _cffi_aligncheck, y),')
- for fname, _, fbitsize in tp.enumfields():
- assert fbitsize < 0
- prnt(' offsetof(%s, %s),' % (cname, fname))
- prnt(' sizeof(((%s *)0)->%s),' % (cname, fname))
- prnt(' -1')
- prnt(' };')
- prnt(' return nums[i];')
- else:
- ffi = self.ffi
- BStruct = ffi._get_cached_btype(tp)
- conditions = [
- 'sizeof(%s) != %d' % (cname, ffi.sizeof(BStruct)),
- 'offsetof(struct _cffi_aligncheck, y) != %d' % (
- ffi.alignof(BStruct),)]
- for fname, ftype, fbitsize in tp.enumfields():
- if fbitsize >= 0:
- continue # xxx ignore fbitsize for now
- BField = ffi._get_cached_btype(ftype)
- conditions += [
- 'offsetof(%s, %s) != %d' % (
- cname, fname, ffi.offsetof(BStruct, fname)),
- 'sizeof(((%s *)0)->%s) != %d' % (
- cname, fname, ffi.sizeof(BField))]
- prnt(' if (%s ||' % conditions[0])
- for i in range(1, len(conditions)-1):
- prnt(' %s ||' % conditions[i])
- prnt(' %s) {' % conditions[-1])
- prnt(' return -1;')
- prnt(' }')
- prnt(' else {')
- prnt(' return 0;')
- prnt(' }')
+ prnt(' static ssize_t nums[] = {')
+ prnt(' sizeof(%s),' % cname)
+ prnt(' offsetof(struct _cffi_aligncheck, y),')
+ for fname, _, fbitsize in tp.enumfields():
+ if fbitsize >= 0:
+ continue # xxx ignore fbitsize for now
+ prnt(' offsetof(%s, %s),' % (cname, fname))
+ prnt(' sizeof(((%s *)0)->%s),' % (cname, fname))
+ prnt(' -1')
+ prnt(' };')
+ prnt(' return nums[i];')
prnt(' /* the next line is not executed, but compiled */')
prnt(' %s(0);' % (checkfuncname,))
prnt('}')
@@ -261,27 +236,46 @@
#
BFunc = self.ffi.typeof("ssize_t(*)(ssize_t)")
function = module.load_function(BFunc, layoutfuncname)
- layout = function(0)
- if layout < 0:
- raise ffiplatform.VerificationError(
- "incompatible layout for %s" % cname)
- elif layout == 0:
- assert isinstance(tp, model.UnionType) or not tp.partial
- else:
- totalsize = function(1)
- totalalignment = function(2)
- fieldofs = []
- fieldsize = []
- num = 3
- while True:
- x = function(num)
- if x < 0: break
- fieldofs.append(x)
- fieldsize.append(function(num+1))
- num += 2
+ layout = []
+ num = 0
+ while True:
+ x = function(num)
+ if x < 0: break
+ layout.append(x)
+ num += 1
+ if isinstance(tp, model.StructType) and tp.partial:
+ # use the function()'s sizes and offsets to guide the
+ # layout of the struct
+ totalsize = layout[0]
+ totalalignment = layout[1]
+ fieldofs = layout[2::2]
+ fieldsize = layout[3::2]
tp.force_flatten()
assert len(fieldofs) == len(fieldsize) == len(tp.fldnames)
tp.fixedlayout = fieldofs, fieldsize, totalsize, totalalignment
+ else:
+ # check that the function()'s sizes and offsets match
+ # the real ones
+ def check(realvalue, expectedvalue, msg):
+ if realvalue != expectedvalue:
+ raise ffiplatform.VerificationError(
+ "in %s: %s (we have %d, but C compiler says %d)"
+ % (cname, msg, expectedvalue, realvalue))
+ ffi = self.ffi
+ BStruct = ffi._get_cached_btype(tp)
+ check(layout[0], ffi.sizeof(BStruct), "wrong total size")
+ check(layout[1], ffi.alignof(BStruct), "wrong total alignment")
+ i = 2
+ for fname, ftype, fbitsize in tp.enumfields():
+ if fbitsize >= 0:
+ continue # xxx ignore fbitsize for now
+ check(layout[i], ffi.offsetof(BStruct, fname),
+ "wrong offset for field %r" % (fname,))
+ BField = ffi._get_cached_btype(ftype)
+ check(layout[i+1], ffi.sizeof(BField),
+ "wrong size for field %r" % (fname,))
+ i += 2
+ assert i == len(layout)
def _loaded_struct_or_union(self, tp):
if tp.fldnames is None:
diff --git a/testing/test_verify.py b/testing/test_verify.py
--- a/testing/test_verify.py
+++ b/testing/test_verify.py
@@ -270,21 +270,37 @@
ffi.cdef("struct foo_s { char x; int y; long *z; };")
ffi.verify("struct foo_s { char x; int y; long *z; };")
#
- if sys.platform == 'win32':
- py.test.skip("XXX fixme: only gives warnings")
- 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)
+ if sys.platform != 'win32': # XXX fixme: only gives warnings
+ py.test.raises(VerificationError, ffi.verify,
+ "struct foo_s { char x; int y; int *z; };")
+ #
+ py.test.raises(VerificationError, ffi.verify,
+ "struct foo_s { int y; long *z; };")
+ #
+ e = py.test.raises(VerificationError, ffi.verify,
+ "struct foo_s { int y; char x; long *z; };")
+ assert str(e.value) == (
+ "in struct foo_s: wrong offset for field 'x'"
+ " (we have 0, but C compiler says 4)")
+ #
+ e = py.test.raises(VerificationError, ffi.verify,
+ "struct foo_s { char x; int y; long *z; char extra; };")
+ assert str(e.value) == (
+ "in struct foo_s: wrong total size"
+ " (we have %d, but C compiler says %d)" % (
+ ffi.sizeof("struct foo_s"),
+ ffi.sizeof("struct foo_s") + ffi.sizeof("long*")))
#
# 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; };")
-
+ #
+ e = py.test.raises(VerificationError, ffi.verify,
+ "struct foo_s { char x; short pad; short y; long *z; };")
+ assert str(e.value) == (
+ "in struct foo_s: wrong size for field 'y'"
+ " (we have 4, but C compiler says 2)")
def test_ffi_nonfull_struct():
ffi = FFI()
More information about the pypy-commit
mailing list