Commits

Armin Rigo committed a1ca6e1 Merge

hg merge default

Comments (0)

Files changed (29)

+3691a2e644c98fc8753ffb96c4ff2d5d3e57bd17 release-0.4.2
+0000000000000000000000000000000000000000 release-0.4.2
+037096d1bdaa213c2adebf3a4124ad56dba8ba82 release-0.4.1
+0000000000000000000000000000000000000000 release-0.4.1
+bd4b6090aea035a6093e684858aa7bd54a6270ec release-0.4
+0000000000000000000000000000000000000000 release-0.4
+5f31908df6c97a1f70f3fcd4d489d98dc2b30f04 release-0.3
+0000000000000000000000000000000000000000 release-0.3
+6a0f0a476101210a76f4bc4d33c5bbb0f8f979fd release-0.2.1
+0000000000000000000000000000000000000000 release-0.2.1
+a8636625e33b0f84c3744f80d49e84b175a0a215 release-0.2
+0000000000000000000000000000000000000000 release-0.2
 ca6e81df7f1ea58d891129ad016a8888c08f238b release-0.1
-a8636625e33b0f84c3744f80d49e84b175a0a215 release-0.2
-6a0f0a476101210a76f4bc4d33c5bbb0f8f979fd release-0.2.1
-5f31908df6c97a1f70f3fcd4d489d98dc2b30f04 release-0.3
-bd4b6090aea035a6093e684858aa7bd54a6270ec release-0.4
-037096d1bdaa213c2adebf3a4124ad56dba8ba82 release-0.4.1
-3691a2e644c98fc8753ffb96c4ff2d5d3e57bd17 release-0.4.2
+0000000000000000000000000000000000000000 release-0.1
 This package has been mostly done by Armin Rigo with help from
-Maciej Fijałkowski.
+Maciej Fijałkowski. The idea is heavily based (although not directly
+copied) from LuaJIT ffi by Mike Pall.
 -------
 
 [Mailing list](https://groups.google.com/forum/#!forum/python-cffi)
+
+To run tests under CPython, run:
+
+python setup.py build_ext -i

c/_cffi_backend.c

 #define CT_IS_LONGDOUBLE        65536
 #define CT_IS_BOOL             131072
 #define _CT_IS_FILE            262144
+#define CT_IS_VOID_PTR         524288
 #define CT_PRIMITIVE_ANY  (CT_PRIMITIVE_SIGNED |        \
                            CT_PRIMITIVE_UNSIGNED |      \
                            CT_PRIMITIVE_CHAR |          \
 static PyTypeObject CField_Type;
 static PyTypeObject CData_Type;
 static PyTypeObject CDataOwning_Type;
+static PyTypeObject CDataOwningGC_Type;
 
 #define CTypeDescr_Check(ob)  (Py_TYPE(ob) == &CTypeDescr_Type)
 #define CData_Check(ob)       (Py_TYPE(ob) == &CData_Type ||            \
-                               Py_TYPE(ob) == &CDataOwning_Type)
-#define CDataOwn_Check(ob)    (Py_TYPE(ob) == &CDataOwning_Type)
+                               Py_TYPE(ob) == &CDataOwning_Type ||      \
+                               Py_TYPE(ob) == &CDataOwningGC_Type)
+#define CDataOwn_Check(ob)    (Py_TYPE(ob) == &CDataOwning_Type ||      \
+                               Py_TYPE(ob) == &CDataOwningGC_Type)
 
 typedef union {
     unsigned char m_char;
     PyObject_Del(cf);
 }
 
-static int
-cfield_traverse(CFieldObject *cf, visitproc visit, void *arg)
-{
-    Py_VISIT(cf->cf_type);
-    return 0;
-}
-
 #undef OFF
 #define OFF(x) offsetof(CFieldObject, x)
 
     0,                                          /* tp_as_buffer */
     Py_TPFLAGS_DEFAULT,                         /* tp_flags */
     0,                                          /* tp_doc */
-    (traverseproc)cfield_traverse,              /* tp_traverse */
+    0,                                          /* tp_traverse */
     0,                                          /* tp_clear */
     0,                                          /* tp_richcompare */
     0,                                          /* tp_weaklistoffset */
         PyObject_ClearWeakRefs((PyObject *) cd);
 
     Py_DECREF(cd->c_type);
-    PyObject_Del(cd);
+#ifndef CFFI_MEM_LEAK     /* never release anything, tests only */
+    Py_TYPE(cd)->tp_free((PyObject *)cd);
+#endif
 }
 
 static void cdataowning_dealloc(CDataObject *cd)
 {
+    assert(!(cd->c_type->ct_flags & (CT_IS_VOID_PTR | CT_FUNCTIONPTR)));
+
     if (cd->c_type->ct_flags & CT_IS_PTR_TO_OWNED) {
         Py_DECREF(((CDataObject_own_structptr *)cd)->structobj);
     }
-    else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) {
-        /* a callback */
+#if defined(CFFI_MEM_DEBUG) || defined(CFFI_MEM_LEAK)
+    if (cd->c_type->ct_flags & (CT_PRIMITIVE_ANY | CT_STRUCT | CT_UNION)) {
+        assert(cd->c_type->ct_size >= 0);
+        memset(cd->c_data, 0xDD, cd->c_type->ct_size);
+    }
+    else if (cd->c_type->ct_flags & CT_ARRAY) {
+        Py_ssize_t x = get_array_length(cd);
+        assert(x >= 0);
+        x *= cd->c_type->ct_itemdescr->ct_size;
+        assert(x >= 0);
+        memset(cd->c_data, 0xDD, x);
+    }
+#endif
+    cdata_dealloc(cd);
+}
+
+static void cdataowninggc_dealloc(CDataObject *cd)
+{
+    assert(!(cd->c_type->ct_flags & (CT_IS_PTR_TO_OWNED |
+                                     CT_PRIMITIVE_ANY |
+                                     CT_STRUCT | CT_UNION)));
+    PyObject_GC_UnTrack(cd);
+
+    if (cd->c_type->ct_flags & CT_IS_VOID_PTR) {        /* a handle */
+        PyObject *x = (PyObject *)(cd->c_data + 42);
+        Py_DECREF(x);
+    }
+    else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) {   /* a callback */
         ffi_closure *closure = (ffi_closure *)cd->c_data;
         PyObject *args = (PyObject *)(closure->user_data);
         Py_XDECREF(args);
     cdata_dealloc(cd);
 }
 
-static int cdata_traverse(CDataObject *cd, visitproc visit, void *arg)
+static int cdataowninggc_traverse(CDataObject *cd, visitproc visit, void *arg)
 {
-    Py_VISIT(cd->c_type);
+    if (cd->c_type->ct_flags & CT_IS_VOID_PTR) {        /* a handle */
+        PyObject *x = (PyObject *)(cd->c_data + 42);
+        Py_VISIT(x);
+    }
+    else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) {   /* a callback */
+        ffi_closure *closure = (ffi_closure *)cd->c_data;
+        PyObject *args = (PyObject *)(closure->user_data);
+        Py_VISIT(args);
+    }
+    return 0;
+}
+
+static int cdataowninggc_clear(CDataObject *cd)
+{
+    if (cd->c_type->ct_flags & CT_IS_VOID_PTR) {        /* a handle */
+        PyObject *x = (PyObject *)(cd->c_data + 42);
+        Py_INCREF(Py_None);
+        cd->c_data = ((char *)Py_None) - 42;
+        Py_DECREF(x);
+    }
+    else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) {   /* a callback */
+        ffi_closure *closure = (ffi_closure *)cd->c_data;
+        PyObject *args = (PyObject *)(closure->user_data);
+        closure->user_data = NULL;
+        Py_XDECREF(args);
+    }
     return 0;
 }
 
     return result;
 }
 
+static PyObject *_cdata_repr2(CDataObject *cd, char *text, PyObject *x)
+{
+    PyObject *res, *s = PyObject_Repr(x);
+    if (s == NULL)
+        return NULL;
+    res = PyText_FromFormat("<cdata '%s' %s %s>",
+                            cd->c_type->ct_name, text, PyText_AsUTF8(s));
+    Py_DECREF(s);
+    return res;
+}
+
 static PyObject *cdataowning_repr(CDataObject *cd)
 {
     Py_ssize_t size;
-    if (cd->c_type->ct_flags & CT_POINTER)
+    if (cd->c_type->ct_flags & CT_POINTER) {
+        if (cd->c_type->ct_flags & CT_IS_VOID_PTR)
+            goto handle_repr;
         size = cd->c_type->ct_itemdescr->ct_size;
+    }
     else if (cd->c_type->ct_flags & CT_ARRAY)
         size = get_array_length(cd) * cd->c_type->ct_itemdescr->ct_size;
     else if (cd->c_type->ct_flags & CT_FUNCTIONPTR)
 
  callback_repr:
     {
-        PyObject *s, *res;
         PyObject *args = (PyObject *)((ffi_closure *)cd->c_data)->user_data;
         if (args == NULL)
             return cdata_repr(cd);
-
-        s = PyObject_Repr(PyTuple_GET_ITEM(args, 1));
-        if (s == NULL)
-            return NULL;
-        res = PyText_FromFormat("<cdata '%s' calling %s>",
-                                cd->c_type->ct_name, PyText_AsUTF8(s));
-        Py_DECREF(s);
-        return res;
+        else
+            return _cdata_repr2(cd, "calling", PyTuple_GET_ITEM(args, 1));
+    }
+
+ handle_repr:
+    {
+        PyObject *x = (PyObject *)(cd->c_data + 42);
+        return _cdata_repr2(cd, "handle to", x);
     }
 }
 
 
 static long cdata_hash(CDataObject *cd)
 {
-    long h = _Py_HashPointer(cd->c_type) ^ _Py_HashPointer(cd->c_data);
-    if (h == -1)
-        h = -2;
-    return h;
+    return _Py_HashPointer(cd->c_data);
 }
 
 static Py_ssize_t
         return 0;
     PyErr_SetString(PyExc_TypeError,
                     "bad argument type for 'FILE' type (note that you cannot "
-                    "pass Python files directly any more since CFFI 0.6; see "
+                    "pass Python files directly any more since CFFI 1.0; see "
                     "demo/file1.py)");
     return -1;
 }
         if ((ctptr->ct_flags & CT_CAST_ANYTHING) ||
             ((ctitem->ct_flags & (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_UNSIGNED))
              && (ctitem->ct_size == sizeof(char)))) {
+#if defined(CFFI_MEM_DEBUG) || defined(CFFI_MEM_LEAK)
+            length = PyBytes_GET_SIZE(init) + 1;
+#else
             *output_data = PyBytes_AS_STRING(init);
             return 0;
+#endif
         }
         else
             goto convert_default;
     0,                                          /* tp_as_buffer */
     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
     0,                                          /* tp_doc */
