[pypy-commit] cffi default: Explicitly protect against variables that end up resolving at address NULL,
arigo
noreply at buildbot.pypy.org
Mon Jul 6 19:12:40 CEST 2015
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r2214:57afc244cbc2
Date: 2015-07-06 19:09 +0200
http://bitbucket.org/cffi/cffi/changeset/57afc244cbc2/
Log: Explicitly protect against variables that end up resolving at
address NULL, which can occur in random cases like
test_macro_var_callback
diff --git a/c/cglob.c b/c/cglob.c
--- a/c/cglob.c
+++ b/c/cglob.c
@@ -4,6 +4,7 @@
typedef struct {
PyObject_HEAD
+ PyObject *gs_name;
CTypeDescrObject *gs_type;
char *gs_data;
gs_fetch_addr_fn gs_fetch_addr;
@@ -12,6 +13,7 @@
static void glob_support_dealloc(GlobSupportObject *gs)
{
+ Py_DECREF(gs->gs_name);
Py_DECREF(gs->gs_type);
PyObject_Del(gs);
}
@@ -41,14 +43,16 @@
#define GlobSupport_Check(ob) (Py_TYPE(ob) == &GlobSupport_Type)
-static PyObject *make_global_var(CTypeDescrObject *type, char *addr,
- gs_fetch_addr_fn fetch_addr)
+static PyObject *make_global_var(PyObject *name, CTypeDescrObject *type,
+ char *addr, gs_fetch_addr_fn fetch_addr)
{
GlobSupportObject *gs = PyObject_New(GlobSupportObject, &GlobSupport_Type);
if (gs == NULL)
return NULL;
+ Py_INCREF(name);
Py_INCREF(type);
+ gs->gs_name = name;
gs->gs_type = type;
gs->gs_data = addr;
gs->gs_fetch_addr = fetch_addr;
@@ -68,18 +72,27 @@
save_errno();
Py_END_ALLOW_THREADS
}
+ if (data == NULL) {
+ PyErr_Format(FFIError, "global variable '%s' is at address NULL",
+ PyText_AS_UTF8(gs->gs_name));
+ return NULL;
+ }
return data;
}
static PyObject *read_global_var(GlobSupportObject *gs)
{
void *data = fetch_global_var_addr(gs);
+ if (data == NULL)
+ return NULL;
return convert_to_object(data, gs->gs_type);
}
static int write_global_var(GlobSupportObject *gs, PyObject *obj)
{
void *data = fetch_global_var_addr(gs);
+ if (data == NULL)
+ return -1;
return convert_from_object(data, gs->gs_type, obj);
}
@@ -91,7 +104,10 @@
return NULL;
data = fetch_global_var_addr(gs);
- x = new_simple_cdata(data, (CTypeDescrObject *)ptrtype);
+ if (data != NULL)
+ x = new_simple_cdata(data, (CTypeDescrObject *)ptrtype);
+ else
+ x = NULL;
Py_DECREF(ptrtype);
return x;
}
diff --git a/c/lib_obj.c b/c/lib_obj.c
--- a/c/lib_obj.c
+++ b/c/lib_obj.c
@@ -324,7 +324,7 @@
if (address == NULL)
return NULL;
}
- x = make_global_var(ct, address, NULL);
+ x = make_global_var(name, ct, address, NULL);
}
Py_DECREF(ct);
break;
@@ -335,7 +335,7 @@
_CFFI_GETARG(g->type_op));
if (ct == NULL)
return NULL;
- x = make_global_var(ct, NULL, (gs_fetch_addr_fn)g->address);
+ x = make_global_var(name, ct, NULL, (gs_fetch_addr_fn)g->address);
Py_DECREF(ct);
break;
diff --git a/testing/cffi1/test_recompiler.py b/testing/cffi1/test_recompiler.py
--- a/testing/cffi1/test_recompiler.py
+++ b/testing/cffi1/test_recompiler.py
@@ -1128,3 +1128,22 @@
assert values[2] == 42
assert p[-1] == 41
assert p[+1] == 42
+ #
+ # if get_my_value raises or returns nonsense, the exception is printed
+ # to stderr like with any callback, but then the C expression 'my_value'
+ # expand to '*NULL'. We assume here that '&my_value' will return NULL
+ # without segfaulting, and check for NULL when accessing the variable.
+ @ffi.callback("int *(*)(void)")
+ def get_my_value():
+ raise LookupError
+ lib.get_my_value = get_my_value
+ py.test.raises(ffi.error, getattr, lib, 'my_value')
+ py.test.raises(ffi.error, setattr, lib, 'my_value', 50)
+ py.test.raises(ffi.error, ffi.addressof, lib, 'my_value')
+ @ffi.callback("int *(*)(void)")
+ def get_my_value():
+ return "hello"
+ lib.get_my_value = get_my_value
+ py.test.raises(ffi.error, getattr, lib, 'my_value')
+ e = py.test.raises(ffi.error, setattr, lib, 'my_value', 50)
+ assert str(e.value) == "global variable 'my_value' is at address NULL"
More information about the pypy-commit
mailing list