Author: Armin Rigo <[email protected]>
Branch:
Changeset: r883:948d8808c081
Date: 2012-08-23 17:02 +0200
http://bitbucket.org/cffi/cffi/changeset/948d8808c081/
Log: Anonymous nested structures in the _cffi_backend
diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -41,7 +41,7 @@
# define PyText_FromFormat PyString_FromFormat
# define PyText_AsUTF8 PyString_AsString
# define PyText_AS_UTF8 PyString_AS_STRING
-# define PyText_GetSize PyString_GetSize
+# define PyText_GetSize PyString_Size
# define PyText_FromString PyString_FromString
# define PyText_FromStringAndSize PyString_FromStringAndSize
# define PyText_InternInPlace PyString_InternInPlace
@@ -314,15 +314,16 @@
/************************************************************/
-static char *
+static PyObject *
get_field_name(CTypeDescrObject *ct, CFieldObject *cf)
{
Py_ssize_t i = 0;
PyObject *d_key, *d_value;
while (PyDict_Next(ct->ct_stuff, &i, &d_key, &d_value)) {
if (d_value == (PyObject *)cf)
- return PyText_AsUTF8(d_key);
+ return d_key;
}
+ Py_FatalError("_cffi_backend: get_field_name()");
return NULL;
}
@@ -2919,6 +2920,39 @@
return _b_struct_or_union_type("union", name, CT_UNION);
}
+static CFieldObject *
+_add_field(PyObject *interned_fields, PyObject *fname, CTypeDescrObject *ftype,
+ Py_ssize_t offset, int bitshift, int fbitsize)
+{
+ int err;
+ Py_ssize_t prev_size;
+ CFieldObject *cf = PyObject_New(CFieldObject, &CField_Type);
+ if (cf == NULL)
+ return NULL;
+
+ Py_INCREF(ftype);
+ cf->cf_type = ftype;
+ cf->cf_offset = offset;
+ cf->cf_bitshift = bitshift;
+ cf->cf_bitsize = fbitsize;
+
+ Py_INCREF(fname);
+ PyText_InternInPlace(&fname);
+ prev_size = PyDict_Size(interned_fields);
+ err = PyDict_SetItem(interned_fields, fname, (PyObject *)cf);
+ Py_DECREF(fname);
+ Py_DECREF(cf);
+ if (err < 0)
+ return NULL;
+
+ if (PyDict_Size(interned_fields) != prev_size + 1) {
+ PyErr_Format(PyExc_KeyError, "duplicate field name '%s'",
+ PyText_AS_UTF8(fname));
+ return NULL;
+ }
+ return cf; /* borrowed reference */
+}
+
static PyObject *b_complete_struct_or_union(PyObject *self, PyObject *args)
{
CTypeDescrObject *ct;
@@ -2964,8 +2998,7 @@
for (i=0; i<nb_fields; i++) {
PyObject *fname;
CTypeDescrObject *ftype;
- int fbitsize = -1, falign, err, bitshift, foffset = -1;
- CFieldObject *cf;
+ int fbitsize = -1, falign, bitshift, foffset = -1;
if (!PyArg_ParseTuple(PyList_GET_ITEM(fields, i), "O!O!|ii:list item",
&PyText_Type, &fname,
@@ -3042,32 +3075,36 @@
prev_bit_position += fbitsize;
}
- cf = PyObject_New(CFieldObject, &CField_Type);
- if (cf == NULL)
- goto error;
- Py_INCREF(ftype);
- cf->cf_type = ftype;
- cf->cf_offset = offset;
- cf->cf_bitshift = bitshift;
- cf->cf_bitsize = fbitsize;
-
- Py_INCREF(fname);
- PyText_InternInPlace(&fname);
- err = PyDict_SetItem(interned_fields, fname, (PyObject *)cf);
- Py_DECREF(fname);
- Py_DECREF(cf);
- if (err < 0)
- goto error;
-
- if (PyDict_Size(interned_fields) != i + 1) {
- PyErr_Format(PyExc_KeyError, "duplicate field name '%s'",
- PyText_AS_UTF8(fname));
- goto error;
+ if (PyText_GetSize(fname) == 0 &&
+ ftype->ct_flags & (CT_STRUCT|CT_UNION)) {
+ /* a nested anonymous struct or union */
+ CFieldObject *cfsrc = (CFieldObject *)ftype->ct_extra;
+ for (; cfsrc != NULL; cfsrc = cfsrc->cf_next) {
+ /* broken complexity in the call to get_field_name(),
+ but we'll assume you never do that with nested
+ anonymous structures with thousand of fields */
+ *previous = _add_field(interned_fields,
+ get_field_name(ftype, cfsrc),
+ cfsrc->cf_type,
+ offset + cfsrc->cf_offset,
+ cfsrc->cf_bitshift,
+ cfsrc->cf_bitsize);
+ if (*previous == NULL)
+ goto error;
+ previous = &(*previous)->cf_next;
+ }
+ /* always forbid such structures from being passed by value */
+ ct->ct_flags |= CT_CUSTOM_FIELD_POS;
+ prev_field = NULL;
}
-
- *previous = cf;
- previous = &cf->cf_next;
- prev_field = cf;
+ else {
+ prev_field = _add_field(interned_fields, fname, ftype,
+ offset, bitshift, fbitsize);
+ if (prev_field == NULL)
+ goto error;
+ *previous = prev_field;
+ previous = &prev_field->cf_next;
+ }
if (maxsize < ftype->ct_size)
maxsize = ftype->ct_size;
@@ -3129,8 +3166,8 @@
return NULL;
for (cf = (CFieldObject *)ct->ct_extra; cf != NULL; cf = cf->cf_next) {
int err;
- PyObject *o = Py_BuildValue("sO", get_field_name(ct, cf),
- (PyObject *)cf);
+ PyObject *o = PyTuple_Pack(2, get_field_name(ct, cf),
+ (PyObject *)cf);
err = (o != NULL) ? PyList_Append(res, o) : -1;
Py_XDECREF(o);
if (err < 0) {
@@ -3208,6 +3245,11 @@
But on 64-bit UNIX, these two structs are passed by value
differently: e.g. on x86-64, "b" ends up in register "rsi" in
the first case and "rdi" in the second case.
+
+ Another reason for CT_CUSTOM_FIELD_POS would be anonymous
+ nested structures: we lost the information about having it
+ here, so better safe (and forbid it) than sorry (and maybe
+ crash).
*/
if (ct->ct_flags & CT_CUSTOM_FIELD_POS) {
PyErr_SetString(PyExc_TypeError,
diff --git a/c/test_c.py b/c/test_c.py
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -2010,3 +2010,32 @@
assert repr(p.a1).startswith("<cdata 'long *' 0x")
else:
assert repr(p.a1).startswith("<cdata 'long[%d]' 0x" % length)
+
+def test_nested_anonymous_struct():
+ BInt = new_primitive_type("int")
+ BChar = new_primitive_type("char")
+ BStruct = new_struct_type("foo")
+ BInnerStruct = new_struct_type("foo")
+ complete_struct_or_union(BInnerStruct, [('a1', BInt, -1),
+ ('a2', BChar, -1)])
+ complete_struct_or_union(BStruct, [('', BInnerStruct, -1),
+ ('a3', BChar, -1)])
+ assert sizeof(BInnerStruct) == sizeof(BInt) * 2 # with alignment
+ assert sizeof(BStruct) == sizeof(BInt) * 3 # 'a3' is placed after
+ d = _getfields(BStruct)
+ assert len(d) == 3
+ assert d[0][0] == 'a1'
+ assert d[0][1].type is BInt
+ assert d[0][1].offset == 0
+ assert d[0][1].bitshift == -1
+ assert d[0][1].bitsize == -1
+ assert d[1][0] == 'a2'
+ assert d[1][1].type is BChar
+ assert d[1][1].offset == sizeof(BInt)
+ assert d[1][1].bitshift == -1
+ assert d[1][1].bitsize == -1
+ assert d[2][0] == 'a3'
+ assert d[2][1].type is BChar
+ assert d[2][1].offset == sizeof(BInt) * 2
+ assert d[2][1].bitshift == -1
+ assert d[2][1].bitsize == -1
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit