Hello community,

here is the log from the commit of package python-cffi for openSUSE:Factory 
checked in at 2019-11-04 17:05:57
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-cffi (Old)
 and      /work/SRC/openSUSE:Factory/.python-cffi.new.2990 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-cffi"

Mon Nov  4 17:05:57 2019 rev:28 rq:738589 version:1.13.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-cffi/python-cffi.changes  2019-05-05 
21:19:36.492981151 +0200
+++ /work/SRC/openSUSE:Factory/.python-cffi.new.2990/python-cffi.changes        
2019-11-04 17:06:03.480238796 +0100
@@ -1,0 +2,6 @@
+Tue Oct 15 10:39:50 UTC 2019 - Tomáš Chvátal <tchva...@suse.com>
+
+- Update to 1.13.0:
+  * No changelog provided upstream
+
+-------------------------------------------------------------------

Old:
----
  cffi-1.12.3.tar.gz

New:
----
  cffi-1.13.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-cffi.spec ++++++
--- /var/tmp/diff_new_pack.O2R1Ev/_old  2019-11-04 17:06:04.260239629 +0100
+++ /var/tmp/diff_new_pack.O2R1Ev/_new  2019-11-04 17:06:04.264239633 +0100
@@ -18,7 +18,7 @@
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-cffi
-Version:        1.12.3
+Version:        1.13.0
 Release:        0
 Summary:        Foreign Function Interface for Python calling C code
 License:        MIT

++++++ cffi-1.12.3.tar.gz -> cffi-1.13.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.12.3/PKG-INFO new/cffi-1.13.0/PKG-INFO
--- old/cffi-1.12.3/PKG-INFO    2019-04-19 18:23:58.000000000 +0200
+++ new/cffi-1.13.0/PKG-INFO    2019-10-15 11:29:36.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: cffi
-Version: 1.12.3
+Version: 1.13.0
 Summary: Foreign Function Interface for Python calling C code.
 Home-page: http://cffi.readthedocs.org
 Author: Armin Rigo, Maciej Fijalkowski
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.12.3/c/_cffi_backend.c 
new/cffi-1.13.0/c/_cffi_backend.c
--- old/cffi-1.12.3/c/_cffi_backend.c   2019-04-19 18:23:55.000000000 +0200
+++ new/cffi-1.13.0/c/_cffi_backend.c   2019-10-15 11:27:46.000000000 +0200
@@ -2,7 +2,7 @@
 #include <Python.h>
 #include "structmember.h"
 
-#define CFFI_VERSION  "1.12.3"
+#define CFFI_VERSION  "1.13.0"
 
 #ifdef MS_WIN32
 #include <windows.h>
@@ -238,12 +238,14 @@
 static PyTypeObject CData_Type;
 static PyTypeObject CDataOwning_Type;
 static PyTypeObject CDataOwningGC_Type;
+static PyTypeObject CDataFromBuf_Type;
 static PyTypeObject CDataGCP_Type;
 
 #define CTypeDescr_Check(ob)  (Py_TYPE(ob) == &CTypeDescr_Type)
 #define CData_Check(ob)       (Py_TYPE(ob) == &CData_Type ||            \
                                Py_TYPE(ob) == &CDataOwning_Type ||      \
                                Py_TYPE(ob) == &CDataOwningGC_Type ||    \
+                               Py_TYPE(ob) == &CDataFromBuf_Type ||     \
                                Py_TYPE(ob) == &CDataGCP_Type)
 #define CDataOwn_Check(ob)    (Py_TYPE(ob) == &CDataOwning_Type ||      \
                                Py_TYPE(ob) == &CDataOwningGC_Type)
@@ -277,14 +279,14 @@
 
 typedef struct {
     CDataObject head;
-    PyObject *structobj;
+    PyObject *structobj;   /* for ffi.new_handle() or ffi.new("struct *") */
 } CDataObject_own_structptr;
 
 typedef struct {
     CDataObject head;
     Py_ssize_t length;     /* same as CDataObject_own_length up to here */
     Py_buffer *bufferview;
-} CDataObject_owngc_frombuf;
+} CDataObject_frombuf;
 
 typedef struct {
     CDataObject head;
@@ -1853,6 +1855,7 @@
     assert(!(cd->c_type->ct_flags & (CT_IS_VOID_PTR | CT_FUNCTIONPTR)));
 
     if (cd->c_type->ct_flags & CT_IS_PTR_TO_OWNED) {
+        /* for ffi.new("struct *") */
         Py_DECREF(((CDataObject_own_structptr *)cd)->structobj);
     }
 #if defined(CFFI_MEM_DEBUG) || defined(CFFI_MEM_LEAK)
@@ -1873,9 +1876,6 @@
 
 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 */
@@ -1892,14 +1892,21 @@
         cffi_closure_free(closure);
 #endif
     }
-    else if (cd->c_type->ct_flags & CT_ARRAY) {         /* from_buffer */
-        Py_buffer *view = ((CDataObject_owngc_frombuf *)cd)->bufferview;
-        PyBuffer_Release(view);
-        PyObject_Free(view);
+    else {
+        Py_FatalError("cdata CDataOwningGC_Type with unexpected type flags");
     }
     cdata_dealloc(cd);
 }
 
+static void cdatafrombuf_dealloc(CDataObject *cd)
+{
+    Py_buffer *view = ((CDataObject_frombuf *)cd)->bufferview;
+    cdata_dealloc(cd);
+
+    PyBuffer_Release(view);
+    PyObject_Free(view);
+}
+
 static int cdataowninggc_traverse(CDataObject *cd, visitproc visit, void *arg)
 {
     if (cd->c_type->ct_flags & CT_IS_VOID_PTR) {        /* a handle */
@@ -1911,10 +1918,13 @@
         PyObject *args = (PyObject *)(closure->user_data);
         Py_VISIT(args);
     }
-    else if (cd->c_type->ct_flags & CT_ARRAY) {         /* from_buffer */
-        Py_buffer *view = ((CDataObject_owngc_frombuf *)cd)->bufferview;
-        Py_VISIT(view->obj);
-    }
+    return 0;
+}
+
+static int cdatafrombuf_traverse(CDataObject *cd, visitproc visit, void *arg)
+{
+    Py_buffer *view = ((CDataObject_frombuf *)cd)->bufferview;
+    Py_VISIT(view->obj);
     return 0;
 }
 
@@ -1933,10 +1943,13 @@
         closure->user_data = NULL;
         Py_XDECREF(args);
     }
-    else if (cd->c_type->ct_flags & CT_ARRAY) {         /* from_buffer */
-        Py_buffer *view = ((CDataObject_owngc_frombuf *)cd)->bufferview;
-        PyBuffer_Release(view);
-    }
+    return 0;
+}
+
+static int cdatafrombuf_clear(CDataObject *cd)
+{
+    Py_buffer *view = ((CDataObject_frombuf *)cd)->bufferview;
+    PyBuffer_Release(view);
     return 0;
 }
 
@@ -2118,6 +2131,35 @@
     return -1;
 }
 
+static PyObject *_frombuf_repr(CDataObject *cd, const char *cd_type_name)
+{
+    Py_buffer *view = ((CDataObject_frombuf *)cd)->bufferview;
+    const char *obj_tp_name;
+    if (view->obj == NULL) {
+        return PyText_FromFormat(
+            "<cdata '%s' buffer RELEASED>",
+            cd_type_name);
+    }
+
+    obj_tp_name = Py_TYPE(view->obj)->tp_name;
+    if (cd->c_type->ct_flags & CT_ARRAY)
+    {
+        Py_ssize_t buflen = get_array_length(cd);
+        return PyText_FromFormat(
+            "<cdata '%s' buffer len %zd from '%.200s' object>",
+            cd_type_name,
+            buflen,
+            obj_tp_name);
+    }
+    else
+    {
+        return PyText_FromFormat(
+            "<cdata '%s' buffer from '%.200s' object>",
+            cd_type_name,
+            obj_tp_name);
+    }
+}
+
 static PyObject *cdataowning_repr(CDataObject *cd)
 {
     Py_ssize_t size = _cdata_var_byte_size(cd);
@@ -2147,16 +2189,12 @@
         else
             return _cdata_repr2(cd, "calling", PyTuple_GET_ITEM(args, 1));
     }
-    else if (cd->c_type->ct_flags & CT_ARRAY) {         /* from_buffer */
-        Py_buffer *view = ((CDataObject_owngc_frombuf *)cd)->bufferview;
-        Py_ssize_t buflen = get_array_length(cd);
-        return PyText_FromFormat(
-            "<cdata '%s' buffer len %zd from '%.200s' object>",
-            cd->c_type->ct_name,
-            buflen,
-            view->obj ? Py_TYPE(view->obj)->tp_name : "(null)");
-    }
-    return cdataowning_repr(cd);
+    return cdataowning_repr(cd);   /* but should be unreachable */
+}
+
+static PyObject *cdatafrombuf_repr(CDataObject *cd)
+{
+    return _frombuf_repr(cd, cd->c_type->ct_name);
 }
 
 static int cdata_nonzero(CDataObject *cd)
@@ -2959,6 +2997,12 @@
                      cd->c_type->ct_name);
         return NULL;
     }
+    if (cd->c_data == NULL) {
+        PyErr_Format(PyExc_RuntimeError,
+                     "cannot call null pointer pointer from cdata '%s'",
+                     cd->c_type->ct_name);
+        return NULL;
+    }
     if (kwds != NULL && PyDict_Size(kwds) != 0) {
         PyErr_SetString(PyExc_TypeError,
                 "a cdata function cannot be called with keyword arguments");
@@ -3168,9 +3212,8 @@
         if ((ct->ct_flags & (CT_POINTER | CT_ARRAY)) != 0)   /* ffi.new() */
             return 0;
     }
-    else if (Py_TYPE(cd) == &CDataOwningGC_Type) {
-        if (ct->ct_flags & CT_ARRAY)      /* ffi.from_buffer() */
-            return 1;
+    else if (Py_TYPE(cd) == &CDataFromBuf_Type) {
+        return 1;    /* ffi.from_buffer() */
     }
     else if (Py_TYPE(cd) == &CDataGCP_Type) {
         return 2;    /* ffi.gc() */
@@ -3207,14 +3250,14 @@
                 PyObject *x = ((CDataObject_own_structptr *)cd)->structobj;
                 if (Py_TYPE(x) == &CDataGCP_Type) {
                     /* this is a special case for
-                       ffi.new_allocator()("struct-or-union") */
+                       ffi.new_allocator()("struct-or-union *") */
                     cdatagcp_finalize((CDataObject_gcp *)x);
                 }
             }
             break;
 
         case 1:    /* ffi.from_buffer() */
-            view = ((CDataObject_owngc_frombuf *)cd)->bufferview;
+            view = ((CDataObject_frombuf *)cd)->bufferview;
             PyBuffer_Release(view);
             break;
 
@@ -3373,7 +3416,7 @@
 static PyTypeObject CDataOwningGC_Type = {
     PyVarObject_HEAD_INIT(NULL, 0)
     "_cffi_backend.CDataOwnGC",
-    sizeof(CDataObject_owngc_frombuf),
+    sizeof(CDataObject_own_structptr),
     0,
     (destructor)cdataowninggc_dealloc,          /* tp_dealloc */
     0,                                          /* tp_print */
@@ -3413,6 +3456,49 @@
     PyObject_GC_Del,                            /* tp_free */
 };
 
+static PyTypeObject CDataFromBuf_Type = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "_cffi_backend.CDataFromBuf",
+    sizeof(CDataObject_frombuf),
+    0,
+    (destructor)cdatafrombuf_dealloc,           /* tp_dealloc */
+    0,                                          /* tp_print */
+    0,                                          /* tp_getattr */
+    0,                                          /* tp_setattr */
+    0,                                          /* tp_compare */
+    (reprfunc)cdatafrombuf_repr,                /* tp_repr */
+    0,  /* inherited */                         /* tp_as_number */
+    0,                                          /* tp_as_sequence */
+    0,  /* inherited */                         /* tp_as_mapping */
+    0,  /* inherited */                         /* tp_hash */
+    0,  /* inherited */                         /* tp_call */
+    0,                                          /* tp_str */
+    0,  /* inherited */                         /* tp_getattro */
+    0,  /* inherited */                         /* tp_setattro */
+    0,                                          /* tp_as_buffer */
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES  /* tp_flags */
+                       | Py_TPFLAGS_HAVE_GC,
+    0,                                          /* tp_doc */
+    (traverseproc)cdatafrombuf_traverse,        /* tp_traverse */
+    (inquiry)cdatafrombuf_clear,                /* tp_clear */
+    0,  /* inherited */                         /* tp_richcompare */
+    0,  /* inherited */                         /* tp_weaklistoffset */
+    0,  /* inherited */                         /* tp_iter */
+    0,                                          /* tp_iternext */
+    0,  /* inherited */                         /* tp_methods */
+    0,                                          /* tp_members */
+    0,                                          /* tp_getset */
+    &CData_Type,                                /* tp_base */
+    0,                                          /* tp_dict */
+    0,                                          /* tp_descr_get */
+    0,                                          /* tp_descr_set */
+    0,                                          /* tp_dictoffset */
+    0,                                          /* tp_init */
+    0,                                          /* tp_alloc */
+    0,                                          /* tp_new */
+    PyObject_GC_Del,                            /* tp_free */
+};
+
 static PyTypeObject CDataGCP_Type = {
     PyVarObject_HEAD_INIT(NULL, 0)
     "_cffi_backend.CDataGCP",
@@ -4900,12 +4986,16 @@
     return 0;
 }
 
+#define ROUNDUP_BYTES(bytes, bits)    ((bytes) + ((bits) > 0))
+
 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 boffset, i, nb_fields, boffsetmax, alignedsize, boffsetorg;
+    Py_ssize_t byteoffset, i, nb_fields, byteoffsetmax, alignedsize;
+    int bitoffset;
+    Py_ssize_t byteoffsetorg;
     Py_ssize_t totalsize = -1;
     int totalalignment = -1;
     CFieldObject **previous;
@@ -4944,8 +5034,9 @@
     ct->ct_flags &= ~(CT_CUSTOM_FIELD_POS | CT_WITH_PACKED_CHANGE);
 
     alignment = 1;
-    boffset = 0;         /* this number is in *bits*, not bytes! */
-    boffsetmax = 0;      /* the maximum value of boffset, in bits too */
+    byteoffset = 0;     /* the real value is 'byteoffset+bitoffset*8', which */
+    bitoffset = 0;      /* counts the offset in bits */
+    byteoffsetmax = 0; /* the maximum value of byteoffset-rounded-up-to-byte */
     prev_bitfield_size = 0;
     prev_bitfield_free = 0;
     nb_fields = PyList_GET_SIZE(fields);
@@ -4995,7 +5086,7 @@
         }
 
         if (is_union)
-            boffset = 0;   /* reset each field at offset 0 */
+            byteoffset = bitoffset = 0;   /* reset each field at offset 0 */
 
         /* update the total alignment requirement, but skip it if the
            field is an anonymous bitfield or if SF_PACKED */
@@ -5030,20 +5121,26 @@
                 bs_flag = BS_REGULAR;
 
             /* align this field to its own 'falign' by inserting padding */
-            boffsetorg = (boffset + falignorg*8-1) & ~(falignorg*8-1); 
/*bits!*/
-            boffset = (boffset + falign*8-1) & ~(falign*8-1); /* bits! */
-            if (boffsetorg != boffset) {
+
+            /* first, pad to the next byte,
+             * then pad to 'falign' or 'falignorg' bytes */
+            byteoffset = ROUNDUP_BYTES(byteoffset, bitoffset);
+            bitoffset = 0;
+            byteoffsetorg = (byteoffset + falignorg-1) & ~(falignorg-1);
+            byteoffset = (byteoffset + falign-1) & ~(falign-1);
+
+            if (byteoffsetorg != byteoffset) {
                 ct->ct_flags |= CT_WITH_PACKED_CHANGE;
             }
 
             if (foffset >= 0) {
                 /* a forced field position: ignore the offset just computed,
                    except to know if we must set CT_CUSTOM_FIELD_POS */
-                if (detect_custom_layout(ct, sflags, boffset / 8, foffset,
+                if (detect_custom_layout(ct, sflags, byteoffset, foffset,
                                          "wrong offset for field '",
                                          PyText_AS_UTF8(fname), "'") < 0)
                     goto error;
-                boffset = foffset * 8;
+                byteoffset = foffset;
             }
 
             if (PyText_GetSize(fname) == 0 &&
@@ -5057,7 +5154,7 @@
                     *previous = _add_field(interned_fields,
                                            get_field_name(ftype, cfsrc),
                                            cfsrc->cf_type,
-                                           boffset / 8 + cfsrc->cf_offset,
+                                           byteoffset + cfsrc->cf_offset,
                                            cfsrc->cf_bitshift,
                                            cfsrc->cf_bitsize,
                                            cfsrc->cf_flags | fflags);
@@ -5070,13 +5167,13 @@
             }
             else {
                 *previous = _add_field(interned_fields, fname, ftype,
-                                        boffset / 8, bs_flag, -1, fflags);
+                                       byteoffset, bs_flag, -1, fflags);
                 if (*previous == NULL)
                     goto error;
                 previous = &(*previous)->cf_next;
             }
             if (ftype->ct_size >= 0)
-                boffset += ftype->ct_size * 8;
+                byteoffset += ftype->ct_size;
             prev_bitfield_size = 0;
         }
         else {
@@ -5113,7 +5210,7 @@
             /* 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 = byteoffset;
             field_offset_bytes &= ~(falign - 1);
 
             if (fbitsize == 0) {
@@ -5126,12 +5223,13 @@
                 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) {
+                    /* pad byteoffset to a value aligned for "ftype" */
+                    if (ROUNDUP_BYTES(byteoffset, bitoffset) > 
field_offset_bytes) {
                         field_offset_bytes += falign;
-                        assert(boffset < field_offset_bytes * 8);
+                        assert(byteoffset < field_offset_bytes);
                     }
-                    boffset = field_offset_bytes * 8;
+                    byteoffset = field_offset_bytes;
+                    bitoffset = 0;
                 }
                 else {
                     /* MSVC's notion of "ftype :0;" */
@@ -5148,7 +5246,8 @@
 
                     /* 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);
+                    bits_already_occupied = (byteoffset-field_offset_bytes) * 8
+                        + bitoffset;
 
                     if (bits_already_occupied + fbitsize > 8 * ftype->ct_size) 
{
                         /* it would not fit, we need to start at the next
@@ -5162,15 +5261,18 @@
                             goto error;
                         }
                         field_offset_bytes += falign;
-                        assert(boffset < field_offset_bytes * 8);
-                        boffset = field_offset_bytes * 8;
+                        assert(byteoffset < field_offset_bytes);
+                        byteoffset = field_offset_bytes;
+                        bitoffset = 0;
                         bitshift = 0;
                     }
                     else {
                         bitshift = bits_already_occupied;
                         assert(bitshift >= 0);
                     }
-                    boffset += fbitsize;
+                    bitoffset += fbitsize;
+                    byteoffset += (bitoffset >> 3);
+                    bitoffset &= 7;
                 }
                 else {
                     /* MSVC's algorithm */
@@ -5186,38 +5288,43 @@
                     }
                     else {
                         /* no: start a new full field */
-                        boffset = (boffset + falign*8-1) & ~(falign*8-1); 
/*align*/
-                        boffset += ftype->ct_size * 8;
+                        byteoffset = ROUNDUP_BYTES(byteoffset, bitoffset);
+                        bitoffset = 0;
+                        /* align */
+                        byteoffset = (byteoffset + falign-1) & ~(falign-1);
+                        byteoffset += ftype->ct_size;
                         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;
+                    field_offset_bytes = byteoffset - ftype->ct_size;
                 }
-
                 if (sflags & SF_GCC_BIG_ENDIAN)
                     bitshift = 8 * ftype->ct_size - fbitsize - bitshift;
 
-                *previous = _add_field(interned_fields, fname, ftype,
+                if (PyText_GetSize(fname) > 0) {
+
+                    *previous = _add_field(interned_fields, fname, ftype,
                                        field_offset_bytes, bitshift, fbitsize,
                                        fflags);
-                if (*previous == NULL)
-                    goto error;
-                previous = &(*previous)->cf_next;
+                    if (*previous == NULL)
+                        goto error;
+                    previous = &(*previous)->cf_next;
+                }
             }
         }
 
-        if (boffset > boffsetmax)
-            boffsetmax = boffset;
+        assert(bitoffset == (bitoffset & 7));
+        if (ROUNDUP_BYTES(byteoffset, bitoffset) > byteoffsetmax)
+            byteoffsetmax = ROUNDUP_BYTES(byteoffset, bitoffset);
     }
     *previous = NULL;
 
     /* 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 */
-    alignedsize = (boffsetmax + alignment - 1) & ~(alignment-1);
+    alignedsize = (byteoffsetmax + alignment - 1) & ~(alignment-1);
     if (alignedsize == 0)
         alignedsize = 1;
 
@@ -5228,10 +5335,10 @@
         if (detect_custom_layout(ct, sflags, alignedsize,
                                  totalsize, "wrong total size", "", "") < 0)
             goto error;
-        if (totalsize < boffsetmax) {
+        if (totalsize < byteoffsetmax) {
             PyErr_Format(PyExc_TypeError,
                          "%s cannot be of size %zd: there are fields at least "
-                         "up to %zd", ct->ct_name, totalsize, boffsetmax);
+                         "up to %zd", ct->ct_name, totalsize, byteoffsetmax);
             goto error;
         }
     }
@@ -6744,7 +6851,7 @@
                                                       &CDataOwningGC_Type);
     if (cd == NULL)
         return NULL;
-    Py_INCREF(ct_voidp);
+    Py_INCREF(ct_voidp);        /* must be "void *" */
     cd->head.c_type = ct_voidp;
     cd->head.c_data = (char *)cd;
     cd->head.c_weakreflist = NULL;