-    (traverseproc)cdata_traverse,               /* tp_traverse */
+    0,                                          /* tp_traverse */
     0,                                          /* tp_clear */
     cdata_richcompare,                          /* tp_richcompare */
     offsetof(CDataObject, c_weakreflist),       /* tp_weaklistoffset */
     &CData_Type,                                /* tp_base */
 };
 
+static PyTypeObject CDataOwningGC_Type = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "_cffi_backend.CDataOwnGC",
+    sizeof(CDataObject),
+    0,
+    (destructor)cdataowninggc_dealloc,          /* tp_dealloc */
+    0,                                          /* tp_print */
+    0,                                          /* tp_getattr */
+    0,                                          /* tp_setattr */
+    0,                                          /* tp_compare */
+    0,                                          /* tp_repr */
+    0,                                          /* tp_as_number */
+    0,                                          /* tp_as_sequence */
+    0,                                          /* tp_as_mapping */
+    0,                                          /* tp_hash */
+    0,                                          /* tp_call */
+    0,                                          /* tp_str */
+    0,                                          /* tp_getattro */
+    0,                                          /* tp_setattro */
+    0,                                          /* tp_as_buffer */
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES  /* tp_flags */
+                       | Py_TPFLAGS_HAVE_GC,
+    0,                                          /* tp_doc */
+    (traverseproc)cdataowninggc_traverse,       /* tp_traverse */
+    (inquiry)cdataowninggc_clear,               /* tp_clear */
+    0,                                          /* tp_richcompare */
+    0,                                          /* tp_weaklistoffset */
+    0,                                          /* tp_iter */
+    0,                                          /* tp_iternext */
+    0,                                          /* tp_methods */
+    0,                                          /* tp_members */
+    0,                                          /* tp_getset */
+    &CDataOwning_Type,                          /* tp_base */
+};
+
 /************************************************************/
 
 typedef struct {
     td->ct_flags = CT_POINTER;
     if (ctitem->ct_flags & (CT_STRUCT|CT_UNION))
         td->ct_flags |= CT_IS_PTR_TO_OWNED;
+    if (ctitem->ct_flags & CT_VOID)
+        td->ct_flags |= CT_IS_VOID_PTR;
     if ((ctitem->ct_flags & CT_VOID) ||
         ((ctitem->ct_flags & CT_PRIMITIVE_CHAR) &&
          ctitem->ct_size == sizeof(char)))
     return (PyObject *)td;
 }
 
-static PyObject *_b_struct_or_union_type(const char *kind, const char *name,
-                                         int flag)
+static PyObject *_b_struct_or_union_type(const char *name, int flag)
 {
-    int kindlen = strlen(kind);
     int namelen = strlen(name);
-    CTypeDescrObject *td = ctypedescr_new(kindlen + 1 + namelen + 1);
+    CTypeDescrObject *td = ctypedescr_new(namelen + 1);
     if (td == NULL)
         return NULL;
 
     td->ct_size = -1;
     td->ct_length = -1;
     td->ct_flags = flag | CT_IS_OPAQUE;
-    memcpy(td->ct_name, kind, kindlen);
-    td->ct_name[kindlen] = ' ';
-    memcpy(td->ct_name + kindlen + 1, name, namelen + 1);
-    td->ct_name_position = kindlen + 1 + namelen;
+    memcpy(td->ct_name, name, namelen + 1);
+    td->ct_name_position = namelen;
     return (PyObject *)td;
 }
 
         return NULL;
 
     flag = CT_STRUCT;
-    if (strcmp(name, "_IO_FILE") == 0 || strcmp(name, "$FILE") == 0)
+    if (strcmp(name, "struct _IO_FILE") == 0 || strcmp(name, "FILE") == 0)
         flag |= _CT_IS_FILE;
-    return _b_struct_or_union_type("struct", name, flag);
+    return _b_struct_or_union_type(name, flag);
 }
 
 static PyObject *b_new_union_type(PyObject *self, PyObject *args)
     char *name;
     if (!PyArg_ParseTuple(args, "s:new_union_type", &name))
         return NULL;
-    return _b_struct_or_union_type("union", name, CT_UNION);
+    return _b_struct_or_union_type(name, CT_UNION);
 }
 
 static CFieldObject *
     return cf;   /* borrowed reference */
 }
 
