diff options
author | Armin Rigo <arigo@tunes.org> | 2015-01-11 15:04:41 +0100 |
---|---|---|
committer | Armin Rigo <arigo@tunes.org> | 2015-01-11 15:04:41 +0100 |
commit | 9215b25edf36171343d4acac02f2237e38e188ed (patch) | |
tree | d5dbbd4096f845530b344bdc5fe13d5234f5ec96 /cffi/vengine_gen.py | |
parent | 5328afc70e4e27f10865d4e596aca6d875284d90 (diff) | |
download | cffi-9215b25edf36171343d4acac02f2237e38e188ed.tar.gz |
Fix (thanks gkcn on irc): in cdef() we can say "#define FOO 42", but
this declaration is completely ignored in verify(). Instead, we
need to check that the real value is 42, and store the name FOO on
the returned library object.
Diffstat (limited to 'cffi/vengine_gen.py')
-rw-r--r-- | cffi/vengine_gen.py | 96 |
1 files changed, 62 insertions, 34 deletions
diff --git a/cffi/vengine_gen.py b/cffi/vengine_gen.py index 1271d4f..8e1412c 100644 --- a/cffi/vengine_gen.py +++ b/cffi/vengine_gen.py @@ -355,11 +355,20 @@ class VGenericEngine(object): # ---------- # constants, likely declared with '#define' - def _generate_gen_const(self, is_int, name, tp=None, category='const'): + def _generate_gen_const(self, is_int, name, tp=None, category='const', + check_value=None): prnt = self._prnt funcname = '_cffi_%s_%s' % (category, name) self.export_symbols.append(funcname) - if is_int: + if check_value is not None: + assert is_int + assert category == 'const' + prnt('int %s(char *out_error)' % funcname) + prnt('{') + self._check_int_constant_value(name, check_value) + prnt(' return 0;') + prnt('}') + elif is_int: assert category == 'const' prnt('int %s(long long *out_value)' % funcname) prnt('{') @@ -368,6 +377,7 @@ class VGenericEngine(object): prnt('}') else: assert tp is not None + assert check_value is None prnt(tp.get_c_name(' %s(void)' % funcname, name),) prnt('{') if category == 'var': @@ -384,9 +394,13 @@ class VGenericEngine(object): _loading_gen_constant = _loaded_noop - def _load_constant(self, is_int, tp, name, module): + def _load_constant(self, is_int, tp, name, module, check_value=None): funcname = '_cffi_const_%s' % name - if is_int: + if check_value is not None: + assert is_int + self._load_known_int_constant(module, funcname) + value = check_value + elif is_int: BType = self.ffi._typeof_locked("long long*")[0] BFunc = self.ffi._typeof_locked("int(*)(long long*)")[0] function = module.load_function(BFunc, funcname) @@ -397,6 +411,7 @@ class VGenericEngine(object): BLongLong = self.ffi._typeof_locked("long long")[0] value += (1 << (8*self.ffi.sizeof(BLongLong))) else: + assert check_value is None BFunc = self.ffi._typeof_locked(tp.get_c_name('(*)(void)', name))[0] function = module.load_function(BFunc, funcname) value = function() @@ -411,6 +426,36 @@ class VGenericEngine(object): # ---------- # enums + def _check_int_constant_value(self, name, value): + prnt = self._prnt + if value <= 0: + prnt(' if ((%s) > 0 || (long)(%s) != %dL) {' % ( + name, name, value)) + else: + prnt(' if ((%s) <= 0 || (unsigned long)(%s) != %dUL) {' % ( + name, name, value)) + prnt(' char buf[64];') + prnt(' if ((%s) <= 0)' % name) + prnt(' sprintf(buf, "%%ld", (long)(%s));' % name) + prnt(' else') + prnt(' sprintf(buf, "%%lu", (unsigned long)(%s));' % + name) + prnt(' sprintf(out_error, "%s has the real value %s, not %s",') + prnt(' "%s", buf, "%d");' % (name[:100], value)) + prnt(' return -1;') + prnt(' }') + + def _load_known_int_constant(self, module, funcname): + BType = self.ffi._typeof_locked("char[]")[0] + BFunc = self.ffi._typeof_locked("int(*)(char*)")[0] + function = module.load_function(BFunc, funcname) + p = self.ffi.new(BType, 256) + if function(p) < 0: + error = self.ffi.string(p) + if sys.version_info >= (3,): + error = str(error, 'utf-8') + raise ffiplatform.VerificationError(error) + def _enum_funcname(self, prefix, name): # "$enum_$1" => "___D_enum____D_1" name = name.replace('$', '___D_') @@ -428,24 +473,7 @@ class VGenericEngine(object): prnt('int %s(char *out_error)' % funcname) prnt('{') for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): - if enumvalue <= 0: - prnt(' if ((%s) > 0 || (long)(%s) != %dL) {' % ( - enumerator, enumerator, enumvalue)) - else: - prnt(' if ((%s) <= 0 || (unsigned long)(%s) != %dUL) {' % ( - enumerator, enumerator, enumvalue)) - prnt(' char buf[64];') - prnt(' if ((%s) <= 0)' % enumerator) - prnt(' sprintf(buf, "%%ld", (long)(%s));' % enumerator) - prnt(' else') - prnt(' sprintf(buf, "%%lu", (unsigned long)(%s));' % - enumerator) - prnt(' sprintf(out_error,' - ' "%s has the real value %s, not %s",') - prnt(' "%s", buf, "%d");' % ( - enumerator[:100], enumvalue)) - prnt(' return -1;') - prnt(' }') + self._check_int_constant_value(enumerator, enumvalue) prnt(' return 0;') prnt('}') prnt() @@ -457,16 +485,8 @@ class VGenericEngine(object): tp.enumvalues = tuple(enumvalues) tp.partial_resolved = True else: - BType = self.ffi._typeof_locked("char[]")[0] - BFunc = self.ffi._typeof_locked("int(*)(char*)")[0] funcname = self._enum_funcname(prefix, name) - function = module.load_function(BFunc, funcname) - p = self.ffi.new(BType, 256) - if function(p) < 0: - error = self.ffi.string(p) - if sys.version_info >= (3,): - error = str(error, 'utf-8') - raise ffiplatform.VerificationError(error) + self._load_known_int_constant(module, funcname) def _loaded_gen_enum(self, tp, name, module, library): for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): @@ -477,13 +497,21 @@ class VGenericEngine(object): # macros: for now only for integers def _generate_gen_macro_decl(self, tp, name): - assert tp == '...' - self._generate_gen_const(True, name) + if tp == '...': + check_value = None + else: + check_value = tp # an integer + self._generate_gen_const(True, name, check_value=check_value) _loading_gen_macro = _loaded_noop def _loaded_gen_macro(self, tp, name, module, library): - value = self._load_constant(True, tp, name, module) + if tp == '...': + check_value = None + else: + check_value = tp # an integer + value = self._load_constant(True, tp, name, module, + check_value=check_value) setattr(library, name, value) type(library)._cffi_dir.append(name) |