@@ -6862,10 +6969,11 @@
 {
     CDataObject *cd;
     Py_buffer *view;
-    Py_ssize_t arraylength;
+    Py_ssize_t arraylength, minimumlength = 0;
 
-    if (!(ct->ct_flags & CT_ARRAY)) {
-        PyErr_Format(PyExc_TypeError, "expected an array ctype, got '%s'",
+    if (!(ct->ct_flags & (CT_ARRAY | CT_POINTER))) {
+        PyErr_Format(PyExc_TypeError,
+                     "expected a pointer or array ctype, got '%s'",
                      ct->ct_name);
         return NULL;
     }
@@ -6888,43 +6996,51 @@
     if (_my_PyObject_GetContiguousBuffer(x, view, require_writable) < 0)
         goto error1;
 
-    if (ct->ct_length >= 0) {
-        /* it's an array with a fixed length; make sure that the
-           buffer contains enough bytes. */
-        if (view->len < ct->ct_size) {
-            PyErr_Format(PyExc_ValueError,
-                "buffer is too small (%zd bytes) for '%s' (%zd bytes)",
-                view->len, ct->ct_name, ct->ct_size);
-            goto error2;
-        }
-        arraylength = ct->ct_length;
-    }
-    else {
-        /* it's an open 'array[]' */
-        if (ct->ct_itemdescr->ct_size == 1) {
-            /* fast path, performance only */
-            arraylength = view->len;
-        }
-        else if (ct->ct_itemdescr->ct_size > 0) {
-            /* give it as many items as fit the buffer.  Ignore a
-               partial last element. */
-            arraylength = view->len / ct->ct_itemdescr->ct_size;
+    if (ct->ct_flags & CT_POINTER)
+    {
+        arraylength = view->len;   /* number of bytes, not used so far */
+    }
+    else {
+        /* ct->ct_flags & CT_ARRAY */
+        if (ct->ct_length >= 0) {
+            /* it's an array with a fixed length; make sure that the
+               buffer contains enough bytes. */
+            minimumlength = ct->ct_size;
+            arraylength = ct->ct_length;
         }
         else {
-            /* it's an array 'empty[]'.  Unsupported obscure case:
-               the problem is that setting the length of the result
-               to anything large (like SSIZE_T_MAX) is dangerous,
-               because if someone tries to loop over it, it will
-               turn effectively into an infinite loop. */
-            PyErr_Format(PyExc_ZeroDivisionError,
-                "from_buffer('%s', ..): the actual length of the array "
-                "cannot be computed", ct->ct_name);
-            goto error2;
+            /* it's an open 'array[]' */
+            if (ct->ct_itemdescr->ct_size == 1) {
+                /* fast path, performance only */
+                arraylength = view->len;
+            }
+            else if (ct->ct_itemdescr->ct_size > 0) {
+                /* give it as many items as fit the buffer.  Ignore a
+                   partial last element. */
+                arraylength = view->len / ct->ct_itemdescr->ct_size;
+            }
+            else {
+                /* it's an array 'empty[]'.  Unsupported obscure case:
+                   the problem is that setting the length of the result
+                   to anything large (like SSIZE_T_MAX) is dangerous,
+                   because if someone tries to loop over it, it will
+                   turn effectively into an infinite loop. */
+                PyErr_Format(PyExc_ZeroDivisionError,
+                    "from_buffer('%s', ..): the actual length of the array "
+                    "cannot be computed", ct->ct_name);
+                goto error2;
+            }
         }
     }
+    if (view->len < minimumlength) {
+        PyErr_Format(PyExc_ValueError,
+            "buffer is too small (%zd bytes) for '%s' (%zd bytes)",
+            view->len, ct->ct_name, minimumlength);
+        goto error2;
+    }
 
-    cd = (CDataObject *)PyObject_GC_New(CDataObject_owngc_frombuf,
-                                        &CDataOwningGC_Type);
+    cd = (CDataObject *)PyObject_GC_New(CDataObject_frombuf,
+                                        &CDataFromBuf_Type);
     if (cd == NULL)
         goto error2;
 
@@ -6932,8 +7048,8 @@
     cd->c_type = ct;
     cd->c_data = view->buf;
     cd->c_weakreflist = NULL;
-    ((CDataObject_owngc_frombuf *)cd)->length = arraylength;
-    ((CDataObject_owngc_frombuf *)cd)->bufferview = view;
+    ((CDataObject_frombuf *)cd)->length = arraylength;
+    ((CDataObject_frombuf *)cd)->bufferview = view;
     PyObject_GC_Track(cd);
     return (PyObject *)cd;
 
@@ -7660,6 +7776,8 @@
         INITERROR;
     if (PyType_Ready(&CDataOwningGC_Type) < 0)
         INITERROR;
+    if (PyType_Ready(&CDataFromBuf_Type) < 0)
+        INITERROR;
     if (PyType_Ready(&CDataGCP_Type) < 0)
         INITERROR;
     if (PyType_Ready(&CDataIter_Type) < 0)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.12.3/c/realize_c_type.c 
new/cffi-1.13.0/c/realize_c_type.c
--- old/cffi-1.12.3/c/realize_c_type.c  2019-04-19 18:23:56.000000000 +0200
+++ new/cffi-1.13.0/c/realize_c_type.c  2019-10-15 11:27:46.000000000 +0200
@@ -413,19 +413,12 @@
 }
 
 static PyObject *
-realize_c_type_or_func(builder_c_t *builder,
-                        _cffi_opcode_t opcodes[], int index)
+realize_c_type_or_func_now(builder_c_t *builder, _cffi_opcode_t op,
+                           _cffi_opcode_t opcodes[], int index)
 {
     PyObject *x, *y, *z;
-    _cffi_opcode_t op = opcodes[index];
     Py_ssize_t length = -1;
 
-    if ((((uintptr_t)op) & 1) == 0) {
-        x = (PyObject *)op;
-        Py_INCREF(x);
-        return x;
-    }
-
     switch (_CFFI_GETOP(op)) {
 
     case _CFFI_OP_PRIMITIVE:
@@ -638,11 +631,40 @@
         break;
     }
 
+    case 255:    /* recursion detection */
+        PyErr_Format(PyExc_RuntimeError,
+            "found a situation in which we try to build a type recursively.  "
+            "This is known to occur e.g. in ``struct s { void(*callable)"
+            "(struct s); }''.  Please report if you get this error and "
+            "really need support for your case.");
+        return NULL;
+
     default:
         PyErr_Format(PyExc_NotImplementedError, "op=%d", (int)_CFFI_GETOP(op));
         return NULL;
     }
 
+    return x;
+}
+
+static PyObject *
+realize_c_type_or_func(builder_c_t *builder,
+                        _cffi_opcode_t opcodes[], int index)
+{
+    PyObject *x;
+     _cffi_opcode_t op = opcodes[index];
+
+    if ((((uintptr_t)op) & 1) == 0) {
+        x = (PyObject *)op;
+        Py_INCREF(x);
+        return x;
+    }
+
+    opcodes[index] = (_cffi_opcode_t)255;   /* recursion detection */
+    x = realize_c_type_or_func_now(builder, op, opcodes, index);
+    if (opcodes[index] == (_cffi_opcode_t)255)
+        opcodes[index] = op;
+
     if (x != NULL && opcodes == builder->ctx.types && opcodes[index] != x) {
         assert((((uintptr_t)x) & 1) == 0);
         assert((((uintptr_t)opcodes[index]) & 1) == 1);
@@ -650,7 +672,7 @@
         opcodes[index] = x;
     }
     return x;
-};
+}
 
 static CTypeDescrObject *
 realize_c_func_return_type(builder_c_t *builder,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.12.3/c/test_c.py new/cffi-1.13.0/c/test_c.py
--- old/cffi-1.12.3/c/test_c.py 2019-04-19 18:23:56.000000000 +0200
+++ new/cffi-1.13.0/c/test_c.py 2019-10-15 11:27:46.000000000 +0200
@@ -14,7 +14,7 @@
 # ____________________________________________________________
 
 import sys
-assert __version__ == "1.12.3", ("This test_c.py file is for testing a version"
+assert __version__ == "1.13.0", ("This test_c.py file is for testing a version"
                                  " of cffi that differs from the one that we"
                                  " get from 'import _cffi_backend'")
 if sys.version_info < (3,):
@@ -3843,7 +3843,9 @@
     BIntP = new_pointer_type(BInt)
     BIntA = new_array_type(BIntP, None)
     lst = [-12345678, 87654321, 489148]
-    bytestring = buffer(newp(BIntA, lst))[:] + b'XYZ'
+    bytestring = bytearray(buffer(newp(BIntA, lst))[:] + b'XYZ')
+    lst2 = lst + [42, -999999999]
+    bytestring2 = bytearray(buffer(newp(BIntA, lst2))[:] + b'XYZ')
     #
     p1 = from_buffer(BIntA, bytestring)      # int[]
     assert typeof(p1) is BIntA
@@ -3857,7 +3859,19 @@
         p1[-1]
     #
     py.test.raises(TypeError, from_buffer, BInt, bytestring)
-    py.test.raises(TypeError, from_buffer, BIntP, bytestring)
+    #
+    p2 = from_buffer(BIntP, bytestring)      # int *
+    assert p2 == p1 or 'PY_DOT_PY' in globals()
+    # note: on py.py ^^^, bytearray buffers are not emulated well enough
+    assert typeof(p2) is BIntP
+    assert p2[0] == lst[0]
+    assert p2[1] == lst[1]
+    assert p2[2] == lst[2]
+    # hopefully does not crash, but doesn't raise an exception:
+    p2[3]
+    p2[-1]
+    # not enough data even for one, but this is not enforced:
+    from_buffer(BIntP, b"")
     #
     BIntA2 = new_array_type(BIntP, 2)
     p2 = from_buffer(BIntA2, bytestring)     # int[2]
@@ -3869,7 +3883,7 @@
         p2[2]
     with pytest.raises(IndexError):
         p2[-1]
-    assert p2 == p1
+    assert p2 == p1 or 'PY_DOT_PY' in globals()
     #
     BIntA4 = new_array_type(BIntP, 4)        # int[4]: too big
     py.test.raises(ValueError, from_buffer, BIntA4, bytestring)
@@ -3879,13 +3893,37 @@
                                        ('a2', BInt, -1)])
     BStructP = new_pointer_type(BStruct)
     BStructA = new_array_type(BStructP, None)
-    p1 = from_buffer(BStructA, bytestring)   # struct[]
-    assert len(p1) == 1
+    p1 = from_buffer(BStructA, bytestring2)   # struct[]
+    assert len(p1) == 2
     assert typeof(p1) is BStructA
-    assert p1[0].a1 == lst[0]
-    assert p1[0].a2 == lst[1]
+    assert p1[0].a1 == lst2[0]
+    assert p1[0].a2 == lst2[1]
+    assert p1[1].a1 == lst2[2]
+    assert p1[1].a2 == lst2[3]
     with pytest.raises(IndexError):
-        p1[1]
+        p1[2]
+    with pytest.raises(IndexError):
+        p1[-1]
+    assert repr(p1) == "<cdata 'foo[]' buffer len 2 from 'bytearray' object>"
+    #
+    p2 = from_buffer(BStructP, bytestring2)    # 'struct *'
+    assert p2 == p1 or 'PY_DOT_PY' in globals()
+    assert typeof(p2) is BStructP
+    assert p2.a1 == lst2[0]
+    assert p2.a2 == lst2[1]
+    assert p2[0].a1 == lst2[0]
+    assert p2[0].a2 == lst2[1]
+    assert p2[1].a1 == lst2[2]
+    assert p2[1].a2 == lst2[3]
+    # does not crash:
+    p2[2]
+    p2[-1]
+    # not enough data even for one, but this is not enforced:
+    from_buffer(BStructP, b"")
+    from_buffer(BStructP, b"1234567")
+    #
+    release(p1)
+    assert repr(p1) == "<cdata 'foo[]' buffer RELEASED>"
     #
     BEmptyStruct = new_struct_type("empty")
     complete_struct_or_union(BEmptyStruct, [], Ellipsis, 0)
@@ -3899,7 +3937,37 @@
     p1 = from_buffer(BEmptyStructA5, bytestring)   # struct empty[5]
     assert typeof(p1) is BEmptyStructA5
     assert len(p1) == 5
-    assert cast(BIntP, p1) == from_buffer(BIntA, bytestring)
+    assert (cast(BIntP, p1) == from_buffer(BIntA, bytestring)
+            or 'PY_DOT_PY' in globals())
+    #
+    BVarStruct = new_struct_type("varfoo")
+    BVarStructP = new_pointer_type(BVarStruct)
+    complete_struct_or_union(BVarStruct, [('a1', BInt, -1),
+                                          ('va', BIntA, -1)])
+    with pytest.raises(TypeError):
+        from_buffer(BVarStruct, bytestring)
+    pv = from_buffer(BVarStructP, bytestring)    # varfoo *
+    assert pv.a1 == lst[0]
+    assert pv.va[0] == lst[1]
+    assert pv.va[1] == lst[2]
+    assert sizeof(pv[0]) == 1 * size_of_int()
+    with pytest.raises(TypeError):
+        len(pv.va)
+    # hopefully does not crash, but doesn't raise an exception:
+    pv.va[2]
+    pv.va[-1]
+    # not enough data even for one, but this is not enforced:
+    from_buffer(BVarStructP, b"")
+    assert repr(pv) == "<cdata 'varfoo *' buffer from 'bytearray' object>"
+    assert repr(pv[0]).startswith("<cdata 'varfoo &' ")
+    #
+    release(pv)
+    assert repr(pv) == "<cdata 'varfoo *' buffer RELEASED>"
+    assert repr(pv[0]).startswith("<cdata 'varfoo &' ")
+    #
+    pv = from_buffer(BVarStructP, bytestring)    # make a fresh one
+    with pytest.raises(ValueError):
+        release(pv[0])
 
 def test_memmove():
     Short = new_primitive_type("short")
@@ -4325,8 +4393,10 @@
     BCharA = new_array_type(BCharP, None)
     p = from_buffer(BCharA, a)
     assert p[2] == b"z"
+    assert repr(p) == "<cdata 'char[]' buffer len 3 from 'bytearray' object>"
     release(p)
     assert p[2] == b"z"  # true so far, but might change to raise RuntimeError
+    assert repr(p) == "<cdata 'char[]' buffer RELEASED>"
     release(p)   # no effect
 
 def test_explicit_release_from_buffer_contextmgr():
@@ -4338,6 +4408,7 @@
     with p:
         assert p[2] == b"z"
     assert p[2] == b"z"  # true so far, but might change to raise RuntimeError
+    assert repr(p) == "<cdata 'char[]' buffer RELEASED>"
     release(p)   # no effect
 
 def test_explicit_release_bytearray_on_cpython():
@@ -4367,3 +4438,18 @@
         float(cast(BBool, 42))
     with pytest.raises(TypeError):
         complex(cast(BBool, 42))
+
+def test_cannot_call_null_function_pointer():
+    BInt = new_primitive_type("int")
+    BFunc = new_function_type((BInt, BInt), BInt, False)
+    f = cast(BFunc, 0)
+    with pytest.raises(RuntimeError):
+        f(40, 2)
+
+def test_huge_structure():
+    BChar = new_primitive_type("char")
+    BArray = new_array_type(new_pointer_type(BChar), sys.maxsize)
+    assert sizeof(BArray) == sys.maxsize
+    BStruct = new_struct_type("struct foo")
+    complete_struct_or_union(BStruct, [('a1', BArray, -1)])
+    assert sizeof(BStruct) == sys.maxsize
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.12.3/cffi/__init__.py 
new/cffi-1.13.0/cffi/__init__.py
--- old/cffi-1.12.3/cffi/__init__.py    2019-04-19 18:23:56.000000000 +0200
+++ new/cffi-1.13.0/cffi/__init__.py    2019-10-15 11:27:46.000000000 +0200
@@ -5,8 +5,8 @@
 from .error import CDefError, FFIError, VerificationError, VerificationMissing
 from .error import PkgConfigError
 
-__version__ = "1.12.3"
-__version_info__ = (1, 12, 3)
+__version__ = "1.13.0"
+__version_info__ = (1, 13, 0)
 
 # The verifier module file names are based on the CRC32 of a string that
 # contains the following version number.  It may be older than __version__
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.12.3/cffi/_embedding.h 
new/cffi-1.13.0/cffi/_embedding.h
--- old/cffi-1.12.3/cffi/_embedding.h   2019-04-19 18:23:56.000000000 +0200
+++ new/cffi-1.13.0/cffi/_embedding.h   2019-10-15 11:27:46.000000000 +0200
@@ -224,7 +224,7 @@
 
         if (f != NULL && f != Py_None) {
             PyFile_WriteString("\nFrom: " _CFFI_MODULE_NAME
-                               "\ncompiled with cffi version: 1.12.3"
+                               "\ncompiled with cffi version: 1.13.0"
                                "\n_cffi_backend module: ", f);
             modules = PyImport_GetModuleDict();
             mod = PyDict_GetItemString(modules, "_cffi_backend");
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.12.3/cffi/backend_ctypes.py 
new/cffi-1.13.0/cffi/backend_ctypes.py
--- old/cffi-1.12.3/cffi/backend_ctypes.py      2019-04-19 18:23:56.000000000 
+0200
+++ new/cffi-1.13.0/cffi/backend_ctypes.py      2019-10-15 11:27:46.000000000 
+0200
@@ -403,7 +403,7 @@
                         source = _cast_source_to_int(source)
                     return cls(bool(source))
                 def __int__(self):
-                    return self._value
+                    return int(self._value)
 
             if kind == 'char':
                 @classmethod
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.12.3/cffi/cparser.py 
new/cffi-1.13.0/cffi/cparser.py
--- old/cffi-1.12.3/cffi/cparser.py     2019-04-19 18:23:56.000000000 +0200
+++ new/cffi-1.13.0/cffi/cparser.py     2019-10-15 11:27:46.000000000 +0200
@@ -145,12 +145,16 @@
     return ''.join(parts)
 
 def _warn_for_string_literal(csource):
-    if '"' in csource:
-        import warnings
-        warnings.warn("String literal found in cdef() or type source. "
-                      "String literals are ignored here, but you should "
-                      "remove them anyway because some character sequences "
-                      "confuse pre-parsing.")
+    if '"' not in csource:
+        return
+    for line in csource.splitlines():
+        if '"' in line and not line.lstrip().startswith('#'):
+            import warnings
+            warnings.warn("String literal found in cdef() or type source. "
+                          "String literals are ignored here, but you should "
+                          "remove them anyway because some character sequences 
"
+                          "confuse pre-parsing.")
+            break
 
 def _preprocess(csource):
     # Remove comments.  NOTE: this only work because the cdef() section
@@ -858,19 +862,39 @@
                            "the actual array length in this context"
                            % exprnode.coord.line)
         #
-        if (isinstance(exprnode, pycparser.c_ast.BinaryOp) and
-                exprnode.op == '+'):
-            return (self._parse_constant(exprnode.left) +
-                    self._parse_constant(exprnode.right))
-        #
-        if (isinstance(exprnode, pycparser.c_ast.BinaryOp) and
-                exprnode.op == '-'):
-            return (self._parse_constant(exprnode.left) -
-                    self._parse_constant(exprnode.right))
+        if isinstance(exprnode, pycparser.c_ast.BinaryOp):
+            left = self._parse_constant(exprnode.left)
+            right = self._parse_constant(exprnode.right)
+            if exprnode.op == '+':
+                return left + right
+            elif exprnode.op == '-':
+                return left - right
+            elif exprnode.op == '*':
+                return left * right
+            elif exprnode.op == '/':
+                return self._c_div(left, right)
+            elif exprnode.op == '%':
+                return left - self._c_div(left, right) * right
+            elif exprnode.op == '<<':
+                return left << right
+            elif exprnode.op == '>>':
+                return left >> right
+            elif exprnode.op == '&':
+                return left & right
+            elif exprnode.op == '|':
+                return left | right
+            elif exprnode.op == '^':
+                return left ^ right
         #
         raise FFIError(":%d: unsupported expression: expected a "
                        "simple numeric constant" % exprnode.coord.line)
 
+    def _c_div(self, a, b):
+        result = a // b
+        if ((a < 0) ^ (b < 0)) and (a % b) != 0:
+            result += 1
+        return result
+
     def _build_enum_type(self, explicit_name, decls):
         if decls is not None:
             partial = False
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.12.3/cffi/recompiler.py 
new/cffi-1.13.0/cffi/recompiler.py
--- old/cffi-1.12.3/cffi/recompiler.py  2019-04-19 18:23:56.000000000 +0200
+++ new/cffi-1.13.0/cffi/recompiler.py  2019-10-15 11:27:46.000000000 +0200
@@ -855,8 +855,9 @@
             try:
                 if ftype.is_integer_type() or fbitsize >= 0:
                     # accept all integers, but complain on float or double
-                    prnt("  (void)((p->%s) | 0);  /* check that '%s.%s' is "
-                         "an integer */" % (fname, cname, fname))
+                    if fname != '':
+                        prnt("  (void)((p->%s) | 0);  /* check that '%s.%s' is 
"
+                             "an integer */" % (fname, cname, fname))
                     continue
                 # only accept exactly the type declared, except that '[]'
                 # is interpreted as a '*' and so will match any array length.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.12.3/cffi.egg-info/PKG-INFO 
new/cffi-1.13.0/cffi.egg-info/PKG-INFO
--- old/cffi-1.12.3/cffi.egg-info/PKG-INFO      2019-04-19 18:23:58.000000000 
+0200
+++ new/cffi-1.13.0/cffi.egg-info/PKG-INFO      2019-10-15 11:29:36.000000000 
+0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: cffi
-Version: 1.12.3
+Version: 1.13.0
 Summary: Foreign Function Interface for Python calling C code.
 Home-page: http://cffi.readthedocs.org
 Author: Armin Rigo, Maciej Fijalkowski
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.12.3/doc/source/conf.py 
new/cffi-1.13.0/doc/source/conf.py
--- old/cffi-1.12.3/doc/source/conf.py  2019-04-19 18:23:56.000000000 +0200
+++ new/cffi-1.13.0/doc/source/conf.py  2019-10-15 11:27:46.000000000 +0200
@@ -45,9 +45,9 @@
 # built documents.
 #
 # The short X.Y version.
-version = '1.12'
+version = '1.13'
 # The full version, including alpha/beta/rc tags.
-release = '1.12.3'
+release = '1.13.0'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.12.3/doc/source/installation.rst 
new/cffi-1.13.0/doc/source/installation.rst
--- old/cffi-1.12.3/doc/source/installation.rst 2019-04-19 18:23:56.000000000 
+0200
+++ new/cffi-1.13.0/doc/source/installation.rst 2019-10-15 11:27:46.000000000 
+0200
@@ -52,7 +52,7 @@
 
 * https://pypi.python.org/pypi/cffi
 
-* Checksums of the "source" package version 1.12.3:
+* Checksums of the "source" package version 1.13.0:
 
    - MD5: ...
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.12.3/doc/source/ref.rst 
new/cffi-1.13.0/doc/source/ref.rst
--- old/cffi-1.12.3/doc/source/ref.rst  2019-04-19 18:23:56.000000000 +0200
+++ new/cffi-1.13.0/doc/source/ref.rst  2019-10-15 11:27:46.000000000 +0200
@@ -51,9 +51,13 @@
 data can be used as long as this object is kept alive, but must not be
 used for a longer time.  Be careful about that when copying the
 pointer to the memory somewhere else, e.g. into another structure.
-Also, this means that a line like ``x = ffi.new(...)[0]`` is *always
-wrong:* the newly allocated object goes out of scope instantly, and so
-is freed immediately, and ``x`` is garbage.
+Also, this means that a line like ``x = ffi.cast("B *", ffi.new("A *"))``
+or ``x = ffi.new("struct s[1]")[0]`` is wrong: the newly allocated object
+goes out of scope instantly, and so is freed immediately, and ``x`` is
+garbage.  The only case where this is fine comes from a special case for
+pointers-to-struct and pointers-to-union types: after
+``p = ffi.new("struct-or-union *", ..)``, then either ``p`` or ``p[0]``
+keeps the memory alive.
 
 The returned memory is initially cleared (filled with zeroes), before
 the optional initializer is applied.  For performance, see
@@ -231,7 +235,8 @@
 *New in version 1.12:* added the optional *first* argument ``cdecl``, and
 the keyword argument ``require_writable``:
 
-* ``cdecl`` defaults to ``"char[]"``, but a different array type can be
+* ``cdecl`` defaults to ``"char[]"``, but a different array
+  or (from version 1.13) pointer type can be
   specified for the result.  A value like ``"int[]"`` will return an array of
   ints instead of chars, and its length will be set to the number of ints
   that fit in the buffer (rounded down if the division is not exact).  Values
@@ -243,6 +248,12 @@
   keeps the underlying Python object alive and locked.  (In addition,
   ``ffi.from_buffer("int[]", x)`` gives better array bound checking.)
 
+  *New in version 1.13:* ``cdecl`` can be a pointer type.  If it points
+  to a struct or union, you can, as usual, write ``p.field`` instead of
+  ``p[0].field``.  You can also access ``p[n]``; note that CFFI does not
+  perform any bounds checking in this case.  Note also that ``p[0]`` cannot
+  be used to keep the buffer alive (unlike what occurs with ``ffi.new()``).
+
 * if ``require_writable`` is set to True, the function fails if the buffer
   obtained from ``python_buffer`` is read-only (e.g. if ``python_buffer`` is
   a byte string).  The exact exception is raised by the object itself, and
@@ -608,6 +619,14 @@
     with my_new("int[]", n) as my_array:
         ...
 
+**Warning:** due to a bug, ``p = ffi.new_allocator(..)("struct-or-union *")``
+might not follow the rule that either ``p`` or ``p[0]`` keeps the memory
+alive, which holds for the normal ``ffi.new("struct-or-union *")`` allocator.
+It may sometimes be the case that if there is only a reference to ``p[0]``,
+the memory is freed.  The cause is that the rule doesn't hold for
+``ffi.gc()``, which is sometimes used in the implementation of
+``ffi.new_allocator()()``; this might be fixed in a future release.
+
 
 .. _ffi-release:
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.12.3/doc/source/whatsnew.rst 
new/cffi-1.13.0/doc/source/whatsnew.rst
--- old/cffi-1.12.3/doc/source/whatsnew.rst     2019-04-19 18:23:56.000000000 
+0200
+++ new/cffi-1.13.0/doc/source/whatsnew.rst     2019-10-15 11:27:46.000000000 
+0200
@@ -3,6 +3,29 @@
 ======================
 
 
+v1.13
+=====
+
+* ``ffi.from_buffer("type *", ..)`` is now supported, in addition to
+  ``"type[]"``.  You can then write ``p.field`` to access the items, instead
+  of only ``p[0].field``.  Be careful that no bounds checking is performed, so
+  ``p[n]`` might access data out of bounds.
+
+* fix for structs containing unnamed bitfields like ``int : 1;``.
+
+* when calling cdata of "function pointer" type, give a RuntimeError instead
+  of a crash if the pointer happens to be NULL
+
+* support some more binary operations between constants in enum definitions
+  (PR #96)
+
+* silence a warning incorrectly emitted if you use a quote in a preprocessor
+  line
+
+* detect a corner case that would throw the C code into an infinite
+  recursion, with ``ffi.cdef("""struct X { void(*fnptr)(struct X); };""")``
+
+
 v1.12.3
 =======
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.12.3/setup.py new/cffi-1.13.0/setup.py
--- old/cffi-1.12.3/setup.py    2019-04-19 18:23:56.000000000 +0200
+++ new/cffi-1.13.0/setup.py    2019-10-15 11:27:46.000000000 +0200
@@ -198,7 +198,7 @@
 
 `Mailing list <https://groups.google.com/forum/#!forum/python-cffi>`_
 """,
-        version='1.12.3',
+        version='1.13.0',
         packages=['cffi'] if cpython else [],
         package_data={'cffi': ['_cffi_include.h', 'parse_c_type.h', 
                                '_embedding.h', '_cffi_errors.h']}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.12.3/testing/cffi0/test_parsing.py 
new/cffi-1.13.0/testing/cffi0/test_parsing.py
--- old/cffi-1.12.3/testing/cffi0/test_parsing.py       2019-04-19 
18:23:56.000000000 +0200
+++ new/cffi-1.13.0/testing/cffi0/test_parsing.py       2019-10-15 
11:27:46.000000000 +0200
@@ -409,7 +409,17 @@
 def test_enum():
     ffi = FFI()
     ffi.cdef("""
-        enum Enum { POS = +1, TWO = 2, NIL = 0, NEG = -1, OP = (POS+TWO)-1};
+        enum Enum {
+            POS = +1,
+            TWO = 2,
+            NIL = 0,
+            NEG = -1,
+            ADDSUB = (POS+TWO)-1,
+            DIVMULINT = (3 * 3) / 2,
+            SHIFT = (1 << 3) >> 1,
+            BINOPS = (0x7 & 0x1) | 0x8,
+            XOR = 0xf ^ 0xa
+        };
         """)
     needs_dlopen_none()
     C = ffi.dlopen(None)
@@ -417,7 +427,11 @@
     assert C.TWO == 2
     assert C.NIL == 0
     assert C.NEG == -1
-    assert C.OP == 2
+    assert C.ADDSUB == 2
+    assert C.DIVMULINT == 4
+    assert C.SHIFT == 4
+    assert C.BINOPS == 0b1001
+    assert C.XOR == 0b0101
 
 def test_stdcall():
     ffi = FFI()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.12.3/testing/cffi0/test_verify.py 
new/cffi-1.13.0/testing/cffi0/test_verify.py
--- old/cffi-1.12.3/testing/cffi0/test_verify.py        2019-04-19 
18:23:56.000000000 +0200
+++ new/cffi-1.13.0/testing/cffi0/test_verify.py        2019-10-15 
11:27:46.000000000 +0200
@@ -2534,3 +2534,29 @@
         x.p = p
         x.cyclic = x
         del p, x
+
+def test_arithmetic_in_cdef():
+    for a in [0, 11, 15]:
+        ffi = FFI()
+        ffi.cdef("""
+            enum FOO {
+                DIVNN = ((-?) / (-3)),
+                DIVNP = ((-?) / (+3)),
+                DIVPN = ((+?) / (-3)),
+                MODNN = ((-?) % (-3)),
+                MODNP = ((-?) % (+3)),
+                MODPN = ((+?) % (-3)),
+                };
+        """.replace('?', str(a)))
+        lib = ffi.verify("""
+            enum FOO {
+                DIVNN = ((-?) / (-3)),
+                DIVNP = ((-?) / (+3)),
+                DIVPN = ((+?) / (-3)),
+                MODNN = ((-?) % (-3)),
+                MODNP = ((-?) % (+3)),
+                MODPN = ((+?) % (-3)),
+                };
+        """.replace('?', str(a)))
+        # the verify() crashes if the values in the enum are different from
+        # the values we computed ourselves from the cdef()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.12.3/testing/cffi1/test_re_python.py 
new/cffi-1.13.0/testing/cffi1/test_re_python.py
--- old/cffi-1.12.3/testing/cffi1/test_re_python.py     2019-04-19 
18:23:56.000000000 +0200
+++ new/cffi-1.13.0/testing/cffi1/test_re_python.py     2019-10-15 
11:27:46.000000000 +0200
@@ -65,7 +65,7 @@
     int add43(int, ...);
     int globalvar42;
     const int globalconst42;
-    const char *const globalconsthello = "hello";
+    const char *const globalconsthello;
     int no_such_function(int);
     int no_such_globalvar;
     struct foo_s;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.12.3/testing/cffi1/test_recompiler.py 
new/cffi-1.13.0/testing/cffi1/test_recompiler.py
--- old/cffi-1.12.3/testing/cffi1/test_recompiler.py    2019-04-19 
18:23:56.000000000 +0200
+++ new/cffi-1.13.0/testing/cffi1/test_recompiler.py    2019-10-15 
11:27:46.000000000 +0200
@@ -2338,3 +2338,101 @@
         typedef int foo_t; struct foo_s { void (*x)(foo_t); };
     """)
     py.test.raises(TypeError, ffi.new, "struct foo_s *")
+
+def test_from_buffer_struct():
+    ffi = FFI()
+    ffi.cdef("""struct foo_s { int a, b; };""")
+    lib = verify(ffi, "test_from_buffer_struct_p", """
+        struct foo_s { int a, b; };
+    """)
+    p = ffi.new("struct foo_s *", [-219239, 58974983])
+    q = ffi.from_buffer("struct foo_s[]", ffi.buffer(p))
+    assert ffi.typeof(q) == ffi.typeof("struct foo_s[]")
+    assert len(q) == 1
+    assert q[0].a == p.a
+    assert q[0].b == p.b
+    assert q == p
+    q = ffi.from_buffer("struct foo_s *", ffi.buffer(p))
+    assert ffi.typeof(q) == ffi.typeof("struct foo_s *")
+    assert q.a == p.a
+    assert q.b == p.b
+    assert q[0].a == p.a
+    assert q[0].b == p.b
+    assert q == p
+
+def test_unnamed_bitfield_1():
+    ffi = FFI()
+    ffi.cdef("""struct A { char : 1; };""")
+    lib = verify(ffi, "test_unnamed_bitfield_1", """
+        struct A { char : 1; };
+    """)
+    p = ffi.new("struct A *")
+    assert ffi.sizeof(p[0]) == 1
+    # Note: on gcc, the type name is ignored for anonymous bitfields
+    # and that's why the result is 1.  On MSVC, the result is
+    # sizeof("char") which is also 1.
+
+def test_unnamed_bitfield_2():
+    ffi = FFI()
+    ffi.cdef("""struct A {
+        short c : 1; short : 1; short d : 1; short : 1; };""")
+    lib = verify(ffi, "test_unnamed_bitfield_2", """
+        struct A {
+            short c : 1; short : 1; short d : 1; short : 1;
+        };
+    """)
+    p = ffi.new("struct A *")
+    assert ffi.sizeof(p[0]) == ffi.sizeof("short")
+
+def test_unnamed_bitfield_3():
+    ffi = FFI()
+    ffi.cdef("""struct A { struct { char : 1; char : 1; } b; };""")
+    lib = verify(ffi, "test_unnamed_bitfield_3", """
+        struct A { struct { char : 1; char : 1; } b; };
+    """)
+    p = ffi.new("struct A *")
+    assert ffi.sizeof(p[0]) == 1
+    # Note: on gcc, the type name is ignored for anonymous bitfields
+    # and that's why the result is 1.  On MSVC, the result is
+    # sizeof("char") which is also 1.
+
+def test_unnamed_bitfield_4():
+    ffi = FFI()
+    ffi.cdef("""struct A { struct {
+        unsigned c : 1; unsigned : 1; unsigned d : 1; unsigned : 1; } a;
+        };
+        struct B { struct A a; };""")
+    lib = verify(ffi, "test_unnamed_bitfield_4", """
+        struct A { struct {
+            unsigned c : 1; unsigned : 1; unsigned d : 1; unsigned : 1; } a;
+        };
+        struct B { struct A a; };
+    """)
+    b = ffi.new("struct B *")
+    a = ffi.new("struct A *")
+    assert ffi.sizeof(a[0]) == ffi.sizeof("unsigned")
+    assert ffi.sizeof(b[0]) == ffi.sizeof(a[0])
+
+def test_struct_with_func_with_struct_pointer_arg():
+    ffi = FFI()
+    ffi.cdef("""struct BinaryTree {
+            int (* CompareKey)(struct BinaryTree *tree);
+        };""")
+    lib = verify(ffi, "test_struct_with_func_with_struct_pointer_arg", """
+        struct BinaryTree {
+            int (* CompareKey)(struct BinaryTree *tree);
+        };
+    """)
+    ffi.new("struct BinaryTree *")
+
+def test_struct_with_func_with_struct_arg():
+    ffi = FFI()
+    ffi.cdef("""struct BinaryTree {
+            int (* CompareKey)(struct BinaryTree tree);
+        };""")
+    lib = verify(ffi, "test_struct_with_func_with_struct_arg", """
+        struct BinaryTree {
+            int (* CompareKey)(struct BinaryTree tree);
+        };
+    """)
+    py.test.raises(RuntimeError, ffi.new, "struct BinaryTree *")


Reply via email to