+#define SF_MSVC_BITFIELDS 1
+#define SF_GCC_ARM_BITFIELDS 2
+
 static PyObject *b_complete_struct_or_union(PyObject *self, PyObject *args)
 {
     CTypeDescrObject *ct;
     PyObject *fields, *interned_fields, *ignored;
     int is_union, alignment;
-    Py_ssize_t offset, i, nb_fields, maxsize, prev_bit_position;
+    Py_ssize_t boffset, i, nb_fields, boffsetmax;
     Py_ssize_t totalsize = -1;
     int totalalignment = -1;
-    CFieldObject **previous, *prev_field;
-
-    if (!PyArg_ParseTuple(args, "O!O!|Oni:complete_struct_or_union",
+    CFieldObject **previous;
+    int prev_bitfield_size, prev_bitfield_free;
+#ifdef MS_WIN32
+    int sflags = SF_MSVC_BITFIELDS;
+#else
+# ifdef __arm__
+    int sflags = SF_GCC_ARM_BITFIELDS;
+# else
+    int sflags = 0;
+# endif
+#endif
+
+    if (!PyArg_ParseTuple(args, "O!O!|Onii:complete_struct_or_union",
                           &CTypeDescr_Type, &ct,
                           &PyList_Type, &fields,
-                          &ignored, &totalsize, &totalalignment))
+                          &ignored, &totalsize, &totalalignment, &sflags))
         return NULL;
 
     if ((ct->ct_flags & (CT_STRUCT|CT_IS_OPAQUE)) ==
         return NULL;
     }
 
-    maxsize = 0;
     alignment = 1;
-    offset = 0;
+    boffset = 0;         /* this number is in *bits*, not bytes! */
+    boffsetmax = 0;      /* the maximum value of boffset, in bits too */
+    prev_bitfield_size = 0;
+    prev_bitfield_free = 0;
     nb_fields = PyList_GET_SIZE(fields);
     interned_fields = PyDict_New();
     if (interned_fields == NULL)
         return NULL;
 
     previous = (CFieldObject **)&ct->ct_extra;
-    prev_bit_position = 0;
-    prev_field = NULL;
 
     for (i=0; i<nb_fields; i++) {
         PyObject *fname;
         CTypeDescrObject *ftype;
-        int fbitsize = -1, falign, bitshift, foffset = -1;
+        int fbitsize = -1, falign, do_align, foffset = -1;
 
         if (!PyArg_ParseTuple(PyList_GET_ITEM(fields, i), "O!O!|ii:list item",
                               &PyText_Type, &fname,
             goto error;
         }
 
+        if (is_union)
+            boffset = 0;   /* reset each field at offset 0 */
+
+        /* update the total alignment requirement, but skip it if the
+           field is an anonymous bitfield */
         falign = get_alignment(ftype);
         if (falign < 0)
             goto error;
-        if (alignment < falign)
+
+        do_align = 1;
+        if (!(sflags & SF_GCC_ARM_BITFIELDS) && fbitsize >= 0) {
+            if (!(sflags & SF_MSVC_BITFIELDS)) {
+                /* GCC: anonymous bitfields (of any size) don't cause alignment */
+                do_align = PyText_GetSize(fname) > 0;
+            }
+            else {
+                /* MSVC: zero-sized bitfields don't cause alignment */
+                do_align = fbitsize > 0;
+            }
+        }
+        if (alignment < falign && do_align)
             alignment = falign;
 
-        /* align this field to its own 'falign' by inserting padding */
-        offset = (offset + falign - 1) & ~(falign-1);
-
-        if (foffset >= 0) {
-            /* a forced field position: ignore the offset just computed,
-               except to know if we must set CT_CUSTOM_FIELD_POS */
-            if (offset != foffset)
+        if (fbitsize < 0) {
+            /* not a bitfield: common case */
+            int bs_flag;
+
+            if (ftype->ct_flags & CT_ARRAY && ftype->ct_length == 0)
+                bs_flag = BS_EMPTY_ARRAY;
+            else
+                bs_flag = BS_REGULAR;
+
+            /* align this field to its own 'falign' by inserting padding */
+            boffset = (boffset + falign*8-1) & ~(falign*8-1); /* bits! */
+
+            if (foffset >= 0) {
+                /* a forced field position: ignore the offset just computed,
+                   except to know if we must set CT_CUSTOM_FIELD_POS */
+                if (boffset != foffset * 8)
+                    ct->ct_flags |= CT_CUSTOM_FIELD_POS;
+                boffset = foffset * 8;
+            }
+
+            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,
+                                           boffset / 8 + 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;
-            offset = foffset;
-        }
-
-        if (fbitsize < 0 || (fbitsize == 8 * ftype->ct_size &&
-                             !(ftype->ct_flags & CT_PRIMITIVE_CHAR))) {
-            fbitsize = -1;
-            if (ftype->ct_flags & CT_ARRAY && ftype->ct_length == 0)
-                bitshift = BS_EMPTY_ARRAY;
-            else
-                bitshift = BS_REGULAR;
-            prev_bit_position = 0;
-        }
-        else {
-            if (!(ftype->ct_flags & (CT_PRIMITIVE_SIGNED |
-                                     CT_PRIMITIVE_UNSIGNED |
-                                     CT_PRIMITIVE_CHAR)) ||
-#ifdef HAVE_WCHAR_H
-                    ((ftype->ct_flags & CT_PRIMITIVE_CHAR)
-                         && ftype->ct_size == sizeof(wchar_t)) ||
-#endif
-                    fbitsize == 0 ||
-                    fbitsize > 8 * ftype->ct_size) {
-                PyErr_Format(PyExc_TypeError, "invalid bit field '%s'",
-                             PyText_AS_UTF8(fname));
-                goto error;
             }
-            if (prev_bit_position > 0) {
-                assert(prev_field && prev_field->cf_bitshift >= 0);
-                if (prev_field->cf_type->ct_size != ftype->ct_size) {
-                    PyErr_SetString(PyExc_NotImplementedError,
-                                    "consecutive bit fields should be "
-                                    "declared with a same-sized type");
-                    goto error;
-                }
-                else if (prev_bit_position + fbitsize > 8 * ftype->ct_size) {
-                    prev_bit_position = 0;
-                }
-                else {
-                    /* we can share the same field as 'prev_field' */
-                    offset = prev_field->cf_offset;
-                }
-            }
-            bitshift = prev_bit_position;
-            if (!is_union)
-                prev_bit_position += fbitsize;
-        }
-
-        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);
+            else {
+                *previous = _add_field(interned_fields, fname, ftype,
+                                        boffset / 8, bs_flag, -1);
                 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;
+            boffset += ftype->ct_size * 8;
+            prev_bitfield_size = 0;
         }
         else {
-            prev_field = _add_field(interned_fields, fname, ftype,
-                                    offset, bitshift, fbitsize);
-            if (prev_field == NULL)
+            /* this is the case of a bitfield */
+            Py_ssize_t field_offset_bytes;
+            int bits_already_occupied, bitshift;
+
+            if (foffset >= 0) {
+                PyErr_Format(PyExc_TypeError,
+                             "field '%s.%s' is a bitfield, "
+                             "but a fixed offset is specified",
+                             ct->ct_name, PyText_AS_UTF8(fname));
                 goto error;
-            *previous = prev_field;
-            previous = &prev_field->cf_next;
+            }
+
+            if (!(ftype->ct_flags & (CT_PRIMITIVE_SIGNED |
+                                     CT_PRIMITIVE_UNSIGNED |
+                                     CT_PRIMITIVE_CHAR))) {
+                PyErr_Format(PyExc_TypeError,
+                        "field '%s.%s' declared as '%s' cannot be a bit field",
+                             ct->ct_name, PyText_AS_UTF8(fname),
+                             ftype->ct_name);
+                goto error;
+            }
+            if (fbitsize > 8 * ftype->ct_size) {
+                PyErr_Format(PyExc_TypeError,
+                             "bit field '%s.%s' is declared '%s:%d', which "
+                             "exceeds the width of the type",
+                             ct->ct_name, PyText_AS_UTF8(fname),
+                             ftype->ct_name, fbitsize);
+                goto error;
+            }
+
+            /* compute the starting position of the theoretical field
+               that covers a complete 'ftype', inside of which we will
+               locate the real bitfield */
+            field_offset_bytes = boffset / 8;
+            field_offset_bytes &= ~(falign - 1);
+
+            if (fbitsize == 0) {
+                if (PyText_GetSize(fname) > 0) {
+                    PyErr_Format(PyExc_TypeError,
+                                 "field '%s.%s' is declared with :0",
+                                 ct->ct_name, PyText_AS_UTF8(fname));
+                }
+                if (!(sflags & SF_MSVC_BITFIELDS)) {
+                    /* GCC's notion of "ftype :0;" */
+
+                    /* pad boffset to a value aligned for "ftype" */
+                    if (boffset > field_offset_bytes * 8) {
+                        field_offset_bytes += falign;
+                        assert(boffset < field_offset_bytes * 8);
+                    }
+                    boffset = field_offset_bytes * 8;
+                }
+                else {
+                    /* MSVC's notion of "ftype :0;" */
+
+                    /* Mostly ignored.  It seems they only serve as
+                       separator between other bitfields, to force them
+                       into separate words. */
+                }
+                prev_bitfield_size = 0;
+            }
+            else {
+                if (!(sflags & SF_MSVC_BITFIELDS)) {
+                    /* GCC's algorithm */
+
+                    /* Can the field start at the offset given by 'boffset'?  It
+                       can if it would entirely fit into an aligned ftype field. */
+                    bits_already_occupied = boffset - (field_offset_bytes * 8);
+
+                    if (bits_already_occupied + fbitsize > 8 * ftype->ct_size) {
+                        /* it would not fit, we need to start at the next
+                           allowed position */
+                        field_offset_bytes += falign;
+                        assert(boffset < field_offset_bytes * 8);
+                        boffset = field_offset_bytes * 8;
+                        bitshift = 0;
+                    }
+                    else {
+                        bitshift = bits_already_occupied;
+                        assert(bitshift >= 0);
+                    }
+                    boffset += fbitsize;
+                }
+                else {
+                    /* MSVC's algorithm */
+
+                    /* A bitfield is considered as taking the full width
+                       of their declared type.  It can share some bits
+                       with the previous field only if it was also a
+                       bitfield and used a type of the same size. */
+                    if (prev_bitfield_size == ftype->ct_size &&
+                        prev_bitfield_free >= fbitsize) {
+                        /* yes: reuse */
+                        bitshift = 8 * prev_bitfield_size - prev_bitfield_free;
+                    }
+                    else {
+                        /* no: start a new full field */
+                        boffset = (boffset + falign*8-1) & ~(falign*8-1); /*align*/
+                        boffset += ftype->ct_size * 8;
+                        bitshift = 0;
+                        prev_bitfield_size = ftype->ct_size;
+                        prev_bitfield_free = 8 * prev_bitfield_size;
+                    }
+                    prev_bitfield_free -= fbitsize;
+                    field_offset_bytes = boffset / 8 - ftype->ct_size;
+                }
+
+                *previous = _add_field(interned_fields, fname, ftype,
+                                       field_offset_bytes, bitshift, fbitsize);
+                if (*previous == NULL)
+                    goto error;
+                previous = &(*previous)->cf_next;
+            }
         }
 
-        if (maxsize < ftype->ct_size)
-            maxsize = ftype->ct_size;
-        if (!is_union)
-            offset += ftype->ct_size;
+        if (boffset > boffsetmax)
+            boffsetmax = boffset;
     }
     *previous = NULL;
 
-    if (is_union) {
-        assert(offset == 0);
-        offset = maxsize;
-    }
-
     /* Like C, if the size of this structure would be zero, we compute it
        as 1 instead.  But for ctypes support, we allow the manually-
        specified totalsize to be zero in this case. */
+    boffsetmax = (boffsetmax + 7) / 8;        /* bits -> bytes */
     if (totalsize < 0) {
-        offset = (offset + alignment - 1) & ~(alignment-1);
-        totalsize = (offset == 0 ? 1 : offset);
-    }
-    else if (totalsize < offset) {
+        totalsize = (boffsetmax + alignment - 1) & ~(alignment-1);
+        if (totalsize == 0)
+            totalsize = 1;
+    }
+    else if (totalsize < boffsetmax) {
         PyErr_Format(PyExc_TypeError,
                      "%s cannot be of size %zd: there are fields at least "
-                     "up to %zd", ct->ct_name, totalsize, offset);
+                     "up to %zd", ct->ct_name, totalsize, boffsetmax);
         goto error;
     }
     ct->ct_size = totalsize;
         }
         assert(cf == NULL);
 
-#ifdef USE_C_LIBFFI_MSVC
-        /* MSVC returns small structures in registers.  Pretend int32 or
-           int64 return type.  This is needed as a workaround for what
-           is really a bug of libffi_msvc seen as an independent library
-           (ctypes has a similar workaround). */
-        if (is_result_type) {
-            if (ct->ct_size <= 4)
-                return &ffi_type_sint32;
-            if (ct->ct_size <= 8)
-                return &ffi_type_sint64;
-        }
-#endif
-
         /* next, allocate and fill the flattened list */
         elements = fb_alloc(fb, (nflat + 1) * sizeof(ffi_type*));
         nflat = 0;
 
     closure = cffi_closure_alloc();
 
-    cd = PyObject_New(CDataObject, &CDataOwning_Type);
+    cd = PyObject_GC_New(CDataObject, &CDataOwningGC_Type);
     if (cd == NULL)
         goto error;
     Py_INCREF(ct);
     cd->c_type = ct;
     cd->c_data = (char *)closure;
     cd->c_weakreflist = NULL;
+    PyObject_GC_Track(cd);
 
     cif_descr = (cif_description_t *)ct->ct_extra;
     if (cif_descr == NULL) {
     Py_CLEAR(dict2);
     Py_CLEAR(dict1);
 
-    name_size = strlen("enum ") + strlen(ename) + 1;
+    name_size = strlen(ename) + 1;
     td = ctypedescr_new(name_size);
     if (td == NULL)
         goto error;
 
-    memcpy(td->ct_name, "enum ", strlen("enum "));
-    memcpy(td->ct_name + strlen("enum "), ename, name_size - strlen("enum "));
+    memcpy(td->ct_name, ename, name_size);
     td->ct_stuff = combined;
     td->ct_size = basetd->ct_size;
     td->ct_length = basetd->ct_length;   /* alignment */
     return Py_None;
 }
 
+static PyObject *b_newp_handle(PyObject *self, PyObject *args)
+{
+    CTypeDescrObject *ct;
+    CDataObject *cd;
+    PyObject *x;
+    if (!PyArg_ParseTuple(args, "O!O", &CTypeDescr_Type, &ct, &x))
+        return NULL;
+
+    if (!(ct->ct_flags & CT_IS_VOID_PTR)) {
+        PyErr_Format(PyExc_TypeError, "needs 'void *', got '%s'", ct->ct_name);
+        return NULL;
+    }
+
+    cd = (CDataObject *)PyObject_GC_New(CDataObject, &CDataOwningGC_Type);
+    if (cd == NULL)
+        return NULL;
+    Py_INCREF(ct);
+    cd->c_type = ct;
+    Py_INCREF(x);
+    cd->c_data = ((char *)x) - 42;
+    cd->c_weakreflist = NULL;
+    PyObject_GC_Track(cd);
+    return (PyObject *)cd;
+}
+
+static PyObject *b_from_handle(PyObject *self, PyObject *arg)
+{
+    CTypeDescrObject *ct;
+    char *raw;
+    PyObject *x;
+    if (!CData_Check(arg)) {
+        PyErr_SetString(PyExc_TypeError, "expected a 'cdata' object");
+        return NULL;
+    }
+    ct = ((CDataObject *)arg)->c_type;
+    raw = ((CDataObject *)arg)->c_data;
+    if (!(ct->ct_flags & CT_CAST_ANYTHING)) {
+        PyErr_Format(PyExc_TypeError,
+                     "expected a 'cdata' object with a 'void *' out of "
+                     "new_handle(), got '%s'", ct->ct_name);
+        return NULL;
+    }
+    if (!raw) {
+        PyErr_SetString(PyExc_RuntimeError,
+                        "cannot use from_handle() on NULL pointer");
+        return NULL;
+    }
+    x = (PyObject *)(raw + 42);
+    Py_INCREF(x);
+    return x;
+}
+
 static PyObject *b__get_types(PyObject *self, PyObject *noarg)
 {
     return PyTuple_Pack(2, (PyObject *)&CData_Type,
     return ptr->a1 + (int)ptr->a2;
 }
 
-static long double _testfunc19(long double x)
+static long double _testfunc19(long double x, int count)
 {
     int i;
-    for (i=0; i<28; i++)
-        x += x;
+    for (i=0; i<count; i++) {
+        x = 4*x - x*x;
+    }
     return x;
 }
 
     {"buffer", b_buffer, METH_VARARGS},
     {"get_errno", b_get_errno, METH_NOARGS},
     {"set_errno", b_set_errno, METH_VARARGS},
+    {"newp_handle", b_newp_handle, METH_VARARGS},
+    {"from_handle", b_from_handle, METH_O},
     {"_get_types", b__get_types, METH_NOARGS},
     {"_testfunc", b__testfunc, METH_VARARGS},
     {NULL,     NULL}    /* Sentinel */
 _cffi_to_c_UNSIGNED_FN(unsigned int, 32)
 _cffi_to_c_UNSIGNED_FN(unsigned PY_LONG_LONG, 64)
 
-static char _cffi_to_c_char(PyObject *obj)
-{
-    return (char)_convert_to_char(obj);
-}
-
 static PyObject *_cffi_from_c_pointer(char *ptr, CTypeDescrObject *ct)
 {
     return convert_to_object((char *)&ptr, ct);
     _cffi_to_c_u32,
     _cffi_to_c_i64,
     _cffi_to_c_u64,
-    _cffi_to_c_char,
+    _convert_to_char,
     _cffi_from_c_pointer,
     _cffi_to_c_pointer,
     _cffi_get_struct_layout,
         INITERROR;
     if (PyType_Ready(&CDataOwning_Type) < 0)
         INITERROR;
+    if (PyType_Ready(&CDataOwningGC_Type) < 0)
+        INITERROR;
     if (PyType_Ready(&CDataIter_Type) < 0)
         INITERROR;
     if (PyType_Ready(&MiniBuffer_Type) < 0)
         INITERROR;
 
+    v = PyText_FromString("_cffi_backend");
+    if (v == NULL || PyDict_SetItemString(CData_Type.tp_dict,
+                                          "__module__", v) < 0)
+        INITERROR;
+    v = PyText_FromString("<cdata>");
+    if (v == NULL || PyDict_SetItemString(CData_Type.tp_dict,
+                                          "__name__", v) < 0)
+        INITERROR;
+
     v = PyCapsule_New((void *)cffi_exports, "cffi", NULL);
     if (v == NULL || PyModule_AddObject(m, "_C_API", v) < 0)
         INITERROR;
 
-    v = PyText_FromString("0.6");
+    v = PyText_FromString("0.7");
     if (v == NULL || PyModule_AddObject(m, "__version__", v) < 0)
         INITERROR;
 

c/libffi_msvc/ffi.c

   register ffi_type **p_arg;
 
   argp = stack;
-  if (ecif->cif->rtype->type == FFI_TYPE_STRUCT)
+  if (ecif->cif->flags == FFI_TYPE_STRUCT)
     {
       *(void **) argp = ecif->rvalue;
       argp += sizeof(void *);
 	      FFI_ASSERT(0);
 	    }
 	}
+#ifdef _WIN64
+      else if (z > 8)
+        {
+          /* On Win64, if a single argument takes more than 8 bytes,
+             then it is always passed by reference. */
+          *(void **)argp = *p_argv;
+          z = 8;
+        }
+#endif
       else
 	{
 	  memcpy(argp, *p_argv, z);
   switch (cif->rtype->type)
     {
     case FFI_TYPE_VOID:
-    case FFI_TYPE_STRUCT:
     case FFI_TYPE_SINT64:
     case FFI_TYPE_FLOAT:
     case FFI_TYPE_DOUBLE:
       cif->flags = (unsigned) cif->rtype->type;
       break;
 
+    case FFI_TYPE_STRUCT:
+      /* MSVC returns small structures in registers.  Put in cif->flags
+         the value FFI_TYPE_STRUCT only if the structure is big enough;
+         otherwise, put the 4- or 8-bytes integer type. */
+      if (cif->rtype->size <= 4)
+        cif->flags = FFI_TYPE_INT;
+      else if (cif->rtype->size <= 8)
+        cif->flags = FFI_TYPE_SINT64;
+      else
+        cif->flags = FFI_TYPE_STRUCT;
+      break;
+
     case FFI_TYPE_UINT64:
 #ifdef _WIN64
     case FFI_TYPE_POINTER:
   /* value address then we need to make one		        */
 
   if ((rvalue == NULL) && 
-      (cif->rtype->type == FFI_TYPE_STRUCT))
+      (cif->flags == FFI_TYPE_STRUCT))
     {
       /*@-sysunrecog@*/
       ecif.rvalue = alloca(cif->rtype->size);
 #else
     case FFI_SYSV:
       /*@-usedef@*/
-      /* Function call needs at least 40 bytes stack size, on win64 AMD64 */
-      return ffi_call_AMD64(ffi_prep_args, &ecif, cif->bytes ? cif->bytes : 40,
+      return ffi_call_AMD64(ffi_prep_args, &ecif, cif->bytes,
 			   cif->flags, ecif.rvalue, fn);
       /*@=usedef@*/
       break;
 #else
 static void __fastcall
 #endif
-ffi_closure_SYSV (ffi_closure *closure, int *argp)
+ffi_closure_SYSV (ffi_closure *closure, char *argp)
 {
   // this is our return value storage
   long double    res;
   void         **arg_area;
   unsigned short rtype;
   void          *resp = (void*)&res;
-  void *args = &argp[1];
+  void *args = argp + sizeof(void *);
 
   cif         = closure->cif;
   arg_area    = (void**) alloca (cif->nargs * sizeof (void*));  
 
   argp = stack;
 
-  if ( cif->rtype->type == FFI_TYPE_STRUCT ) {
+  if ( cif->flags == FFI_TYPE_STRUCT ) {
     *rvalue = *(void **) argp;
     argp += 4;
   }
 
       /* because we're little endian, this is what it turns into.   */
 
+#ifdef _WIN64
+      if (z > 8)
+        {
+          /* On Win64, if a single argument takes more than 8 bytes,
+             then it is always passed by reference. */
+          *p_argv = *((void**) argp);
+          z = 8;
+        }
+      else
+#endif
       *p_argv = (void*) argp;
 
       p_argv++;

c/libffi_msvc/prep_cif.c

 #if !defined M68K && !defined __x86_64__ && !defined S390
   /* Make space for the return structure pointer */
   if (cif->rtype->type == FFI_TYPE_STRUCT
-      /* MSVC returns small structures in registers.  But we have a different
-      workaround: pretend int32 or int64 return type, and converting to
-      structure afterwards. */
+#ifdef _WIN32
+      && (cif->rtype->size > 8)  /* MSVC returns small structs in registers */
+#endif
 #ifdef SPARC
       && (cif->abi != FFI_V9 || cif->rtype->size > 32)
 #endif
 #endif
     }
 
+#ifdef _WIN64
+  /* Function call needs at least 40 bytes stack size, on win64 AMD64 */
+  if (bytes < 40)
+      bytes = 40;
+#endif
+
   cif->bytes = bytes;
 
   /* Perform machine dependent cif processing */

c/libffi_msvc/types.c

 FFI_INTEGRAL_TYPEDEF(float, 4, 4, FFI_TYPE_FLOAT);
 
 #if defined ALPHA || defined SPARC64 || defined X86_64 || defined S390X \
-    || defined IA64
+    || defined IA64 || defined _WIN64
 
 FFI_INTEGRAL_TYPEDEF(pointer, 8, 8, FFI_TYPE_POINTER);
 
Add a comment to this file

c/libffi_msvc/win64.obj

Binary file added.

     BInt = new_primitive_type("int")
     BFloat = new_primitive_type("float")
     for i in range(1, 20):
-        if (hash(cast(BChar, chr(i))) !=
-            hash(cast(BInt, i))):
+        x1 = cast(BChar, chr(i))
+        x2 = cast(BInt, i)
+        if hash(x1) != hash(x2):
             break
     else:
         raise AssertionError("hashes are equal")
 
 def test_new_struct_type():
     BStruct = new_struct_type("foo")
+    assert repr(BStruct) == "<ctype 'foo'>"
+    BStruct = new_struct_type("struct foo")
     assert repr(BStruct) == "<ctype 'struct foo'>"
     BPtr = new_pointer_type(BStruct)
     assert repr(BPtr) == "<ctype 'struct foo *'>"
     py.test.raises(ValueError, alignof, BStruct)
 
 def test_new_union_type():
-    BUnion = new_union_type("foo")
+    BUnion = new_union_type("union foo")
     assert repr(BUnion) == "<ctype 'union foo'>"
     BPtr = new_pointer_type(BUnion)
     assert repr(BPtr) == "<ctype 'union foo *'>"
     BLong = new_primitive_type("long")
     BChar = new_primitive_type("char")
     BShort = new_primitive_type("short")
-    BStruct = new_struct_type("foo")
+    BStruct = new_struct_type("struct foo")
     assert BStruct.kind == "struct"
     assert BStruct.cname == "struct foo"
     assert BStruct.fields is None
 def test_complete_union():
     BLong = new_primitive_type("long")
     BChar = new_primitive_type("char")
-    BUnion = new_union_type("foo")
+    BUnion = new_union_type("union foo")
     assert BUnion.kind == "union"
     assert BUnion.cname == "union foo"
     assert BUnion.fields is None
 
 def test_struct_instance():
     BInt = new_primitive_type("int")
-    BStruct = new_struct_type("foo")
+    BStruct = new_struct_type("struct foo")
     BStructPtr = new_pointer_type(BStruct)
     p = cast(BStructPtr, 0)
     py.test.raises(AttributeError, "p.a1")    # opaque
 def test_union_instance():
     BInt = new_primitive_type("int")
     BUInt = new_primitive_type("unsigned int")
-    BUnion = new_union_type("bar")
+    BUnion = new_union_type("union bar")
     complete_struct_or_union(BUnion, [('a1', BInt, -1), ('a2', BUInt, -1)])
     p = newp(new_pointer_type(BUnion), [-42])
     bigval = -42 + (1 << (8*size_of_int()))
 
 def test_struct_pointer():
     BInt = new_primitive_type("int")
-    BStruct = new_struct_type("foo")
+    BStruct = new_struct_type("struct foo")
     BStructPtr = new_pointer_type(BStruct)
     complete_struct_or_union(BStruct, [('a1', BInt, -1),
                                        ('a2', BInt, -1)])
     BVoidP = new_pointer_type(new_void_type())
     BInt = new_primitive_type("int")
     BIntPtr = new_pointer_type(BInt)
-    BStruct = new_struct_type("foo")
+    BStruct = new_struct_type("struct foo")
     BStructPtr = new_pointer_type(BStruct)
     complete_struct_or_union(BStruct, [('a1', BInt, -1),
                                        ('a2', BInt, -1),
 
 def test_array_in_struct():
     BInt = new_primitive_type("int")
-    BStruct = new_struct_type("foo")
+    BStruct = new_struct_type("struct foo")
     BArrayInt5 = new_array_type(new_pointer_type(BInt), 5)
     complete_struct_or_union(BStruct, [('a1', BArrayInt5, -1)])
     s = newp(new_pointer_type(BStruct), [[20, 24, 27, 29, 30]])
     def offsetof(BType, fieldname):
         return typeoffsetof(BType, fieldname)[1]
     BInt = new_primitive_type("int")
-    BStruct = new_struct_type("foo")
+    BStruct = new_struct_type("struct foo")
     py.test.raises(TypeError, offsetof, BInt, "abc")
     py.test.raises(TypeError, offsetof, BStruct, "abc")
     complete_struct_or_union(BStruct, [('abc', BInt, -1), ('def', BInt, -1)])
 def test_function_type_taking_struct():
     BChar = new_primitive_type("char")
     BShort = new_primitive_type("short")
-    BStruct = new_struct_type("foo")
+    BStruct = new_struct_type("struct foo")
     complete_struct_or_union(BStruct, [('a1', BChar, -1),
                                        ('a2', BShort, -1)])
     BFunc = new_function_type((BStruct,), BShort, False)
 def test_call_function_7():
     BChar = new_primitive_type("char")
     BShort = new_primitive_type("short")
-    BStruct = new_struct_type("foo")
+    BStruct = new_struct_type("struct foo")
     BStructPtr = new_pointer_type(BStruct)
     complete_struct_or_union(BStruct, [('a1', BChar, -1),
                                        ('a2', BShort, -1)])
 def test_call_function_20():
     BChar = new_primitive_type("char")
     BShort = new_primitive_type("short")
-    BStruct = new_struct_type("foo")
+    BStruct = new_struct_type("struct foo")
     BStructPtr = new_pointer_type(BStruct)
     complete_struct_or_union(BStruct, [('a1', BChar, -1),
                                        ('a2', BShort, -1)])
 
 def test_call_function_21():
     BInt = new_primitive_type("int")
-    BStruct = new_struct_type("foo")
+    BStruct = new_struct_type("struct foo")
     complete_struct_or_union(BStruct, [('a', BInt, -1),
                                        ('b', BInt, -1),
                                        ('c', BInt, -1),
 def test_call_function_22():
     BInt = new_primitive_type("int")
     BArray10 = new_array_type(new_pointer_type(BInt), 10)
-    BStruct = new_struct_type("foo")
+    BStruct = new_struct_type("struct foo")
     BStructP = new_pointer_type(BStruct)
     complete_struct_or_union(BStruct, [('a', BArray10, -1)])
     BFunc22 = new_function_type((BStruct, BStruct), BStruct, False)
 def test_cannot_pass_struct_with_array_of_length_0():
     BInt = new_primitive_type("int")
     BArray0 = new_array_type(new_pointer_type(BInt), 0)
-    BStruct = new_struct_type("foo")
+    BStruct = new_struct_type("struct foo")
     complete_struct_or_union(BStruct, [('a', BArray0)])
     py.test.raises(NotImplementedError, new_function_type,
                    (BStruct,), BInt, False)
 def test_cannot_call_with_a_autocompleted_struct():
     BSChar = new_primitive_type("signed char")
     BDouble = new_primitive_type("double")
-    BStruct = new_struct_type("foo")
+    BStruct = new_struct_type("struct foo")
     BStructPtr = new_pointer_type(BStruct)
     complete_struct_or_union(BStruct, [('c', BDouble, -1, 8),
                                        ('a', BSChar, -1, 2),
     for i, f in enumerate(flist):
         assert f(-142) == -142 + i
 
+def test_callback_receiving_tiny_struct():
+    BSChar = new_primitive_type("signed char")
+    BInt = new_primitive_type("int")
+    BStruct = new_struct_type("struct foo")
+    BStructPtr = new_pointer_type(BStruct)
+    complete_struct_or_union(BStruct, [('a', BSChar, -1),
+                                       ('b', BSChar, -1)])
+    def cb(s):
+        return s.a + 10 * s.b
+    BFunc = new_function_type((BStruct,), BInt)
+    f = callback(BFunc, cb)
+    p = newp(BStructPtr, [-2, -4])
+    n = f(p[0])
+    assert n == -42
+
+def test_callback_returning_tiny_struct():
+    BSChar = new_primitive_type("signed char")
+    BInt = new_primitive_type("int")
+    BStruct = new_struct_type("struct foo")
+    BStructPtr = new_pointer_type(BStruct)
+    complete_struct_or_union(BStruct, [('a', BSChar, -1),
+                                       ('b', BSChar, -1)])
+    def cb(n):
+        return newp(BStructPtr, [-n, -3*n])[0]
+    BFunc = new_function_type((BInt,), BStruct)
+    f = callback(BFunc, cb)
+    s = f(10)
+    assert typeof(s) is BStruct
+    assert repr(s) == "<cdata 'struct foo' owning 2 bytes>"
+    assert s.a == -10
+    assert s.b == -30
+
+def test_callback_receiving_struct():
+    BSChar = new_primitive_type("signed char")
+    BInt = new_primitive_type("int")
+    BDouble = new_primitive_type("double")
+    BStruct = new_struct_type("struct foo")
+    BStructPtr = new_pointer_type(BStruct)
+    complete_struct_or_union(BStruct, [('a', BSChar, -1),
+                                       ('b', BDouble, -1)])
+    def cb(s):
+        return s.a + int(s.b)
+    BFunc = new_function_type((BStruct,), BInt)
+    f = callback(BFunc, cb)
+    p = newp(BStructPtr, [-2, 44.444])
+    n = f(p[0])
+    assert n == 42
+
 def test_callback_returning_struct():
     BSChar = new_primitive_type("signed char")
     BInt = new_primitive_type("int")
     BDouble = new_primitive_type("double")
-    BStruct = new_struct_type("foo")
+    BStruct = new_struct_type("struct foo")
     BStructPtr = new_pointer_type(BStruct)
     complete_struct_or_union(BStruct, [('a', BSChar, -1),
                                        ('b', BDouble, -1)])
     assert s.a == -10
     assert s.b == 1E-42
 
+def test_callback_receiving_big_struct():
+    BInt = new_primitive_type("int")
+    BStruct = new_struct_type("struct foo")
+    BStructPtr = new_pointer_type(BStruct)
+    complete_struct_or_union(BStruct, [('a', BInt, -1),
+                                       ('b', BInt, -1),
+                                       ('c', BInt, -1),
+                                       ('d', BInt, -1),
+                                       ('e', BInt, -1),
+                                       ('f', BInt, -1),
+                                       ('g', BInt, -1),
+                                       ('h', BInt, -1),
+                                       ('i', BInt, -1),
+                                       ('j', BInt, -1)])
+    def cb(s):
+        for i, name in enumerate("abcdefghij"):
+            assert getattr(s, name) == 13 - i
+        return 42
+    BFunc = new_function_type((BStruct,), BInt)
+    f = callback(BFunc, cb)
+    p = newp(BStructPtr, list(range(13, 3, -1)))
+    n = f(p[0])
+    assert n == 42
+
 def test_callback_returning_big_struct():
     BInt = new_primitive_type("int")
-    BStruct = new_struct_type("foo")
+    BStruct = new_struct_type("struct foo")
     BStructPtr = new_pointer_type(BStruct)
     complete_struct_or_union(BStruct, [('a', BInt, -1),
                                        ('b', BInt, -1),
 def test_enum_type():
     BUInt = new_primitive_type("unsigned int")
     BEnum = new_enum_type("foo", (), (), BUInt)
-    assert repr(BEnum) == "<ctype 'enum foo'>"
+    assert repr(BEnum) == "<ctype 'foo'>"
     assert BEnum.kind == "enum"
-    assert BEnum.cname == "enum foo"
+    assert BEnum.cname == "foo"
     assert BEnum.elements == {}
     #
     BInt = new_primitive_type("int")
-    BEnum = new_enum_type("foo", ('def', 'c', 'ab'), (0, 1, -20), BInt)
+    BEnum = new_enum_type("enum foo", ('def', 'c', 'ab'), (0, 1, -20), BInt)
     assert BEnum.kind == "enum"
+    assert BEnum.cname == "enum foo"
     assert BEnum.elements == {-20: 'ab', 0: 'def', 1: 'c'}
     # 'elements' is not the real dict, but merely a copy
     BEnum.elements[2] = '??'
     assert BEnum.elements == {-20: 'ab', 0: 'def', 1: 'c'}
     #
-    BEnum = new_enum_type("bar", ('ab', 'cd'), (5, 5), BUInt)
+    BEnum = new_enum_type("enum bar", ('ab', 'cd'), (5, 5), BUInt)
     assert BEnum.elements == {5: 'ab'}
     assert BEnum.relements == {'ab': 5, 'cd': 5}
 
 def test_cast_to_enum():
     BInt = new_primitive_type("int")
-    BEnum = new_enum_type("foo", ('def', 'c', 'ab'), (0, 1, -20), BInt)
+    BEnum = new_enum_type("enum foo", ('def', 'c', 'ab'), (0, 1, -20), BInt)
     assert sizeof(BEnum) == sizeof(BInt)
     e = cast(BEnum, 0)
     assert repr(e) == "<cdata 'enum foo' 0: def>"
     assert string(cast(BEnum, -242 + 2**128)) == '-242'
     #
     BUInt = new_primitive_type("unsigned int")
-    BEnum = new_enum_type("bar", ('def', 'c', 'ab'), (0, 1, 20), BUInt)
+    BEnum = new_enum_type("enum bar", ('def', 'c', 'ab'), (0, 1, 20), BUInt)
     e = cast(BEnum, -1)
     assert repr(e) == "<cdata 'enum bar' 4294967295>"     # unsigned int
     #
     BLong = new_primitive_type("long")
-    BEnum = new_enum_type("baz", (), (), BLong)
+    BEnum = new_enum_type("enum baz", (), (), BLong)
     assert sizeof(BEnum) == sizeof(BLong)
     e = cast(BEnum, -1)
     assert repr(e) == "<cdata 'enum baz' -1>"
 
 def test_enum_with_non_injective_mapping():
     BInt = new_primitive_type("int")
-    BEnum = new_enum_type("foo", ('ab', 'cd'), (7, 7), BInt)
+    BEnum = new_enum_type("enum foo", ('ab', 'cd'), (7, 7), BInt)
     e = cast(BEnum, 7)
     assert repr(e) == "<cdata 'enum foo' 7: ab>"
     assert string(e) == 'ab'
 
 def test_enum_in_struct():
     BInt = new_primitive_type("int")
-    BEnum = new_enum_type("foo", ('def', 'c', 'ab'), (0, 1, -20), BInt)
-    BStruct = new_struct_type("bar")
+    BEnum = new_enum_type("enum foo", ('def', 'c', 'ab'), (0, 1, -20), BInt)
+    BStruct = new_struct_type("struct bar")
     BStructPtr = new_pointer_type(BStruct)
     complete_struct_or_union(BStruct, [('a1', BEnum, -1)])
     p = newp(BStructPtr, [-20])
 
 def test_struct_with_bitfields():
     BLong = new_primitive_type("long")
-    BStruct = new_struct_type("foo")
+    BStruct = new_struct_type("struct foo")
     LONGBITS = 8 * sizeof(BLong)
     complete_struct_or_union(BStruct, [('a1', BLong, 1),
                                        ('a2', BLong, 2),
 def test_bitfield_instance():
     BInt = new_primitive_type("int")
     BUnsignedInt = new_primitive_type("unsigned int")
-    BStruct = new_struct_type("foo")
+    BStruct = new_struct_type("struct foo")
     complete_struct_or_union(BStruct, [('a1', BInt, 1),
                                        ('a2', BUnsignedInt, 2),
                                        ('a3', BInt, 3)])
 
 def test_bitfield_instance_init():
     BInt = new_primitive_type("int")
-    BStruct = new_struct_type("foo")
+    BStruct = new_struct_type("struct foo")
     complete_struct_or_union(BStruct, [('a1', BInt, 1)])
     p = newp(new_pointer_type(BStruct), [-1])
     assert p.a1 == -1
     p = newp(new_pointer_type(BStruct), {'a1': -1})
     assert p.a1 == -1
     #
-    BUnion = new_union_type("bar")
+    BUnion = new_union_type("union bar")
     complete_struct_or_union(BUnion, [('a1', BInt, 1)])
     p = newp(new_pointer_type(BUnion), [-1])
     assert p.a1 == -1
     py.test.raises(IndexError, newp, BArray, tuple(b'123456'))
     py.test.raises(IndexError, newp, BArray, list(b'123456'))
     py.test.raises(IndexError, newp, BArray, b'123456')
-    BStruct = new_struct_type("foo")
+    BStruct = new_struct_type("struct foo")
     complete_struct_or_union(BStruct, [])
     py.test.raises(TypeError, newp, new_pointer_type(BStruct), b'')
     py.test.raises(ValueError, newp, new_pointer_type(BStruct), [b'1'])
     p = newp(new_pointer_type(BFloat), cast(BFloat, 12.25))
     assert p[0] == 12.25
     #
-    BStruct = new_struct_type("foo_s")
+    BStruct = new_struct_type("struct foo_s")
     BStructPtr = new_pointer_type(BStruct)
     complete_struct_or_union(BStruct, [('a1', BInt, -1)])
     s1 = newp(BStructPtr, [42])
     s2 = newp(BStructPtr, s1[0])
     assert s2.a1 == 42
     #
-    BUnion = new_union_type("foo_u")
+    BUnion = new_union_type("union foo_u")
     BUnionPtr = new_pointer_type(BUnion)
     complete_struct_or_union(BUnion, [('a1', BInt, -1)])
     u1 = newp(BUnionPtr, [42])
     BChar = new_primitive_type("char")
     BCharP = new_pointer_type(BChar)
     BCharArray10 = new_array_type(BCharP, 10)
-    BStruct = new_struct_type("foo")
+    BStruct = new_struct_type("struct foo")
     BStructPtr = new_pointer_type(BStruct)
     complete_struct_or_union(BStruct, [('a1', BCharArray10, -1)])
     p = newp(BStructPtr, None)
     new_function_type((), BFunc)    # works
     new_function_type((), new_primitive_type("int"))
     new_function_type((), new_pointer_type(BFunc))
-    BUnion = new_union_type("foo_u")
+    BUnion = new_union_type("union foo_u")
     complete_struct_or_union(BUnion, [])
     py.test.raises(NotImplementedError, new_function_type, (), BUnion)
     py.test.raises(TypeError, new_function_type, (), BArray)
     BFloat = new_primitive_type("float")
     BDouble = new_primitive_type("double")
     BInt = new_primitive_type("int")
-    BStruct = new_struct_type("foo_s")
+    BStruct = new_struct_type("struct foo_s")
     complete_struct_or_union(BStruct, [('a1', BChar, -1),
                                        ('a2', BShort, -1)])
     BFunc10 = new_function_type((BInt,), BStruct)
     assert s.a1 == bytechr(40)
     assert s.a2 == 40 * 40
     #
-    BStruct11 = new_struct_type("test11")
+    BStruct11 = new_struct_type("struct test11")
     complete_struct_or_union(BStruct11, [('a1', BInt, -1),
                                          ('a2', BInt, -1)])
     BFunc11 = new_function_type((BInt,), BStruct11)
     assert s.a1 == 40
     assert s.a2 == 40 * 40
     #
-    BStruct12 = new_struct_type("test12")
+    BStruct12 = new_struct_type("struct test12")
     complete_struct_or_union(BStruct12, [('a1', BDouble, -1),
                                          ])
     BFunc12 = new_function_type((BInt,), BStruct12)
     assert repr(s) == "<cdata 'struct test12' owning 8 bytes>"
     assert s.a1 == 40.0
     #
-    BStruct13 = new_struct_type("test13")
+    BStruct13 = new_struct_type("struct test13")
     complete_struct_or_union(BStruct13, [('a1', BInt, -1),
                                          ('a2', BInt, -1),
                                          ('a3', BInt, -1)])
     assert s.a2 == 40 * 40
     assert s.a3 == 40 * 40 * 40
     #
-    BStruct14 = new_struct_type("test14")
+    BStruct14 = new_struct_type("struct test14")
     complete_struct_or_union(BStruct14, [('a1', BFloat, -1),
                                          ])
     BFunc14 = new_function_type((BInt,), BStruct14)
     assert repr(s) == "<cdata 'struct test14' owning 4 bytes>"
     assert s.a1 == 40.0
     #
-    BStruct15 = new_struct_type("test15")
+    BStruct15 = new_struct_type("struct test15")
     complete_struct_or_union(BStruct15, [('a1', BFloat, -1),
                                          ('a2', BInt, -1)])
     BFunc15 = new_function_type((BInt,), BStruct15)
     assert s.a1 == 40.0
     assert s.a2 == 40 * 40
     #
-    BStruct16 = new_struct_type("test16")
+    BStruct16 = new_struct_type("struct test16")
     complete_struct_or_union(BStruct16, [('a1', BFloat, -1),
                                          ('a2', BFloat, -1)])
     BFunc16 = new_function_type((BInt,), BStruct16)
     assert s.a1 == 40.0
     assert s.a2 == -40.0
     #
-    BStruct17 = new_struct_type("test17")
+    BStruct17 = new_struct_type("struct test17")
     complete_struct_or_union(BStruct17, [('a1', BInt, -1),
                                          ('a2', BFloat, -1)])
     BFunc17 = new_function_type((BInt,), BStruct17)
     BFunc2 = new_function_type((), new_primitive_type("short"))
     BCharP = new_pointer_type(new_primitive_type("char"))
     BIntP = new_pointer_type(new_primitive_type("int"))
-    BStruct = new_struct_type("foo")
+    BStruct = new_struct_type("struct foo")
     BStructPtr = new_pointer_type(BStruct)
     complete_struct_or_union(BStruct, [('a1', BFunc, -1)])
     newp(BStructPtr, [cast(BFunc, 0)])
         assert not pyuni4
     #
     BWCharP = new_pointer_type(BWChar)
-    BStruct = new_struct_type("foo_s")
+    BStruct = new_struct_type("struct foo_s")
     BStructPtr = new_pointer_type(BStruct)
     complete_struct_or_union(BStruct, [('a1', BWChar, -1),
                                        ('a2', BWCharP, -1)])
     # exception to the no-keepalive rule: p=newp(BStructPtr) returns a
     # pointer owning the memory, and p[0] returns a pointer to the
     # struct that *also* owns the memory
-    BStruct = new_struct_type("foo")
+    BStruct = new_struct_type("struct foo")
     BStructPtr = new_pointer_type(BStruct)
     complete_struct_or_union(BStruct, [('a1', new_primitive_type("int"), -1),
                                        ('a2', new_primitive_type("int"), -1),
     assert q.a1 == 123456
 
 def test_nokeepalive_struct():
-    BStruct = new_struct_type("foo")
+    BStruct = new_struct_type("struct foo")
     BStructPtr = new_pointer_type(BStruct)
     BStructPtrPtr = new_pointer_type(BStructPtr)
     complete_struct_or_union(BStruct, [('a1', new_primitive_type("int"), -1)])
     py.test.raises(ValueError, 'buf[:] = b"this is much too long!"')
     buf[4:2] = b""   # no effect, but should work
     assert buf[:] == b"hi there\x00"
+    buf[:2] = b"HI"
+    assert buf[:] == b"HI there\x00"
+    buf[:2] = b"hi"
     expected = list(map(bitem2bchr, b"hi there\x00"))
     x = 0
     for i in range(-12, 12):
 def test_errno_callback():
     if globals().get('PY_DOT_PY') == '2.5':
         py.test.skip("cannot run this test on py.py with Python 2.5")
+    set_errno(95)
     def cb():
         e = get_errno()
         set_errno(e - 6)
     assert repr(x) == "<cdata 'int[3]' NULL>"
 
 def test_cast_invalid():
-    BStruct = new_struct_type("foo")
+    BStruct = new_struct_type("struct foo")
     complete_struct_or_union(BStruct, [])
     p = cast(new_pointer_type(BStruct), 123456)
     s = p[0]
 
 def test_bug_delattr():
     BLong = new_primitive_type("long")
-    BStruct = new_struct_type("foo")
+    BStruct = new_struct_type("struct foo")
     complete_struct_or_union(BStruct, [('a1', BLong, -1)])
     x = newp(new_pointer_type(BStruct))
     py.test.raises(AttributeError, "del x.a1")
     py.test.skip("later")
     BLong = new_primitive_type("long")
     BArray = new_array_type(new_pointer_type(BLong), None)
-    BStruct = new_struct_type("foo")
+    BStruct = new_struct_type("struct foo")
     BStructP = new_pointer_type(BStruct)
     complete_struct_or_union(BStruct, [('a1', BLong, -1),
                                        ('a2', BArray, -1)])
 
 def test_longdouble():
     py_py = 'PY_DOT_PY' in globals()
+    BInt = new_primitive_type("int")
     BLongDouble = new_primitive_type("long double")
     BLongDoublePtr = new_pointer_type(BLongDouble)
     BLongDoubleArray = new_array_type(BLongDoublePtr, None)
     assert float(x) == 1.23
     assert int(x) == 1
     #
-    BFunc19 = new_function_type((BLongDouble,), BLongDouble)
+    BFunc19 = new_function_type((BLongDouble, BInt), BLongDouble)
     f = cast(BFunc19, _testfunc(19))
-    start = 8
+    start = lstart = 1.5
     for i in range(107):
-        start = f(start)
-    if sizeof(BLongDouble) > sizeof(new_primitive_type("double")):
-        if not py_py:
-            assert repr(start).startswith("<cdata 'long double' 6.15")
-            assert repr(start).endswith("E+902>")
-        #
-        c = newp(BLongDoubleArray, [start])
-        x = c[0]
-        if not py_py:
-            assert repr(x).endswith("E+902>")
-            assert float(x) == float("inf")
+        start = 4 * start - start * start
+        lstart = f(lstart, 1)
+    lother = f(1.5, 107)
+    if not py_py:
+        assert float(lstart) == float(lother)
+        assert repr(lstart) == repr(lother)
+        if sizeof(BLongDouble) > sizeof(new_primitive_type("double")):
+            assert float(lstart) != start
+            assert repr(lstart).startswith("<cdata 'long double' ")
+    #
+    c = newp(BLongDoubleArray, [lstart])
+    x = c[0]
+    assert float(f(lstart, 107)) == float(f(x, 107))
 
 def test_get_array_of_length_zero():
     for length in [0, 5, 10]:
         BLong = new_primitive_type("long")
         BLongP = new_pointer_type(BLong)
         BArray0 = new_array_type(BLongP, length)
-        BStruct = new_struct_type("foo")
+        BStruct = new_struct_type("struct foo")
         BStructPtr = new_pointer_type(BStruct)
         complete_struct_or_union(BStruct, [('a1', BArray0, -1)])
         p = newp(BStructPtr, None)
 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")
+    BStruct = new_struct_type("struct foo")
+    BInnerStruct = new_struct_type("struct foo")
     complete_struct_or_union(BInnerStruct, [('a1', BInt, -1),
                                             ('a2', BChar, -1)])
     complete_struct_or_union(BStruct, [('', BInnerStruct, -1),
     BChar = new_primitive_type("char")
     BShort = new_primitive_type("short")
     assert sizeof(BShort) == alignof(BShort) == 2
-    BStruct = new_struct_type("foo")
+    BStruct = new_struct_type("struct foo")
     complete_struct_or_union(BStruct, [('a1', BChar),
                                        ('a2', BChar),
                                        ('a3', BChar)])
     assert sizeof(BStruct) == 3 and alignof(BStruct) == 1
-    BUnion = new_union_type("u")
+    BUnion = new_union_type("union u")
     complete_struct_or_union(BUnion, [('s', BStruct),
                                       ('i', BShort)])
     assert sizeof(BUnion) == 4
 
 def test_unaligned_struct():
     BInt = new_primitive_type("int")
-    BStruct = new_struct_type("foo")
+    BStruct = new_struct_type("struct foo")
     complete_struct_or_union(BStruct, [('b', BInt, -1, 1)],
                              None, 5, 1)
 
 
 def test_typeoffsetof():
     BChar = new_primitive_type("char")
-    BStruct = new_struct_type("foo")
+    BStruct = new_struct_type("struct foo")
     BStructPtr = new_pointer_type(BStruct)
     complete_struct_or_union(BStruct, [('a1', BChar, -1),
                                        ('a2', BChar, -1),
 
 def test_typeoffsetof_no_bitfield():
     BInt = new_primitive_type("int")
-    BStruct = new_struct_type("foo")
+    BStruct = new_struct_type("struct foo")
     complete_struct_or_union(BStruct, [('a1', BInt, 4)])
     py.test.raises(TypeError, typeoffsetof, BStruct, 'a1')
 
 def test_rawaddressof():
     BChar = new_primitive_type("char")
     BCharP = new_pointer_type(BChar)
-    BStruct = new_struct_type("foo")
+    BStruct = new_struct_type("struct foo")
     BStructPtr = new_pointer_type(BStruct)
     complete_struct_or_union(BStruct, [('a1', BChar, -1),
                                        ('a2', BChar, -1),
     if sys.platform == "win32":
         py.test.skip("testing FILE not implemented")
     #
-    BFILE = new_struct_type("_IO_FILE")
+    BFILE = new_struct_type("struct _IO_FILE")
     BFILEP = new_pointer_type(BFILE)
     BChar = new_primitive_type("char")
     BCharP = new_pointer_type(BChar)
         e = py.test.raises(TypeError, func, f)
     if '__pypy__' not in sys.builtin_module_names:
         assert ('note that you cannot pass Python files directly '
-                'any more since CFFI 0.6') in str(e.value)
+                'any more since CFFI 1.0') in str(e.value)
+
+def test_cdata_name_module_doc():
+    p = new_primitive_type("signed char")
+    x = cast(p, 17)
+    assert x.__module__ == '_cffi_backend'
+    assert x.__name__ == '<cdata>'
+    assert hasattr(x, '__doc__')
+
+def test_different_types_of_ptr_equality():
+    BVoidP = new_pointer_type(new_void_type())
+    BIntP = new_pointer_type(new_primitive_type("int"))
+    x = cast(BVoidP, 12345)
+    assert x == cast(BIntP, 12345)
+    assert x != cast(BIntP, 12344)
+    assert hash(x) == hash(cast(BIntP, 12345))
+
+def test_new_handle():
+    import _weakref
+    BVoidP = new_pointer_type(new_void_type())
+    BCharP = new_pointer_type(new_primitive_type("char"))
+    class mylist(list):
+        pass
+    o = mylist([2, 3, 4])
+    x = newp_handle(BVoidP, o)
+    assert repr(x) == "<cdata 'void *' handle to [2, 3, 4]>"
+    assert x
+    assert from_handle(x) is o
+    assert from_handle(cast(BCharP, x)) is o
+    wr = _weakref.ref(o)
+    del o
+    import gc; gc.collect()
+    assert wr() is not None
+    assert from_handle(x) == list((2, 3, 4))
+    assert from_handle(cast(BCharP, x)) == list((2, 3, 4))
+    del x
+    for i in range(3):
+        if wr() is not None:
+            import gc; gc.collect()
+    assert wr() is None
+    py.test.raises(RuntimeError, from_handle, cast(BCharP, 0))
+
+def test_new_handle_cycle():
+    import _weakref
+    BVoidP = new_pointer_type(new_void_type())
+    class A(object):
+        pass
+    o = A()
+    o.cycle = newp_handle(BVoidP, o)
+    wr = _weakref.ref(o)
+    del o
+    for i in range(3):
+        if wr() is not None:
+            import gc; gc.collect()
+    assert wr() is None
+
+def _test_bitfield_details(flag):
+    BChar = new_primitive_type("char")
+    BShort = new_primitive_type("short")
+    BInt = new_primitive_type("int")
+    BUInt = new_primitive_type("unsigned int")
+    BStruct = new_struct_type("struct foo1")
+    complete_struct_or_union(BStruct, [('a', BChar, -1),
+                                       ('b1', BInt, 9),
+                                       ('b2', BUInt, 7),
+                                       ('c', BChar, -1)], -1, -1, -1, flag)
+    if flag % 2 == 0:   # gcc and gcc ARM
+        assert typeoffsetof(BStruct, 'c') == (BChar, 3)
+        assert sizeof(BStruct) == 4
+    else:               # msvc
+        assert typeoffsetof(BStruct, 'c') == (BChar, 8)
+        assert sizeof(BStruct) == 12
+    assert alignof(BStruct) == 4
+    #
+    BStruct = new_struct_type("struct foo2")
+    complete_struct_or_union(BStruct, [('a', BChar, -1),
+                                       ('',  BShort, 9),
+                                       ('c', BChar, -1)], -1, -1, -1, flag)
+    assert typeoffsetof(BStruct, 'c') == (BChar, 4)
+    if flag == 0:   # gcc
+        assert sizeof(BStruct) == 5
+        assert alignof(BStruct) == 1
+    elif flag == 1: # msvc
+        assert sizeof(BStruct) == 6
+        assert alignof(BStruct) == 2
+    else:           # gcc ARM
+        assert sizeof(BStruct) == 6
+        assert alignof(BStruct) == 2
+    #
+    BStruct = new_struct_type("struct foo2")
+    complete_struct_or_union(BStruct, [('a', BChar, -1),
+                                       ('',  BInt, 0),
+                                       ('',  BInt, 0),
+                                       ('c', BChar, -1)], -1, -1, -1, flag)
+    if flag == 0:   # gcc
+        assert typeoffsetof(BStruct, 'c') == (BChar, 4)
+        assert sizeof(BStruct) == 5
+        assert alignof(BStruct) == 1
+    elif flag == 1:  # msvc
+        assert typeoffsetof(BStruct, 'c') == (BChar, 1)
+        assert sizeof(BStruct) == 2
+        assert alignof(BStruct) == 1
+    else:            # gcc ARM
+        assert typeoffsetof(BStruct, 'c') == (BChar, 4)
+        assert sizeof(BStruct) == 8
+        assert alignof(BStruct) == 4
+
+
+def test_bitfield_as_gcc():
+    _test_bitfield_details(flag=0)
+
+def test_bitfield_as_msvc():
+    _test_bitfield_details(flag=1)
+
+def test_bitfield_as_arm_gcc():
+    _test_bitfield_details(flag=2)
+
 
 def test_version():
     # this test is here mostly for PyPy
-    assert __version__ == "0.6"
+    assert __version__ == "0.7"
 from .api import FFI, CDefError, FFIError
 from .ffiplatform import VerificationError, VerificationMissing
 
-__version__ = "0.6"
-__version_info__ = (0, 6)
+__version__ = "0.7.2"
+__version_info__ = (0, 7, 2)
             # You need PyPy (>= 2.0 beta), or a CPython (>= 2.6) with
             # _cffi_backend.so compiled.
             import _cffi_backend as backend
+            from . import __version__
+            assert (backend.__version__ == __version__ or
+                    backend.__version__ == __version__[:3])
             # (If you insist you can also try to pass the option
             # 'backend=backend_ctypes.CTypesBackend()', but don't
             # rely on it!  It's probably not going to work well.)
             if name.startswith('RTLD_'):
                 setattr(self, name, getattr(backend, name))
         #
-        BVoidP = self._get_cached_btype(model.voidp_type)
+        self.BVoidP = self._get_cached_btype(model.voidp_type)
         if isinstance(backend, types.ModuleType):
             # _cffi_backend: attach these constants to the class
             if not hasattr(FFI, 'NULL'):
-                FFI.NULL = self.cast(BVoidP, 0)
+                FFI.NULL = self.cast(self.BVoidP, 0)
                 FFI.CData, FFI.CType = backend._get_types()
         else:
             # ctypes backend: attach these constants to the instance
-            self.NULL = self.cast(BVoidP, 0)
+            self.NULL = self.cast(self.BVoidP, 0)
             self.CData, self.CType = backend._get_types()
 
     def cdef(self, csource, override=False):
         """
         if isinstance(cdecl, basestring):
             return self._typeof(cdecl)
-        else:
+        if isinstance(cdecl, self.CData):
             return self._backend.typeof(cdecl)
+        if isinstance(cdecl, types.BuiltinFunctionType):
+            res = _builtin_function_type(cdecl)
+            if res is not None:
+                return res
+        raise TypeError(type(cdecl))
 
     def sizeof(self, cdecl):
         """Return the size in bytes of the argument.  It can be a
         it as a string or unicode string.
 
         If 'cdata' is an enum, returns the value of the enumerator as a
-        string, or '#NUMBER' if the value is out of range.
+        string, or 'NUMBER' if the value is out of range.
         """
         return self._backend.string(cdata, maxlen)
 
         self._cdefsources.extend(ffi_to_include._cdefsources)
         self._cdefsources.append(']')
 
+    def new_handle(self, x):
+        return self._backend.newp_handle(self.BVoidP, x)
+
+    def from_handle(self, x):
+        return self._backend.from_handle(x)
+
 
 def _make_ffi_library(ffi, libname, flags, guess=False):
     import os
             _name = 'c'    # on Posix only
         try:
             if '.' not in _name and '/' not in _name:
-                raise OSError
+                raise OSError("library not found: %r" % (_name,))
             backendlib = backend.load_library(_name, flags)
         except OSError:
             import ctypes.util
             path = ctypes.util.find_library(_name)
             if path is None:
-                raise OSError("library not found: %r" % (_name,))
+                raise     # propagate the original OSError
             backendlib = backend.load_library(path, flags)
     else:
         backendlib = backend.load_library(libname, flags)
+    copied_enums = []
     #
     def make_accessor(name):
         key = 'function ' + name
         if key in ffi._parser._declarations:
             tp = ffi._parser._declarations[key]
             BType = ffi._get_cached_btype(tp)
-            value = backendlib.load_function(BType, name)
+            try:
+                value = backendlib.load_function(BType, name)
+            except KeyError as e:
+                raise AttributeError('%s: %s' % (name, e))
             library.__dict__[name] = value
             return
         #
                 lambda self, value: write_variable(BType, name, value)))
             return
         #
+        if not copied_enums:
+            from . import model
+            for key, tp in ffi._parser._declarations.items():
+                if not isinstance(tp, model.EnumType):
+                    continue
+                for enumname, enumval in zip(tp.enumerators, tp.enumvalues):
+                    if enumname not in library.__dict__:
+                        library.__dict__[enumname] = enumval
+            copied_enums.append(True)
+        #
+        if name in library.__dict__:   # copied from an enum value just above,
+            return                     # or multithread's race condition
         raise AttributeError(name)
     #
     class FFILibrary(object):
     ffi._function_caches.append(library.__dict__)
     ffi._libraries.append(library)
     return library
+
+def _builtin_function_type(func):
+    # a hack to make at least ffi.typeof(builtin_function) work,
+    # if the builtin function was obtained by 'vengine_cpy'.
+    import sys
+    try:
+        module = sys.modules[func.__module__]
+        ffi = module._cffi_original_ffi
+        types_of_builtin_funcs = module._cffi_types_of_builtin_funcs
+        tp = types_of_builtin_funcs[func]
+    except (KeyError, AttributeError, TypeError):
+        return None
+    else:
+        return ffi._get_cached_btype(tp)

cffi/backend_ctypes.py

 class CTypesData(object):
     __metaclass__ = CTypesType
     __slots__ = ['__weakref__']
+    __name__ = '<cdata>'
 
     def __init__(self, *args):
         raise TypeError("cannot instantiate %r" % (self.__class__,))
         elif BItem in (getbtype(model.PrimitiveType('signed char')),
                        getbtype(model.PrimitiveType('unsigned char'))):
             kind = 'bytep'
+        elif BItem is getbtype(model.void_type):
+            kind = 'voidp'
         else:
             kind = 'generic'
         #
             def __setitem__(self, index, value):
                 self._as_ctype_ptr[index] = BItem._to_ctypes(value)
 
-            if kind == 'charp':
+            if kind == 'charp' or kind == 'voidp':
                 @classmethod
-                def _arg_to_ctypes(cls, value):
-                    if isinstance(value, bytes):
-                        return ctypes.c_char_p(value)
+                def _arg_to_ctypes(cls, *value):
+                    if value and isinstance(value[0], bytes):
+                        return ctypes.c_char_p(value[0])
                     else:
-                        return super(CTypesPtr, cls)._arg_to_ctypes(value)
+                        return super(CTypesPtr, cls)._arg_to_ctypes(*value)
 
             if kind == 'charp' or kind == 'bytep':
                 def _to_string(self, maxlen):
         class CTypesStructOrUnion(CTypesBaseStructOrUnion):
             __slots__ = ['_blob']
             _ctype = struct_or_union
-            _reftypename = '%s %s &' % (kind, name)
+            _reftypename = '%s &' % (name,)
             _kind = kind
         #
         CTypesStructOrUnion._fix_class()
         #
         class CTypesEnum(CTypesInt):
             __slots__ = []
-            _reftypename = 'enum %s &' % name
+            _reftypename = '%s &' % name
 
             def _get_own_repr(self):
                 value = self._value

cffi/commontypes.py

         elif result in model.PrimitiveType.ALL_PRIMITIVE_TYPES:
             result = model.PrimitiveType(result)
         else:
-            assert commontype != result
+            if commontype == result:
+                raise api.FFIError("Unsupported type: %r.  Please file a bug "
+                                   "if you think it should be." % (commontype,))
             result = resolve_common_type(result)   # recursively
         assert isinstance(result, model.BaseTypeByIdentity)
         _CACHE[commontype] = result
 
 from . import api, model
 from .commontypes import COMMON_TYPES, resolve_common_type
-import pycparser.c_parser, weakref, re, sys
+try:
+    from . import _pycparser as pycparser
+except ImportError:
+    import pycparser
+import weakref, re, sys
 
 try:
     if sys.version_info < (3,):
                 # assume a primitive type.  get it from .names, but reduce
                 # synonyms to a single chosen combination
                 names = list(type.names)
-                if names == ['signed'] or names == ['unsigned']:
-                    names.append('int')
-                if names[0] == 'signed' and names != ['signed', 'char']:
-                    names.pop(0)
-                if (len(names) > 1 and names[-1] == 'int'
-                        and names != ['unsigned', 'int']):
-                    names.pop()
+                if names != ['signed', 'char']:    # keep this unmodified
+                    prefixes = {}
+                    while names:
+                        name = names[0]
+                        if name in ('short', 'long', 'signed', 'unsigned'):
+                            prefixes[name] = prefixes.get(name, 0) + 1
+                            del names[0]
+                        else:
+                            break
+                    # ignore the 'signed' prefix below, and reorder the others
+                    newnames = []
+                    for prefix in ('unsigned', 'short', 'long'):
+                        for i in range(prefixes.get(prefix, 0)):
+                            newnames.append(prefix)
+                    if not names:
+                        names = ['int']    # implicitly
+                    if names == ['int']:   # but kill it if 'short' or 'long'
+                        if 'short' in prefixes or 'long' in prefixes:
+                            names = []
+                    names = newnames + names
                 ident = ' '.join(names)
                 if ident == 'void':
                     return model.void_type
                 self._partial_length = True
                 return None
         #
-        raise api.FFIError("unsupported non-constant or "
-                           "not immediately constant expression")
+        raise api.FFIError("unsupported expression: expected a "
+                           "simple numeric constant")
 
     def _build_enum_type(self, explicit_name, decls):
         if decls is not None:
                     nextenumvalue = self._parse_constant(enum.value)
                 enumvalues.append(nextenumvalue)
                 nextenumvalue += 1
-            enumvalues = tuple(enumvalues) 
+            enumvalues = tuple(enumvalues)
             tp = model.EnumType(explicit_name, enumerators, enumvalues)
             tp.partial = partial
         else:   # opaque enum
         self.forcename = forcename
         self.build_c_name_with_marker()
 
+    def get_official_name(self):
+        assert self.c_name_with_marker.endswith('&')
+        return self.c_name_with_marker[:-1]
+