Author: Armin Rigo <ar...@tunes.org> Branch: cffi-1.0 Changeset: r1856:7d84833187ae Date: 2015-04-27 17:26 +0200 http://bitbucket.org/cffi/cffi/changeset/7d84833187ae/
Log: Check sizeof(global variables) when possible diff --git a/_cffi1/lib_obj.c b/_cffi1/lib_obj.c --- a/_cffi1/lib_obj.c +++ b/_cffi1/lib_obj.c @@ -141,8 +141,7 @@ PyErr_Format(PyExc_AttributeError, "lib '%.200s' has no function," " global variable or constant named '%.200s'", - PyText_AS_UTF8(lib->l_libname), - PyText_Check(name) ? PyText_AS_UTF8(name) : "?"); + PyText_AS_UTF8(lib->l_libname), s); return NULL; } @@ -198,12 +197,23 @@ _CFFI_GETARG(g->type_op)); if (ct == NULL) return NULL; - x = make_global_var(ct, g->address); + if (g->size != ct->ct_size && + g->size != (size_t)-1 && ct->ct_size != -1) { + PyErr_Format(FFIError, + "global variable '%.200s' should be %zd bytes " + "according to the cdef, but is actually %zd", + s, ct->ct_size, g->size); + x = NULL; + } + else { + x = make_global_var(ct, g->address); + } Py_DECREF(ct); break; default: - PyErr_SetString(PyExc_NotImplementedError, "in lib_build_attr"); + PyErr_Format(PyExc_NotImplementedError, "in lib_build_attr: op=%d", + (int)_CFFI_GETOP(g->type_op)); return NULL; } diff --git a/_cffi1/parse_c_type.h b/_cffi1/parse_c_type.h --- a/_cffi1/parse_c_type.h +++ b/_cffi1/parse_c_type.h @@ -63,6 +63,7 @@ struct _cffi_global_s { const char *name; void *address; + size_t size; // -1 if unknown _cffi_opcode_t type_op; }; diff --git a/_cffi1/recompiler.py b/_cffi1/recompiler.py --- a/_cffi1/recompiler.py +++ b/_cffi1/recompiler.py @@ -418,7 +418,8 @@ else: meth_kind = 'V' # 'METH_VARARGS' self._lsts["global"].append( - ' { "%s", _cffi_f_%s, _CFFI_OP(_CFFI_OP_CPYTHON_BLTN_%s, %d) },' + ' { "%s", _cffi_f_%s, (size_t)-1, ' + '_CFFI_OP(_CFFI_OP_CPYTHON_BLTN_%s, %d) },' % (name, name, meth_kind, type_index)) # ---------- @@ -631,7 +632,8 @@ type_index = self._typesdict[tp] type_op = '_CFFI_OP(_CFFI_OP_CONSTANT, %d)' % type_index self._lsts["global"].append( - ' { "%s", _cffi_const_%s, %s },' % (name, name, type_op)) + ' { "%s", _cffi_const_%s, (size_t)-1, %s },' % + (name, name, type_op)) # ---------- # enums @@ -648,8 +650,8 @@ type_op = '_CFFI_OP(_CFFI_OP_ENUM, -1)' for enumerator in tp.enumerators: self._lsts["global"].append( - ' { "%s", _cffi_const_%s, %s },' % (enumerator, enumerator, - type_op)) + ' { "%s", _cffi_const_%s, (size_t)-1, %s },' % + (enumerator, enumerator, type_op)) # if cname is not None and '$' not in cname: size = "sizeof(%s)" % cname @@ -679,7 +681,8 @@ def _generate_cpy_macro_ctx(self, tp, name): self._lsts["global"].append( - ' { "%s", _cffi_const_%s, _CFFI_OP(_CFFI_OP_CONSTANT_INT, 0) },' % + ' { "%s", _cffi_const_%s, (size_t)-1,' + ' _CFFI_OP(_CFFI_OP_CONSTANT_INT, 0) },' % (name, name)) # ---------- @@ -700,9 +703,13 @@ def _generate_cpy_variable_ctx(self, tp, name): tp = self._global_type(tp, name) type_index = self._typesdict[tp] + if tp.sizeof_enabled(): + size = "sizeof(%s)" % (name,) + else: + size = "(size_t)-1" self._lsts["global"].append( - ' { "%s", &%s, _CFFI_OP(_CFFI_OP_GLOBAL_VAR, %d)},' - % (name, name, type_index)) + ' { "%s", &%s, %s, _CFFI_OP(_CFFI_OP_GLOBAL_VAR, %d)},' + % (name, name, size, type_index)) # ---------- # emitting the opcodes for individual types diff --git a/_cffi1/test_recompiler.py b/_cffi1/test_recompiler.py --- a/_cffi1/test_recompiler.py +++ b/_cffi1/test_recompiler.py @@ -420,3 +420,23 @@ assert test_module_name_in_package.mymod.lib.foo(10) == 42 finally: sys.path[:] = old_sys_path + +def test_bad_size_of_global_1(): + ffi = FFI() + ffi.cdef("short glob;") + lib = verify(ffi, "test_bad_size_of_global_1", "long glob;") + py.test.raises(ffi.error, "lib.glob") + +def test_bad_size_of_global_2(): + ffi = FFI() + ffi.cdef("int glob[10];") + lib = verify(ffi, "test_bad_size_of_global_2", "int glob[9];") + e = py.test.raises(ffi.error, "lib.glob") + assert str(e.value) == ("global variable 'glob' should be 40 bytes " + "according to the cdef, but is actually 36") + +def test_unspecified_size_of_global(): + ffi = FFI() + ffi.cdef("int glob[];") + lib = verify(ffi, "test_unspecified_size_of_global", "int glob[10];") + lib.glob # does not crash diff --git a/cffi/model.py b/cffi/model.py --- a/cffi/model.py +++ b/cffi/model.py @@ -31,6 +31,9 @@ def has_c_name(self): return '$' not in self._get_c_name() + + def sizeof_enabled(self): + return False def get_cached_btype(self, ffi, finishlist, can_delay=False): try: @@ -121,6 +124,9 @@ def is_float_type(self): return self.ALL_PRIMITIVE_TYPES[self.name] == 'f' + def sizeof_enabled(self): + return True + def build_backend_type(self, ffi, finishlist): return global_cache(self, ffi, 'new_primitive_type', self.name) @@ -161,6 +167,9 @@ class FunctionPtrType(BaseFunctionType): _base_pattern = '(*&)(%s)' + def sizeof_enabled(self): + return True + def build_backend_type(self, ffi, finishlist): result = self.result.get_cached_btype(ffi, finishlist) args = [] @@ -186,6 +195,9 @@ extra = self._base_pattern self.c_name_with_marker = totype.c_name_with_marker.replace('&', extra) + def sizeof_enabled(self): + return True + def build_backend_type(self, ffi, finishlist): BItem = self.totype.get_cached_btype(ffi, finishlist, can_delay=True) return global_cache(self, ffi, 'new_pointer_type', BItem) @@ -226,6 +238,9 @@ self.c_name_with_marker = ( self.item.c_name_with_marker.replace('&', brackets)) + def sizeof_enabled(self): + return self.item.sizeof_enabled() and self.length is not None + def resolve_length(self, newlength): return ArrayType(self.item, newlength) @@ -379,6 +394,9 @@ from . import ffiplatform raise ffiplatform.VerificationMissing(self._get_c_name()) + def sizeof_enabled(self): + return self.fldtypes is not None + def build_backend_type(self, ffi, finishlist): self.check_not_partial() finishlist.append(self) @@ -407,6 +425,9 @@ self.baseinttype = baseinttype self.build_c_name_with_marker() + def sizeof_enabled(self): + return True # not strictly true, but external enums are obscure + def force_the_name(self, forcename): StructOrUnionOrEnum.force_the_name(self, forcename) if self.forcename is None: _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit