-- cgit v1.2.1 From 5137d7874fb0c343f1a09cd6fb3b94c8d832e958 Mon Sep 17 00:00:00 2001 From: Armin Rigo Date: Fri, 27 Jul 2012 14:03:57 +0200 Subject: For now, edit verifier.py in-place. Will think later about how best to have them both and share common code. Also, it seems that this 2nd version is much simpler than the 1st one. --- cffi/verifier.py | 221 +++++-------------------------------------------------- 1 file changed, 20 insertions(+), 201 deletions(-) diff --git a/cffi/verifier.py b/cffi/verifier.py index 020b1f2..f4a8547 100644 --- a/cffi/verifier.py +++ b/cffi/verifier.py @@ -148,30 +148,6 @@ class Verifier(object): # implement the function _cffi_setup_custom() as calling the # head of the chained list. self._generate_setup_custom() - prnt() - # - # produce the method table, including the entries for the - # generated Python->C function wrappers, which are done - # by generate_cpy_function_method(). - prnt('static PyMethodDef _cffi_methods[] = {') - self._generate("method") - prnt(' {"_cffi_setup", _cffi_setup, METH_VARARGS},') - prnt(' {NULL, NULL} /* Sentinel */') - prnt('};') - prnt() - # - # standard init. - modname = self.get_module_name() - prnt('PyMODINIT_FUNC') - prnt('init%s(void)' % modname) - prnt('{') - prnt(' PyObject *lib;') - prnt(' lib = Py_InitModule("%s", _cffi_methods);' % modname) - prnt(' if (lib == NULL || %s < 0)' % ( - self._chained_list_constants[False],)) - prnt(' return;') - prnt(' _cffi_init();') - prnt('}') def _compile_module(self): # compile this C source @@ -188,13 +164,9 @@ class Verifier(object): def _load_library(self): # XXX review all usages of 'self' here! - # import it as a new extension module - try: - module = imp.load_dynamic(self.get_module_name(), - self.modulefilename) - except ImportError, e: - error = "importing %r: %s" % (self.modulefilename, e) - raise ffiplatform.VerificationError(error) + # import it with the CFFI backend + backend = self.ffi._backend + module = backend.load_library(self.modulefilename) # # call loading_cpy_struct() to get the struct layout inferred by # the C compiler @@ -202,10 +174,10 @@ class Verifier(object): # # the C code will need the objects. Collect them in # order in a list. - revmapping = dict([(value, key) - for (key, value) in self._typesdict.items()]) - lst = [revmapping[i] for i in range(len(revmapping))] - lst = map(self.ffi._get_cached_btype, lst) + #revmapping = dict([(value, key) + # for (key, value) in self._typesdict.items()]) + #lst = [revmapping[i] for i in range(len(revmapping))] + #lst = map(self.ffi._get_cached_btype, lst) # # build the FFILibrary class and instance and call _cffi_setup(). # this will set up some fields like '_cffi_types', and only then @@ -213,9 +185,9 @@ class Verifier(object): # build (notably) the constant objects, as if they are # pointers, and store them as attributes on the 'library' object. class FFILibrary(object): - pass + _cffi_module = module library = FFILibrary() - sz = module._cffi_setup(lst, ffiplatform.VerificationError, library) + #module._cffi_setup(lst, ffiplatform.VerificationError, library) # # finally, call the loaded_cpy_xxx() functions. This will perform # the final adjustments, like copying the Python->C wrapper @@ -333,52 +305,20 @@ class Verifier(object): return prnt = self._prnt numargs = len(tp.args) - if numargs == 0: - argname = 'no_arg' - elif numargs == 1: - argname = 'arg0' - else: - argname = 'args' - prnt('static PyObject *') - prnt('_cffi_f_%s(PyObject *self, PyObject *%s)' % (name, argname)) + arglist = [type.get_c_name(' x%d' % i) + for i, type in enumerate(tp.args)] + arglist = ', '.join(arglist) or 'void' + funcdecl = ' _cffi_f_%s(%s)' % (name, arglist) + prnt(tp.result.get_c_name(funcdecl)) prnt('{') # - for i, type in enumerate(tp.args): - prnt(' %s;' % type.get_c_name(' x%d' % i)) if not isinstance(tp.result, model.VoidType): - result_code = 'result = ' - prnt(' %s;' % tp.result.get_c_name(' result')) + result_code = 'return ' else: result_code = '' - # - if len(tp.args) > 1: - rng = range(len(tp.args)) - for i in rng: - prnt(' PyObject *arg%d;' % i) - prnt() - prnt(' if (!PyArg_ParseTuple(args, "%s:%s", %s))' % ( - 'O' * numargs, name, ', '.join(['&arg%d' % i for i in rng]))) - prnt(' return NULL;') - prnt() - # - for i, type in enumerate(tp.args): - self._convert_funcarg_to_c(type, 'arg%d' % i, 'x%d' % i, - 'return NULL') - prnt() - # - prnt(' _cffi_restore_errno();') - prnt(' { %s%s(%s); }' % ( + prnt(' %s%s(%s);' % ( result_code, name, ', '.join(['x%d' % i for i in range(len(tp.args))]))) - prnt(' _cffi_save_errno();') - prnt() - # - if result_code: - prnt(' return %s;' % - self._convert_expr_from_c(tp.result, 'result')) - else: - prnt(' Py_INCREF(Py_None);') - prnt(' return Py_None;') prnt('}') prnt() @@ -399,7 +339,9 @@ class Verifier(object): def _loaded_cpy_function(self, tp, name, module, library): if tp.ellipsis: return - setattr(library, name, getattr(module, name)) + BFunc = self.ffi._get_cached_btype(tp) + wrappername = '_cffi_f_%s' % name + setattr(library, name, module.load_function(BFunc, wrappername)) # ---------- # named structs @@ -686,6 +628,7 @@ class Verifier(object): # ---------- def _generate_setup_custom(self): + return #XXX prnt = self._prnt prnt('static PyObject *_cffi_setup_custom(PyObject *lib)') prnt('{') @@ -696,132 +639,8 @@ class Verifier(object): prnt('}') cffimod_header = r''' -#include #include -#define _cffi_from_c_double PyFloat_FromDouble -#define _cffi_from_c_float PyFloat_FromDouble -#define _cffi_from_c_signed_char PyInt_FromLong -#define _cffi_from_c_short PyInt_FromLong -#define _cffi_from_c_int PyInt_FromLong -#define _cffi_from_c_long PyInt_FromLong -#define _cffi_from_c_unsigned_char PyInt_FromLong -#define _cffi_from_c_unsigned_short PyInt_FromLong -#define _cffi_from_c_unsigned_long PyLong_FromUnsignedLong -#define _cffi_from_c_unsigned_long_long PyLong_FromUnsignedLongLong - -#if SIZEOF_INT < SIZEOF_LONG -# define _cffi_from_c_unsigned_int PyInt_FromLong -#else -# define _cffi_from_c_unsigned_int PyLong_FromUnsignedLong -#endif - -#if SIZEOF_LONG < SIZEOF_LONG_LONG -# define _cffi_from_c_long_long PyLong_FromLongLong -#else -# define _cffi_from_c_long_long PyInt_FromLong -#endif - -#define _cffi_to_c_long PyInt_AsLong -#define _cffi_to_c_double PyFloat_AsDouble -#define _cffi_to_c_float PyFloat_AsDouble - -#define _cffi_to_c_char_p \ - ((char *(*)(PyObject *))_cffi_exports[0]) -#define _cffi_to_c_signed_char \ - ((signed char(*)(PyObject *))_cffi_exports[1]) -#define _cffi_to_c_unsigned_char \ - ((unsigned char(*)(PyObject *))_cffi_exports[2]) -#define _cffi_to_c_short \ - ((short(*)(PyObject *))_cffi_exports[3]) -#define _cffi_to_c_unsigned_short \ - ((unsigned short(*)(PyObject *))_cffi_exports[4]) - -#if SIZEOF_INT < SIZEOF_LONG -# define _cffi_to_c_int \ - ((int(*)(PyObject *))_cffi_exports[5]) -# define _cffi_to_c_unsigned_int \ - ((unsigned int(*)(PyObject *))_cffi_exports[6]) -#else -# define _cffi_to_c_int _cffi_to_c_long -# define _cffi_to_c_unsigned_int _cffi_to_c_unsigned_long -#endif - -#define _cffi_to_c_unsigned_long \ - ((unsigned long(*)(PyObject *))_cffi_exports[7]) -#define _cffi_to_c_unsigned_long_long \ - ((unsigned long long(*)(PyObject *))_cffi_exports[8]) -#define _cffi_to_c_char \ - ((char(*)(PyObject *))_cffi_exports[9]) -#define _cffi_from_c_pointer \ - ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[10]) -#define _cffi_to_c_pointer \ - ((char *(*)(PyObject *, CTypeDescrObject *))_cffi_exports[11]) -#define _cffi_get_struct_layout \ - ((PyObject *(*)(Py_ssize_t[]))_cffi_exports[12]) -#define _cffi_restore_errno \ - ((void(*)(void))_cffi_exports[13]) -#define _cffi_save_errno \ - ((void(*)(void))_cffi_exports[14]) -#define _cffi_from_c_char \ - ((PyObject *(*)(char))_cffi_exports[15]) -#define _cffi_from_c_deref \ - ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[16]) -#define _cffi_to_c \ - ((int(*)(char *, CTypeDescrObject *, PyObject *))_cffi_exports[17]) -#define _cffi_from_c_struct \ - ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[18]) -#define _cffi_to_c_wchar_t \ - ((wchar_t(*)(PyObject *))_cffi_exports[19]) -#define _cffi_from_c_wchar_t \ - ((PyObject *(*)(wchar_t))_cffi_exports[20]) -#define _CFFI_NUM_EXPORTS 21 - -#if SIZEOF_LONG < SIZEOF_LONG_LONG -# define _cffi_to_c_long_long PyLong_AsLongLong -#else -# define _cffi_to_c_long_long _cffi_to_c_long -#endif - -typedef struct _ctypedescr CTypeDescrObject; - -static void *_cffi_exports[_CFFI_NUM_EXPORTS]; -static PyObject *_cffi_types, *_cffi_VerificationError; - -static PyObject *_cffi_setup_custom(PyObject *lib); /* forward */ - -static PyObject *_cffi_setup(PyObject *self, PyObject *args) -{ - PyObject *library; - if (!PyArg_ParseTuple(args, "OOO", &_cffi_types, &_cffi_VerificationError, - &library)) - return NULL; - Py_INCREF(_cffi_types); - Py_INCREF(_cffi_VerificationError); - return _cffi_setup_custom(library); -} - -static void _cffi_init(void) -{ - PyObject *module = PyImport_ImportModule("_cffi_backend"); - PyObject *c_api_object; - - if (module == NULL) - return; - - c_api_object = PyObject_GetAttrString(module, "_C_API"); - if (c_api_object == NULL) - return; - if (!PyCObject_Check(c_api_object)) { - PyErr_SetNone(PyExc_ImportError); - return; - } - memcpy(_cffi_exports, PyCObject_AsVoidPtr(c_api_object), - _CFFI_NUM_EXPORTS * sizeof(void *)); -} - -#define _cffi_type(num) ((CTypeDescrObject *)PyList_GET_ITEM(_cffi_types, num)) - /**********/ ''' -- cgit v1.2.1 From c22e6f1b098eb343293e3055f573ff7e3c49aaa6 Mon Sep 17 00:00:00 2001 From: Armin Rigo Date: Fri, 27 Jul 2012 14:50:25 +0200 Subject: test_verify.test_ffi_full_struct --- cffi/verifier.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/cffi/verifier.py b/cffi/verifier.py index f4a8547..49711cb 100644 --- a/cffi/verifier.py +++ b/cffi/verifier.py @@ -386,8 +386,7 @@ class Verifier(object): prnt(' { %s = &p->%s; (void)tmp; }' % ( ftype.get_c_name('(*tmp)'), fname)) prnt('}') - prnt('static PyObject *') - prnt('%s(PyObject *self, PyObject *noarg)' % (layoutfuncname,)) + prnt('ssize_t %s(void)' % (layoutfuncname,)) prnt('{') prnt(' struct _cffi_aligncheck { char x; %s y; };' % cname) if tp.partial: @@ -418,12 +417,10 @@ class Verifier(object): 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(' return -1;') prnt(' }') prnt(' else {') - prnt(' Py_INCREF(Py_True);') - prnt(' return Py_True;') + prnt(' return 0;') prnt(' }') prnt(' /* the next line is not executed, but compiled */') prnt(' %s(0);' % (checkfuncname,)) @@ -443,12 +440,13 @@ class Verifier(object): layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) cname = ('%s %s' % (prefix, name)).strip() # - function = getattr(module, layoutfuncname) + BFunc = self.ffi.typeof("ssize_t(*)(void)") + function = module.load_function(BFunc, layoutfuncname) layout = function() - if layout is False: + if layout < 0: raise ffiplatform.VerificationError( "incompatible layout for %s" % cname) - elif layout is True: + elif layout == 0: assert not tp.partial else: totalsize = layout[0] @@ -640,6 +638,8 @@ class Verifier(object): cffimod_header = r''' #include +#include +#include /* XXX for ssize_t */ /**********/ ''' -- cgit v1.2.1 From a91c764104b435dcc52c7749befbac88896a5308 Mon Sep 17 00:00:00 2001 From: Armin Rigo Date: Fri, 27 Jul 2012 14:54:59 +0200 Subject: test_verify.test_ffi_nonfull_struct --- cffi/verifier.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/cffi/verifier.py b/cffi/verifier.py index 49711cb..9f91451 100644 --- a/cffi/verifier.py +++ b/cffi/verifier.py @@ -386,11 +386,11 @@ class Verifier(object): prnt(' { %s = &p->%s; (void)tmp; }' % ( ftype.get_c_name('(*tmp)'), fname)) prnt('}') - prnt('ssize_t %s(void)' % (layoutfuncname,)) + prnt('ssize_t %s(ssize_t i)' % (layoutfuncname,)) prnt('{') prnt(' struct _cffi_aligncheck { char x; %s y; };' % cname) if tp.partial: - prnt(' static Py_ssize_t nums[] = {') + prnt(' static ssize_t nums[] = {') prnt(' sizeof(%s),' % cname) prnt(' offsetof(struct _cffi_aligncheck, y),') for fname in tp.fldnames: @@ -398,7 +398,8 @@ class Verifier(object): prnt(' sizeof(((%s *)0)->%s),' % (cname, fname)) prnt(' -1') prnt(' };') - prnt(' return _cffi_get_struct_layout(nums);') + prnt(' if (i < 0) return 1;') + prnt(' return nums[i];') else: ffi = self.ffi BStruct = ffi._get_cached_btype(tp) @@ -440,15 +441,20 @@ class Verifier(object): layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) cname = ('%s %s' % (prefix, name)).strip() # - BFunc = self.ffi.typeof("ssize_t(*)(void)") + BFunc = self.ffi.typeof("ssize_t(*)(ssize_t)") function = module.load_function(BFunc, layoutfuncname) - layout = function() + layout = function(-1) if layout < 0: raise ffiplatform.VerificationError( "incompatible layout for %s" % cname) elif layout == 0: assert not tp.partial else: + layout = [] + while True: + x = function(len(layout)) + if x < 0: break + layout.append(x) totalsize = layout[0] totalalignment = layout[1] fieldofs = layout[2::2] -- cgit v1.2.1 From cea2f95f34007c12b08068dba9030b98c443bfda Mon Sep 17 00:00:00 2001 From: Armin Rigo Date: Fri, 27 Jul 2012 15:11:42 +0200 Subject: test_global_const_int_size --- cffi/verifier.py | 39 ++++++++++++++++----------------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/cffi/verifier.py b/cffi/verifier.py index 9f91451..91a7a11 100644 --- a/cffi/verifier.py +++ b/cffi/verifier.py @@ -131,7 +131,7 @@ class Verifier(object): # The following two 'chained_list_constants' items contains # the head of these two chained lists, as a string that gives the # call to do, if any. - self._chained_list_constants = ['0', '0'] + ##self._chained_list_constants = ['0', '0'] # prnt = self._prnt # first paste some standard set of lines that are mostly '#define' @@ -139,7 +139,6 @@ class Verifier(object): prnt() # then paste the C source given by the user, verbatim. prnt(self.preamble) - prnt() # # call generate_cpy_xxx_decl(), for every xxx found from # ffi._parser._declarations. This generates all the functions. @@ -489,42 +488,27 @@ class Verifier(object): # constants, likely declared with '#define' def _generate_cpy_const(self, is_int, name, tp=None, category='const', - vartp=None, delayed=True): + vartp=None): prnt = self._prnt funcname = '_cffi_%s_%s' % (category, name) - prnt('static int %s(PyObject *lib)' % funcname) + prnt('int %s(long long *out_value)' % funcname) prnt('{') - prnt(' PyObject *o;') - prnt(' int res;') if not is_int: prnt(' %s;' % (vartp or tp).get_c_name(' i')) else: assert category == 'const' # if not is_int: + xxxxxxxxxxxx if category == 'var': realexpr = '&' + name else: realexpr = name prnt(' i = (%s);' % (realexpr,)) prnt(' o = %s;' % (self._convert_expr_from_c(tp, 'i'),)) - assert delayed else: - prnt(' if (LONG_MIN <= (%s) && (%s) <= LONG_MAX)' % (name, name)) - prnt(' o = PyInt_FromLong((long)(%s));' % (name,)) - prnt(' else if ((%s) <= 0)' % (name,)) - prnt(' o = PyLong_FromLongLong((long long)(%s));' % (name,)) - prnt(' else') - prnt(' o = PyLong_FromUnsignedLongLong(' - '(unsigned long long)(%s));' % (name,)) - prnt(' if (o == NULL)') - prnt(' return -1;') - prnt(' res = PyObject_SetAttrString(lib, "%s", o);' % name) - prnt(' Py_DECREF(o);') - prnt(' if (res < 0)') - prnt(' return -1;') - prnt(' return %s;' % self._chained_list_constants[delayed]) - self._chained_list_constants[delayed] = funcname + '(lib)' + prnt(' *out_value = (long long)(%s);' % (name,)) + prnt(' return (%s) <= 0;' % (name,)) prnt('}') prnt() @@ -539,7 +523,16 @@ class Verifier(object): _generate_cpy_constant_method = _generate_nothing _loading_cpy_constant = _loaded_noop - _loaded_cpy_constant = _loaded_noop + + def _loaded_cpy_constant(self, tp, name, module, library): + BFunc = self.ffi.typeof("int(*)(long long*)") + function = module.load_function(BFunc, '_cffi_const_%s' % name) + p = self.ffi.new("long long*") + negative = function(p) + value = int(p[0]) + if value < 0 and not negative: + value += (1 << (8*self.ffi.sizeof("long long"))) + setattr(library, name, value) # ---------- # enums -- cgit v1.2.1 From 98f2ce53293a6ee977871984752a3284808001f4 Mon Sep 17 00:00:00 2001 From: Armin Rigo Date: Fri, 27 Jul 2012 15:20:36 +0200 Subject: test_verify.test_global_constants_non_int --- cffi/verifier.py | 56 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/cffi/verifier.py b/cffi/verifier.py index 91a7a11..e201a1a 100644 --- a/cffi/verifier.py +++ b/cffi/verifier.py @@ -487,29 +487,21 @@ class Verifier(object): # ---------- # constants, likely declared with '#define' - def _generate_cpy_const(self, is_int, name, tp=None, category='const', - vartp=None): + def _generate_cpy_const(self, is_int, name, tp=None): prnt = self._prnt - funcname = '_cffi_%s_%s' % (category, name) - prnt('int %s(long long *out_value)' % funcname) - prnt('{') - if not is_int: - prnt(' %s;' % (vartp or tp).get_c_name(' i')) - else: - assert category == 'const' - # - if not is_int: - xxxxxxxxxxxx - if category == 'var': - realexpr = '&' + name - else: - realexpr = name - prnt(' i = (%s);' % (realexpr,)) - prnt(' o = %s;' % (self._convert_expr_from_c(tp, 'i'),)) - else: + funcname = '_cffi_const_%s' % name + if is_int: + prnt('int %s(long long *out_value)' % funcname) + prnt('{') prnt(' *out_value = (long long)(%s);' % (name,)) prnt(' return (%s) <= 0;' % (name,)) - prnt('}') + prnt('}') + else: + assert tp is not None + prnt('void %s(%s)' % (funcname, tp.get_c_name('(*out_value)'))) + prnt('{') + prnt(' *out_value = (%s);' % (name,)) + prnt('}') prnt() def _generate_cpy_constant_collecttype(self, tp, name): @@ -525,13 +517,23 @@ class Verifier(object): _loading_cpy_constant = _loaded_noop def _loaded_cpy_constant(self, tp, name, module, library): - BFunc = self.ffi.typeof("int(*)(long long*)") - function = module.load_function(BFunc, '_cffi_const_%s' % name) - p = self.ffi.new("long long*") - negative = function(p) - value = int(p[0]) - if value < 0 and not negative: - value += (1 << (8*self.ffi.sizeof("long long"))) + funcname = '_cffi_const_%s' % name + is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() + if is_int: + BFunc = self.ffi.typeof("int(*)(long long*)") + function = module.load_function(BFunc, funcname) + p = self.ffi.new("long long*") + negative = function(p) + value = int(p[0]) + if value < 0 and not negative: + value += (1 << (8*self.ffi.sizeof("long long"))) + else: + tppname = tp.get_c_name('*') + BFunc = self.ffi.typeof("int(*)(%s)" % (tppname,)) + function = module.load_function(BFunc, funcname) + p = self.ffi.new(tppname) + function(p) + value = p[0] setattr(library, name, value) # ---------- -- cgit v1.2.1 From 81a6a3c9f599faeed781f982b99c80a82d8e08dd Mon Sep 17 00:00:00 2001 From: Armin Rigo Date: Fri, 27 Jul 2012 15:29:08 +0200 Subject: test_nonfull_enum --- cffi/verifier.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/cffi/verifier.py b/cffi/verifier.py index e201a1a..10ebfee 100644 --- a/cffi/verifier.py +++ b/cffi/verifier.py @@ -516,9 +516,8 @@ class Verifier(object): _generate_cpy_constant_method = _generate_nothing _loading_cpy_constant = _loaded_noop - def _loaded_cpy_constant(self, tp, name, module, library): + def _load_constant(self, is_int, tp, name, module): funcname = '_cffi_const_%s' % name - is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() if is_int: BFunc = self.ffi.typeof("int(*)(long long*)") function = module.load_function(BFunc, funcname) @@ -534,6 +533,11 @@ class Verifier(object): p = self.ffi.new(tppname) function(p) value = p[0] + return value + + def _loaded_cpy_constant(self, tp, name, module, library): + is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() + value = self._load_constant(is_int, tp, name, module) setattr(library, name, value) # ---------- @@ -542,7 +546,7 @@ class Verifier(object): def _generate_cpy_enum_decl(self, tp, name): if tp.partial: for enumerator in tp.enumerators: - self._generate_cpy_const(True, enumerator, delayed=False) + self._generate_cpy_const(True, enumerator) return # funcname = '_cffi_enum_%s' % name @@ -569,7 +573,7 @@ class Verifier(object): def _loading_cpy_enum(self, tp, name, module): if tp.partial: - enumvalues = [getattr(module, enumerator) + enumvalues = [self._load_constant(True, tp, enumerator, module) for enumerator in tp.enumerators] tp.enumvalues = tuple(enumvalues) tp.partial = False -- cgit v1.2.1 From ea579838733191c5341d61907bdffe12523df940 Mon Sep 17 00:00:00 2001 From: Armin Rigo Date: Fri, 27 Jul 2012 15:35:35 +0200 Subject: test_verify.test_full_enum --- cffi/verifier.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/cffi/verifier.py b/cffi/verifier.py index 10ebfee..d14abf6 100644 --- a/cffi/verifier.py +++ b/cffi/verifier.py @@ -551,19 +551,17 @@ class Verifier(object): # funcname = '_cffi_enum_%s' % name prnt = self._prnt - prnt('static int %s(PyObject *lib)' % funcname) + prnt('int %s(char *out_error)' % funcname) prnt('{') for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): prnt(' if (%s != %d) {' % (enumerator, enumvalue)) - prnt(' PyErr_Format(_cffi_VerificationError,') - prnt(' "in enum %s: %s has the real value %d, ' - 'not %d",') - prnt(' "%s", "%s", (int)%s, %d);' % ( + prnt(' snprintf(out_error, 255, "in enum %s: ' + '%s has the real value %d, not %d",') + prnt(' "%s", "%s", (int)%s, %d);' % ( name, enumerator, enumerator, enumvalue)) prnt(' return -1;') prnt(' }') - prnt(' return %s;' % self._chained_list_constants[True]) - self._chained_list_constants[True] = funcname + '(lib)' + prnt(' return 0;') prnt('}') prnt() @@ -577,6 +575,13 @@ class Verifier(object): for enumerator in tp.enumerators] tp.enumvalues = tuple(enumvalues) tp.partial = False + else: + BFunc = self.ffi.typeof("int(*)(char*)") + funcname = '_cffi_enum_%s' % name + function = module.load_function(BFunc, funcname) + p = self.ffi.new("char[]", 256) + if function(p): + raise ffiplatform.VerificationError(str(p)) def _loaded_cpy_enum(self, tp, name, module, library): for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): @@ -642,6 +647,7 @@ class Verifier(object): prnt('}') cffimod_header = r''' +#include #include #include #include /* XXX for ssize_t */ -- cgit v1.2.1 From cf0b5e0f1676bc06281bc82bf68f842d591c7854 Mon Sep 17 00:00:00 2001 From: Armin Rigo Date: Fri, 27 Jul 2012 15:36:25 +0200 Subject: test_verify.test_get_set_errno --- cffi/verifier.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cffi/verifier.py b/cffi/verifier.py index d14abf6..ad15d64 100644 --- a/cffi/verifier.py +++ b/cffi/verifier.py @@ -650,6 +650,7 @@ cffimod_header = r''' #include #include #include +#include #include /* XXX for ssize_t */ /**********/ -- cgit v1.2.1 From e7c53bd8e646aa49eb0138347c3a7a4814316222 Mon Sep 17 00:00:00 2001 From: Armin Rigo Date: Fri, 27 Jul 2012 15:38:52 +0200 Subject: test_define_int --- cffi/verifier.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cffi/verifier.py b/cffi/verifier.py index ad15d64..7add02e 100644 --- a/cffi/verifier.py +++ b/cffi/verifier.py @@ -597,7 +597,10 @@ class Verifier(object): _generate_cpy_macro_collecttype = _generate_nothing _generate_cpy_macro_method = _generate_nothing _loading_cpy_macro = _loaded_noop - _loaded_cpy_macro = _loaded_noop + + def _loaded_cpy_macro(self, tp, name, module, library): + value = self._load_constant(True, tp, name, module) + setattr(library, name, value) # ---------- # global variables -- cgit v1.2.1 From 62ea9e6bfda96cf10b46d7202878a76d5cbe7e90 Mon Sep 17 00:00:00 2001 From: Armin Rigo Date: Fri, 27 Jul 2012 15:51:07 +0200 Subject: test_verify.test_access_variable --- cffi/verifier.py | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/cffi/verifier.py b/cffi/verifier.py index 7add02e..cd6f2cc 100644 --- a/cffi/verifier.py +++ b/cffi/verifier.py @@ -16,8 +16,8 @@ class Verifier(object): self.preamble = preamble self.kwds = kwds # - m = hashlib.md5('\x00'.join([sys.version[:3], __version__, preamble] + - ffi._cdefsources)) + m = hashlib.md5('\x00'.join([sys.version[:3], __version__, 'pypy', + preamble] + ffi._cdefsources)) modulename = '_cffi_%s' % m.hexdigest() suffix = _get_so_suffix() self.sourcefilename = os.path.join(_TMPDIR, modulename + '.c') @@ -487,10 +487,11 @@ class Verifier(object): # ---------- # constants, likely declared with '#define' - def _generate_cpy_const(self, is_int, name, tp=None): + def _generate_cpy_const(self, is_int, name, tp=None, category='const'): prnt = self._prnt - funcname = '_cffi_const_%s' % name + funcname = '_cffi_%s_%s' % (category, name) if is_int: + assert category == 'const' prnt('int %s(long long *out_value)' % funcname) prnt('{') prnt(' *out_value = (long long)(%s);' % (name,)) @@ -498,9 +499,13 @@ class Verifier(object): prnt('}') else: assert tp is not None - prnt('void %s(%s)' % (funcname, tp.get_c_name('(*out_value)'))) + prnt(tp.get_c_name(' %s(void)' % funcname),) prnt('{') - prnt(' *out_value = (%s);' % (name,)) + if category == 'var': + ampersand = '&' + else: + ampersand = '' + prnt(' return (%s%s);' % (ampersand, name)) prnt('}') prnt() @@ -527,12 +532,9 @@ class Verifier(object): if value < 0 and not negative: value += (1 << (8*self.ffi.sizeof("long long"))) else: - tppname = tp.get_c_name('*') - BFunc = self.ffi.typeof("int(*)(%s)" % (tppname,)) + BFunc = self.ffi.typeof(tp.get_c_name('(*)(void)')) function = module.load_function(BFunc, funcname) - p = self.ffi.new(tppname) - function(p) - value = p[0] + value = function() return value def _loaded_cpy_constant(self, tp, name, module, library): @@ -628,8 +630,10 @@ class Verifier(object): return # sense that "a=..." is forbidden # remove ptr= from the library instance, and replace # it by a property on the class, which reads/writes into ptr[0]. - ptr = getattr(library, name) - delattr(library, name) + funcname = '_cffi_var_%s' % name + BFunc = self.ffi.typeof(tp.get_c_name('*(*)(void)')) + function = module.load_function(BFunc, funcname) + ptr = function() def getter(library): return ptr[0] def setter(library, value): -- cgit v1.2.1 From eb5e10b608a715e35024c0e751953ffae65cdf71 Mon Sep 17 00:00:00 2001 From: Armin Rigo Date: Fri, 27 Jul 2012 15:55:12 +0200 Subject: test_verify.test_access_array_variable --- cffi/verifier.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cffi/verifier.py b/cffi/verifier.py index cd6f2cc..911bf39 100644 --- a/cffi/verifier.py +++ b/cffi/verifier.py @@ -617,7 +617,7 @@ class Verifier(object): def _generate_cpy_variable_decl(self, tp, name): if isinstance(tp, model.ArrayType): tp_ptr = model.PointerType(tp.item) - self._generate_cpy_const(False, name, tp, vartp=tp_ptr) + self._generate_cpy_const(False, name, tp_ptr) else: tp_ptr = model.PointerType(tp) self._generate_cpy_const(False, name, tp_ptr, category='var') @@ -627,7 +627,11 @@ class Verifier(object): def _loaded_cpy_variable(self, tp, name, module, library): if isinstance(tp, model.ArrayType): # int a[5] is "constant" in the - return # sense that "a=..." is forbidden + # sense that "a=..." is forbidden + tp_ptr = model.PointerType(tp.item) + value = self._load_constant(False, tp_ptr, name, module) + setattr(library, name, value) + return # remove ptr= from the library instance, and replace # it by a property on the class, which reads/writes into ptr[0]. funcname = '_cffi_var_%s' % name -- cgit v1.2.1 From 23542af0a6eed1ee4f60d7af6676c7a5602a6614 Mon Sep 17 00:00:00 2001 From: Armin Rigo Date: Fri, 27 Jul 2012 15:58:50 +0200 Subject: test_verify.test_varargs --- cffi/verifier.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/cffi/verifier.py b/cffi/verifier.py index 911bf39..bffdbd2 100644 --- a/cffi/verifier.py +++ b/cffi/verifier.py @@ -337,10 +337,12 @@ class Verifier(object): def _loaded_cpy_function(self, tp, name, module, library): if tp.ellipsis: - return - BFunc = self.ffi._get_cached_btype(tp) - wrappername = '_cffi_f_%s' % name - setattr(library, name, module.load_function(BFunc, wrappername)) + newfunction = self._load_constant(False, tp, name, module) + else: + BFunc = self.ffi._get_cached_btype(tp) + wrappername = '_cffi_f_%s' % name + newfunction = module.load_function(BFunc, wrappername) + setattr(library, name, newfunction) # ---------- # named structs @@ -661,6 +663,7 @@ cffimod_header = r''' #include #include #include +#include #include #include /* XXX for ssize_t */ -- cgit v1.2.1 From 8b6ca900b938c745c448142e9ea12f5b146fab30 Mon Sep 17 00:00:00 2001 From: Armin Rigo Date: Fri, 27 Jul 2012 16:02:05 +0200 Subject: Garbage-collection of some code --- cffi/verifier.py | 129 ------------------------------------------------------- 1 file changed, 129 deletions(-) diff --git a/cffi/verifier.py b/cffi/verifier.py index bffdbd2..17577a2 100644 --- a/cffi/verifier.py +++ b/cffi/verifier.py @@ -79,26 +79,11 @@ class Verifier(object): if f is not None: f.close() self.modulefilename = filename - self._collect_types() self._status = 'module' def _prnt(self, what=''): print >> self._f, what - def _gettypenum(self, type): - # a KeyError here is a bug. please report it! :-) - return self._typesdict[type] - - def _collect_types(self): - self._typesdict = {} - self._generate("collecttype") - - def _do_collect_type(self, tp): - if (not isinstance(tp, model.PrimitiveType) and - tp not in self._typesdict): - num = len(self._typesdict) - self._typesdict[tp] = num - def _write_source(self, file=None): must_close = (file is None) if must_close: @@ -114,7 +99,6 @@ class Verifier(object): self._status = 'source' def _write_source_to_f(self): - self._collect_types() # # The new module will have a _cffi_setup() function that receives # objects from the ffi world, and that calls some setup code in @@ -218,82 +202,16 @@ class Verifier(object): def _loaded_noop(self, tp, name, module, **kwds): pass - # ---------- - - def _convert_funcarg_to_c(self, tp, fromvar, tovar, errcode): - extraarg = '' - if isinstance(tp, model.PrimitiveType): - converter = '_cffi_to_c_%s' % (tp.name.replace(' ', '_'),) - errvalue = '-1' - # - elif isinstance(tp, model.PointerType): - if (isinstance(tp.totype, model.PrimitiveType) and - tp.totype.name == 'char'): - converter = '_cffi_to_c_char_p' - else: - converter = '(%s)_cffi_to_c_pointer' % tp.get_c_name('') - extraarg = ', _cffi_type(%d)' % self._gettypenum(tp) - errvalue = 'NULL' - # - elif isinstance(tp, (model.StructOrUnion, model.EnumType)): - # a struct (not a struct pointer) as a function argument - self._prnt(' if (_cffi_to_c((char *)&%s, _cffi_type(%d), %s) < 0)' - % (tovar, self._gettypenum(tp), fromvar)) - self._prnt(' %s;' % errcode) - return - # - elif isinstance(tp, model.FunctionPtrType): - converter = '(%s)_cffi_to_c_pointer' % tp.get_c_name('') - extraarg = ', _cffi_type(%d)' % self._gettypenum(tp) - errvalue = 'NULL' - # - else: - raise NotImplementedError(tp) - # - self._prnt(' %s = %s(%s%s);' % (tovar, converter, fromvar, extraarg)) - self._prnt(' if (%s == (%s)%s && PyErr_Occurred())' % ( - tovar, tp.get_c_name(''), errvalue)) - self._prnt(' %s;' % errcode) - - def _convert_expr_from_c(self, tp, var): - if isinstance(tp, model.PrimitiveType): - return '_cffi_from_c_%s(%s)' % (tp.name.replace(' ', '_'), var) - elif isinstance(tp, (model.PointerType, model.FunctionPtrType)): - return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % ( - var, self._gettypenum(tp)) - elif isinstance(tp, model.ArrayType): - return '_cffi_from_c_deref((char *)%s, _cffi_type(%d))' % ( - var, self._gettypenum(tp)) - elif isinstance(tp, model.StructType): - return '_cffi_from_c_struct((char *)&%s, _cffi_type(%d))' % ( - var, self._gettypenum(tp)) - elif isinstance(tp, model.EnumType): - return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( - var, self._gettypenum(tp)) - else: - raise NotImplementedError(tp) - # ---------- # typedefs: generates no code so far - _generate_cpy_typedef_collecttype = _generate_nothing _generate_cpy_typedef_decl = _generate_nothing - _generate_cpy_typedef_method = _generate_nothing _loading_cpy_typedef = _loaded_noop _loaded_cpy_typedef = _loaded_noop # ---------- # function declarations - def _generate_cpy_function_collecttype(self, tp, name): - assert isinstance(tp, model.FunctionPtrType) - if tp.ellipsis: - self._do_collect_type(tp) - else: - for type in tp.args: - self._do_collect_type(type) - self._do_collect_type(tp.result) - def _generate_cpy_function_decl(self, tp, name): assert isinstance(tp, model.FunctionPtrType) if tp.ellipsis: @@ -321,18 +239,6 @@ class Verifier(object): prnt('}') prnt() - def _generate_cpy_function_method(self, tp, name): - if tp.ellipsis: - return - numargs = len(tp.args) - if numargs == 0: - meth = 'METH_NOARGS' - elif numargs == 1: - meth = 'METH_O' - else: - meth = 'METH_VARARGS' - self._prnt(' {"%s", _cffi_f_%s, %s},' % (name, name, meth)) - _loading_cpy_function = _loaded_noop def _loaded_cpy_function(self, tp, name, module, library): @@ -347,15 +253,10 @@ class Verifier(object): # ---------- # named structs - _generate_cpy_struct_collecttype = _generate_nothing - def _generate_cpy_struct_decl(self, tp, name): assert name == tp.name self._generate_struct_or_union_decl(tp, 'struct', name) - def _generate_cpy_struct_method(self, tp, name): - self._generate_struct_or_union_method(tp, 'struct', name) - def _loading_cpy_struct(self, tp, name, module): self._loading_struct_or_union(tp, 'struct', name, module) @@ -429,13 +330,6 @@ class Verifier(object): prnt('}') prnt() - def _generate_struct_or_union_method(self, tp, prefix, name): - if tp.fldnames is None: - return # nothing to do with opaque structs - layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) - self._prnt(' {"%s", %s, METH_NOARGS},' % (layoutfuncname, - layoutfuncname)) - def _loading_struct_or_union(self, tp, prefix, name, module): if tp.fldnames is None: return # nothing to do with opaque structs @@ -472,14 +366,9 @@ class Verifier(object): # 'anonymous' declarations. These are produced for anonymous structs # or unions; the 'name' is obtained by a typedef. - _generate_cpy_anonymous_collecttype = _generate_nothing - def _generate_cpy_anonymous_decl(self, tp, name): self._generate_struct_or_union_decl(tp, '', name) - def _generate_cpy_anonymous_method(self, tp, name): - self._generate_struct_or_union_method(tp, '', name) - def _loading_cpy_anonymous(self, tp, name, module): self._loading_struct_or_union(tp, '', name, module) @@ -511,16 +400,10 @@ class Verifier(object): prnt('}') prnt() - def _generate_cpy_constant_collecttype(self, tp, name): - is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() - if not is_int: - self._do_collect_type(tp) - def _generate_cpy_constant_decl(self, tp, name): is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() self._generate_cpy_const(is_int, name, tp) - _generate_cpy_constant_method = _generate_nothing _loading_cpy_constant = _loaded_noop def _load_constant(self, is_int, tp, name, module): @@ -569,8 +452,6 @@ class Verifier(object): prnt('}') prnt() - _generate_cpy_enum_collecttype = _generate_nothing - _generate_cpy_enum_method = _generate_nothing _loading_cpy_enum = _loaded_noop def _loading_cpy_enum(self, tp, name, module): @@ -598,8 +479,6 @@ class Verifier(object): assert tp == '...' self._generate_cpy_const(True, name) - _generate_cpy_macro_collecttype = _generate_nothing - _generate_cpy_macro_method = _generate_nothing _loading_cpy_macro = _loaded_noop def _loaded_cpy_macro(self, tp, name, module, library): @@ -609,13 +488,6 @@ class Verifier(object): # ---------- # global variables - def _generate_cpy_variable_collecttype(self, tp, name): - if isinstance(tp, model.ArrayType): - self._do_collect_type(tp) - else: - tp_ptr = model.PointerType(tp) - self._do_collect_type(tp_ptr) - def _generate_cpy_variable_decl(self, tp, name): if isinstance(tp, model.ArrayType): tp_ptr = model.PointerType(tp.item) @@ -624,7 +496,6 @@ class Verifier(object): tp_ptr = model.PointerType(tp) self._generate_cpy_const(False, name, tp_ptr, category='var') - _generate_cpy_variable_method = _generate_nothing _loading_cpy_variable = _loaded_noop def _loaded_cpy_variable(self, tp, name, module, library): -- cgit v1.2.1 From 1908c2576c3706ad5c679abe8909bdacbdc90d59 Mon Sep 17 00:00:00 2001 From: Armin Rigo Date: Fri, 27 Jul 2012 18:07:59 +0200 Subject: Cleaning. --- cffi/verifier.py | 65 ++++++++++++-------------------------------------------- 1 file changed, 14 insertions(+), 51 deletions(-) diff --git a/cffi/verifier.py b/cffi/verifier.py index 17577a2..301c30b 100644 --- a/cffi/verifier.py +++ b/cffi/verifier.py @@ -99,38 +99,15 @@ class Verifier(object): self._status = 'source' def _write_source_to_f(self): - # - # The new module will have a _cffi_setup() function that receives - # objects from the ffi world, and that calls some setup code in - # the module. This setup code is split in several independent - # functions, e.g. one per constant. The functions are "chained" - # by ending in a tail call to each other. - # - # This is further split in two chained lists, depending on if we - # can do it at import-time or if we must wait for _cffi_setup() to - # provide us with the objects. This is needed because we - # need the values of the enum constants in order to build the - # that we may have to pass to _cffi_setup(). - # - # The following two 'chained_list_constants' items contains - # the head of these two chained lists, as a string that gives the - # call to do, if any. - ##self._chained_list_constants = ['0', '0'] - # prnt = self._prnt - # first paste some standard set of lines that are mostly '#define' + # first paste some standard set of lines that are mostly '#include' prnt(cffimod_header) - prnt() # then paste the C source given by the user, verbatim. prnt(self.preamble) # # call generate_cpy_xxx_decl(), for every xxx found from # ffi._parser._declarations. This generates all the functions. self._generate("decl") - # - # implement the function _cffi_setup_custom() as calling the - # head of the chained list. - self._generate_setup_custom() def _compile_module(self): # compile this C source @@ -217,7 +194,7 @@ class Verifier(object): if tp.ellipsis: # cannot support vararg functions better than this: check for its # exact type (including the fixed arguments), and build it as a - # constant function pointer (no CPython wrapper) + # constant function pointer (no _cffi_f_%s wrapper) self._generate_cpy_const(False, name, tp) return prnt = self._prnt @@ -293,14 +270,13 @@ class Verifier(object): prnt(' struct _cffi_aligncheck { char x; %s y; };' % cname) if tp.partial: prnt(' static ssize_t nums[] = {') - prnt(' sizeof(%s),' % cname) + prnt(' 1, sizeof(%s),' % cname) prnt(' offsetof(struct _cffi_aligncheck, y),') for fname in tp.fldnames: prnt(' offsetof(%s, %s),' % (cname, fname)) prnt(' sizeof(((%s *)0)->%s),' % (cname, fname)) prnt(' -1') prnt(' };') - prnt(' if (i < 0) return 1;') prnt(' return nums[i];') else: ffi = self.ffi @@ -338,22 +314,24 @@ class Verifier(object): # BFunc = self.ffi.typeof("ssize_t(*)(ssize_t)") function = module.load_function(BFunc, layoutfuncname) - layout = function(-1) + layout = function(0) if layout < 0: raise ffiplatform.VerificationError( "incompatible layout for %s" % cname) elif layout == 0: assert not tp.partial else: - layout = [] + totalsize = function(1) + totalalignment = function(2) + fieldofs = [] + fieldsize = [] + num = 3 while True: - x = function(len(layout)) + x = function(num) if x < 0: break - layout.append(x) - totalsize = layout[0] - totalalignment = layout[1] - fieldofs = layout[2::2] - fieldsize = layout[3::2] + fieldofs.append(x) + fieldsize.append(function(num+1)) + num += 2 assert len(fieldofs) == len(fieldsize) == len(tp.fldnames) tp.fixedlayout = fieldofs, fieldsize, totalsize, totalalignment @@ -465,7 +443,7 @@ class Verifier(object): funcname = '_cffi_enum_%s' % name function = module.load_function(BFunc, funcname) p = self.ffi.new("char[]", 256) - if function(p): + if function(p) < 0: raise ffiplatform.VerificationError(str(p)) def _loaded_cpy_enum(self, tp, name, module, library): @@ -517,19 +495,6 @@ class Verifier(object): ptr[0] = value setattr(library.__class__, name, property(getter, setter)) - # ---------- - - def _generate_setup_custom(self): - return #XXX - prnt = self._prnt - prnt('static PyObject *_cffi_setup_custom(PyObject *lib)') - prnt('{') - prnt(' if (%s < 0)' % self._chained_list_constants[True]) - prnt(' return NULL;') - prnt(' Py_INCREF(Py_None);') - prnt(' return Py_None;') - prnt('}') - cffimod_header = r''' #include #include @@ -537,8 +502,6 @@ cffimod_header = r''' #include #include #include /* XXX for ssize_t */ - -/**********/ ''' # ____________________________________________________________ -- cgit v1.2.1 From c220bd4463c82f0bf4031080f4b57a257aaf253e Mon Sep 17 00:00:00 2001 From: Armin Rigo Date: Fri, 27 Jul 2012 18:27:24 +0200 Subject: Fix the last failure in test_verify. --- c/_cffi_backend.c | 12 +++++++++++- cffi/verifier.py | 23 ++++++++++++++++++----- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c index 92b3431..77a967f 100644 --- a/c/_cffi_backend.c +++ b/c/_cffi_backend.c @@ -1729,8 +1729,18 @@ cdata_call(CDataObject *cd, PyObject *args, PyObject *kwds) } #endif } - if (convert_from_object(data, argtype, obj) < 0) + if (convert_from_object(data, argtype, obj) < 0) { + if (CData_Check(obj) && argtype->ct_flags & CT_POINTER && + argtype->ct_itemdescr == ((CDataObject *)obj)->c_type) { + /* special case to make the life of verifier.py easier: + if the formal argument type is 'struct foo *' but + we pass a 'struct foo', then get a pointer to it */ + PyErr_Clear(); + ((char **)data)[0] = ((CDataObject *)obj)->c_data; + continue; + } goto error; + } } resultdata = buffer + cif_descr->exchange_offset_arg[0]; diff --git a/cffi/verifier.py b/cffi/verifier.py index 301c30b..e409541 100644 --- a/cffi/verifier.py +++ b/cffi/verifier.py @@ -199,8 +199,14 @@ class Verifier(object): return prnt = self._prnt numargs = len(tp.args) - arglist = [type.get_c_name(' x%d' % i) - for i, type in enumerate(tp.args)] + argnames = [] + for i, type in enumerate(tp.args): + indirection = '' + if isinstance(type, model.StructOrUnion): + indirection = '*' + argnames.append('%sx%d' % (indirection, i)) + arglist = [type.get_c_name(' %s' % arg) + for type, arg in zip(tp.args, argnames)] arglist = ', '.join(arglist) or 'void' funcdecl = ' _cffi_f_%s(%s)' % (name, arglist) prnt(tp.result.get_c_name(funcdecl)) @@ -210,18 +216,25 @@ class Verifier(object): result_code = 'return ' else: result_code = '' - prnt(' %s%s(%s);' % ( - result_code, name, - ', '.join(['x%d' % i for i in range(len(tp.args))]))) + prnt(' %s%s(%s);' % (result_code, name, ', '.join(argnames))) prnt('}') prnt() _loading_cpy_function = _loaded_noop def _loaded_cpy_function(self, tp, name, module, library): + assert isinstance(tp, model.FunctionPtrType) if tp.ellipsis: newfunction = self._load_constant(False, tp, name, module) else: + if any(isinstance(type, model.StructOrUnion) for type in tp.args): + indirect_args = [] + for i, type in enumerate(tp.args): + if isinstance(type, model.StructOrUnion): + type = model.PointerType(type) + indirect_args.append(type) + tp = model.FunctionPtrType(tuple(indirect_args), + tp.result, tp.ellipsis) BFunc = self.ffi._get_cached_btype(tp) wrappername = '_cffi_f_%s' % name newfunction = module.load_function(BFunc, wrappername) -- cgit v1.2.1 From 840821dad5f23e5e675692909643cdad878d4b63 Mon Sep 17 00:00:00 2001 From: Armin Rigo Date: Fri, 27 Jul 2012 18:47:21 +0200 Subject: Test and fix --- c/_cffi_backend.c | 8 +++++++- c/test_c.py | 16 ++++++++++++++++ cffi/verifier.py | 12 ++++++++++++ testing/test_verify.py | 1 + 4 files changed, 36 insertions(+), 1 deletion(-) diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c index 77a967f..083d11b 100644 --- a/c/_cffi_backend.c +++ b/c/_cffi_backend.c @@ -1730,7 +1730,7 @@ cdata_call(CDataObject *cd, PyObject *args, PyObject *kwds) #endif } if (convert_from_object(data, argtype, obj) < 0) { - if (CData_Check(obj) && argtype->ct_flags & CT_POINTER && + if (CData_Check(obj) && (argtype->ct_flags & CT_POINTER) && argtype->ct_itemdescr == ((CDataObject *)obj)->c_type) { /* special case to make the life of verifier.py easier: if the formal argument type is 'struct foo *' but @@ -3908,6 +3908,11 @@ static struct _testfunc17_s _testfunc17(int n) return result; } +static short _testfunc18(struct _testfunc7_s *ptr) +{ + return ptr->a1 + ptr->a2; +} + static PyObject *b__testfunc(PyObject *self, PyObject *args) { /* for testing only */ @@ -3934,6 +3939,7 @@ static PyObject *b__testfunc(PyObject *self, PyObject *args) case 15: f = &_testfunc15; break; case 16: f = &_testfunc16; break; case 17: f = &_testfunc17; break; + case 18: f = &_testfunc18; break; default: PyErr_SetNone(PyExc_ValueError); return NULL; diff --git a/c/test_c.py b/c/test_c.py index a5e9ad7..5bda64d 100644 --- a/c/test_c.py +++ b/c/test_c.py @@ -786,6 +786,22 @@ def test_call_function_7(): res = f(x[0]) assert res == -4042 + ord('A') +def test_call_function_18(): + BChar = new_primitive_type("char") + BShort = new_primitive_type("short") + BStruct = new_struct_type("foo") + BStructPtr = new_pointer_type(BStruct) + complete_struct_or_union(BStruct, [('a1', BChar, -1), + ('a2', BShort, -1)]) + BFunc18 = new_function_type((BStructPtr,), BShort, False) + f = cast(BFunc18, _testfunc(18)) + x = newp(BStructPtr, {'a1': 'A', 'a2': -4042}) + # test the exception that allows us to pass a 'struct foo' where the + # function really expects a 'struct foo *'. + res = f(x[0]) + assert res == -4042 + ord('A') + assert res == f(x) + def test_call_function_9(): BInt = new_primitive_type("int") BFunc9 = new_function_type((BInt,), BInt, True) # vararg diff --git a/cffi/verifier.py b/cffi/verifier.py index e409541..19e039f 100644 --- a/cffi/verifier.py +++ b/cffi/verifier.py @@ -227,19 +227,31 @@ class Verifier(object): if tp.ellipsis: newfunction = self._load_constant(False, tp, name, module) else: + indirections = [] if any(isinstance(type, model.StructOrUnion) for type in tp.args): indirect_args = [] for i, type in enumerate(tp.args): if isinstance(type, model.StructOrUnion): type = model.PointerType(type) + indirections.append((i, type)) indirect_args.append(type) tp = model.FunctionPtrType(tuple(indirect_args), tp.result, tp.ellipsis) BFunc = self.ffi._get_cached_btype(tp) wrappername = '_cffi_f_%s' % name newfunction = module.load_function(BFunc, wrappername) + for i, type in indirections: + newfunction = self._make_struct_wrapper(newfunction, i, type) setattr(library, name, newfunction) + def _make_struct_wrapper(self, oldfunc, i, tp): + backend = self.ffi._backend + BType = self.ffi._get_cached_btype(tp) + def newfunc(*args): + args = args[:i] + (backend.newp(BType, args[i]),) + args[i+1:] + return oldfunc(*args) + return newfunc + # ---------- # named structs diff --git a/testing/test_verify.py b/testing/test_verify.py index 3da1aea..93cbd89 100644 --- a/testing/test_verify.py +++ b/testing/test_verify.py @@ -583,6 +583,7 @@ def test_autofilled_struct_as_argument(): """) s = ffi.new("struct foo_s *", [100, 1]) assert lib.foo(s[0]) == 99 + assert lib.foo([100, 1]) == 99 def test_autofilled_struct_as_argument_dynamic(): ffi = FFI() -- cgit v1.2.1