[pypy-commit] cffi cffi-1.0: Check sizeof(global variables) when possible
arigo
noreply at buildbot.pypy.org
Mon Apr 27 18:27:40 CEST 2015
Author: Armin Rigo <arigo at 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:
More information about the pypy-commit
mailing list