Hello community,

here is the log from the commit of package python3-cffi for openSUSE:Factory 
checked in at 2016-11-18 22:00:15
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python3-cffi (Old)
 and      /work/SRC/openSUSE:Factory/.python3-cffi.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python3-cffi"

Changes:
--------
--- /work/SRC/openSUSE:Factory/python3-cffi/python3-cffi-doc.changes    
2016-09-20 13:24:53.000000000 +0200
+++ /work/SRC/openSUSE:Factory/.python3-cffi.new/python3-cffi-doc.changes       
2016-11-18 22:00:16.000000000 +0100
@@ -1,0 +2,35 @@
+Tue Nov 15 23:55:38 UTC 2016 - a...@gmx.de
+
+- update to version 1.9.1:
+  (no changelog available)
+
+- changes from version 1.9:
+  * Structs with variable-sized arrays as their last field: now we
+    track the length of the array after ffi.new() is called, just like
+    we always tracked the length of ffi.new("int[]", 42). This lets us
+    detect out-of-range accesses to array items. This also lets us
+    display a better repr(), and have the total size returned by
+    ffi.sizeof() and ffi.buffer(). Previously both functions would
+    return a result based on the size of the declared structure type,
+    with an assumed empty array. (Thanks andrew for starting this
+    refactoring.)
+  * Add support in cdef()/set_source() for unspecified-length arrays
+    in typedefs: typedef int foo_t[...];. It was already supported for
+    global variables or structure fields.
+  * I turned in v1.8 a warning from cffi/model.py into an error: 'enum
+    xxx' has no values explicitly defined: refusing to guess which
+    integer type it is meant to be (unsigned/signed, int/long). Now
+    I’m turning it back to a warning again; it seems that guessing
+    that the enum has size int is a 99%-safe bet. (But not 100%, so it
+    stays as a warning.)
+  * Fix leaks in the code handling FILE * arguments. In CPython 3
+    there is a remaining issue that is hard to fix: if you pass a
+    Python file object to a FILE * argument, then os.dup() is used and
+    the new file descriptor is only closed when the GC reclaims the
+    Python file object—and not at the earlier time when you call
+    close(), which only closes the original file descriptor. If this
+    is an issue, you should avoid this automatic convertion of Python
+    file objects: instead, explicitly manipulate file descriptors and
+    call fdopen() from C (...via cffi).
+
+-------------------------------------------------------------------
python3-cffi.changes: same change

Old:
----
  cffi-1.8.3.tar.gz

New:
----
  cffi-1.9.1.tar.gz

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

Other differences:
------------------
++++++ python3-cffi-doc.spec ++++++
--- /var/tmp/diff_new_pack.iFQMqf/_old  2016-11-18 22:00:17.000000000 +0100
+++ /var/tmp/diff_new_pack.iFQMqf/_new  2016-11-18 22:00:17.000000000 +0100
@@ -17,7 +17,7 @@
 
 
 Name:           python3-cffi-doc
-Version:        1.8.3
+Version:        1.9.1
 Release:        0
 Summary:        Documentation for python3-cffi
 License:        MIT

python3-cffi.spec: same change
++++++ cffi-1.8.3.tar.gz -> cffi-1.9.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.8.3/PKG-INFO new/cffi-1.9.1/PKG-INFO
--- old/cffi-1.8.3/PKG-INFO     2016-09-17 12:21:52.000000000 +0200
+++ new/cffi-1.9.1/PKG-INFO     2016-11-12 14:46:13.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: cffi
-Version: 1.8.3
+Version: 1.9.1
 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.8.3/c/_cffi_backend.c 
new/cffi-1.9.1/c/_cffi_backend.c
--- old/cffi-1.8.3/c/_cffi_backend.c    2016-09-17 12:21:34.000000000 +0200
+++ new/cffi-1.9.1/c/_cffi_backend.c    2016-11-12 14:45:24.000000000 +0100
@@ -2,7 +2,7 @@
 #include <Python.h>
 #include "structmember.h"
 
-#define CFFI_VERSION  "1.8.3"
+#define CFFI_VERSION  "1.9.1"
 
 #ifdef MS_WIN32
 #include <windows.h>
@@ -132,7 +132,7 @@
 #define CT_PRIMITIVE_FITS_LONG   2048
 #define CT_IS_OPAQUE             4096
 #define CT_IS_ENUM               8192
-#define CT_IS_PTR_TO_OWNED      16384
+#define CT_IS_PTR_TO_OWNED      16384   /* only owned if CDataOwning_Type */
 #define CT_CUSTOM_FIELD_POS     32768
 #define CT_IS_LONGDOUBLE        65536
 #define CT_IS_BOOL             131072
@@ -190,9 +190,9 @@
     unsigned char cf_flags;   /* BF_... */
     struct cfieldobject_s *cf_next;
 } CFieldObject;
-#define BS_REGULAR     (-1)      /* a regular field, not with bitshift */
-#define BS_EMPTY_ARRAY (-2)      /* a field which is an array 'type[0]' */
-#define BF_IGNORE_IN_CTOR  0x01  /* union field not in the first place */
+#define BS_REGULAR            (-1) /* a regular field, not with bitshift */
+#define BS_EMPTY_ARRAY        (-2) /* a field declared 'type[0]' or 'type[]' */
+#define BF_IGNORE_IN_CTOR     0x01 /* union field not in the first place */
 
 static PyTypeObject CTypeDescr_Type;
 static PyTypeObject CField_Type;
@@ -266,6 +266,9 @@
     Py_ssize_t exchange_offset_arg[1];
 } cif_description_t;
 
+#define ADD_WRAPAROUND(x, y)  ((Py_ssize_t)(((size_t)(x)) + ((size_t)(y))))
+#define MUL_WRAPAROUND(x, y)  ((Py_ssize_t)(((size_t)(x)) * ((size_t)(y))))
+
 
 /* whenever running Python code, the errno is saved in this thread-local
    variable */
@@ -905,6 +908,23 @@
     return (PyObject *)cd;
 }
 
+static PyObject *
+new_sized_cdata(char *data, CTypeDescrObject *ct, Py_ssize_t length)
+{
+    CDataObject_own_length *scd;
+
+    scd = (CDataObject_own_length *)PyObject_Malloc(
+        offsetof(CDataObject_own_length, alignment));
+    if (PyObject_Init((PyObject *)scd, &CData_Type) == NULL)
+        return NULL;
+    Py_INCREF(ct);
+    scd->head.c_type = ct;
+    scd->head.c_data = data;
+    scd->head.c_weakreflist = NULL;
+    scd->length = length;
+    return (PyObject *)scd;
+}
+
 static CDataObject *_new_casted_primitive(CTypeDescrObject *ct);  /*forward*/
 
 static PyObject *
@@ -1161,7 +1181,8 @@
             Py_ssize_t size, itemsize;
             assert(data == NULL);
             itemsize = cf->cf_type->ct_itemdescr->ct_size;
-            size = cf->cf_offset + itemsize * varsizelength;
+            size = ADD_WRAPAROUND(cf->cf_offset,
+                                  MUL_WRAPAROUND(itemsize, varsizelength));
             if (size < 0 ||
                 ((size - cf->cf_offset) / itemsize) != varsizelength) {
                 PyErr_SetString(PyExc_OverflowError,
@@ -1827,16 +1848,34 @@
     return res;
 }
 
-static PyObject *cdataowning_repr(CDataObject *cd)
+static Py_ssize_t _cdata_var_byte_size(CDataObject *cd)
 {
-    Py_ssize_t size;
-    if (cd->c_type->ct_flags & CT_POINTER)
-        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
-        size = cd->c_type->ct_size;
+    /* If 'cd' is a 'struct foo' or 'struct foo *' allocated with
+       ffi.new(), and if the struct foo contains a varsize array,
+       then return the real allocated size.  Otherwise, return -1. */
+    if (!CDataOwn_Check(cd))
+        return -1;
 
+    if (cd->c_type->ct_flags & CT_IS_PTR_TO_OWNED) {
+        cd = (CDataObject *)((CDataObject_own_structptr *)cd)->structobj;
+    }
+    if (cd->c_type->ct_flags & CT_WITH_VAR_ARRAY) {
+        return ((CDataObject_own_length *)cd)->length;
+    }
+    return -1;
+}
+
+static PyObject *cdataowning_repr(CDataObject *cd)
+{
+    Py_ssize_t size = _cdata_var_byte_size(cd);
+    if (size < 0) {
+        if (cd->c_type->ct_flags & CT_POINTER)
+            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
+            size = cd->c_type->ct_size;
+    }
     return PyText_FromFormat("<cdata '%s' owning %zd bytes>",
                              cd->c_type->ct_name, size);
 }
@@ -2114,8 +2153,8 @@
 static PyObject *
 cdata_slice(CDataObject *cd, PySliceObject *slice)
 {
+    char *cdata;
     Py_ssize_t bounds[2];
-    CDataObject_own_length *scd;
     CTypeDescrObject *ct = _cdata_getslicearg(cd, slice, bounds);
     if (ct == NULL)
         return NULL;
@@ -2127,16 +2166,8 @@
     }
     ct = (CTypeDescrObject *)ct->ct_stuff;
 
-    scd = (CDataObject_own_length *)PyObject_Malloc(
-              offsetof(CDataObject_own_length, alignment));
-    if (PyObject_Init((PyObject *)scd, &CData_Type) == NULL)
-        return NULL;
-    Py_INCREF(ct);
-    scd->head.c_type = ct;
-    scd->head.c_data = cd->c_data + ct->ct_itemdescr->ct_size * bounds[0];
-    scd->head.c_weakreflist = NULL;
-    scd->length = bounds[1];
-    return (PyObject *)scd;
+    cdata = cd->c_data + ct->ct_itemdescr->ct_size * bounds[0];
+    return new_sized_cdata(cdata, ct, bounds[1]);
 }
 
 static int
@@ -2401,13 +2432,25 @@
             if (cf != NULL) {
                 /* read the field 'cf' */
                 char *data = cd->c_data + cf->cf_offset;
-                if (cf->cf_bitshift == BS_REGULAR)
+                Py_ssize_t array_len, size;
+
+                if (cf->cf_bitshift == BS_REGULAR) {
                     return convert_to_object(data, cf->cf_type);
-                else if (cf->cf_bitshift == BS_EMPTY_ARRAY)
-                    return new_simple_cdata(data,
-                        (CTypeDescrObject *)cf->cf_type->ct_stuff);
-                else
+                }
+                else if (cf->cf_bitshift != BS_EMPTY_ARRAY) {
                     return convert_to_object_bitfield(data, cf);
+                }
+
+                /* variable-length array: */
+                /* if reading variable length array from variable length
+                   struct, calculate array type from allocated length */
+                size = _cdata_var_byte_size(cd) - cf->cf_offset;
+                if (size >= 0) {
+                    array_len = size / cf->cf_type->ct_itemdescr->ct_size;
+                    return new_sized_cdata(data, cf->cf_type, array_len);
+                }
+                return new_simple_cdata(data,
+                    (CTypeDescrObject *)cf->cf_type->ct_stuff);
             }
             break;
         case -1:
@@ -2527,7 +2570,7 @@
 
     if (ctitem->ct_size <= 0)
         goto convert_default;
-    datasize = length * ctitem->ct_size;
+    datasize = MUL_WRAPAROUND(length, ctitem->ct_size);
     if ((datasize / ctitem->ct_size) != length) {
         PyErr_SetString(PyExc_OverflowError,
                         "array size would overflow a Py_ssize_t");
@@ -3062,6 +3105,10 @@
                         "return type is an opaque structure or union");
         return NULL;
     }
+    if (ct->ct_flags & CT_WITH_VAR_ARRAY) {
+        PyErr_SetString(PyExc_TypeError,
+                  "return type is a struct/union with a varsize array member");
+    }
     cd = allocate_owning_object(dataoffset + datasize, ct);
     if (cd == NULL)
         return NULL;
@@ -3160,15 +3207,21 @@
         if (ctitem->ct_flags & CT_PRIMITIVE_CHAR)
             datasize *= 2;   /* forcefully add another character: a null */
 
-        if ((ctitem->ct_flags & (CT_STRUCT | CT_UNION)) && init != Py_None) {
+        if (ctitem->ct_flags & (CT_STRUCT | CT_UNION)) {
             if (force_lazy_struct(ctitem) < 0)   /* for CT_WITH_VAR_ARRAY */
                 return NULL;
+
             if (ctitem->ct_flags & CT_WITH_VAR_ARRAY) {
-                Py_ssize_t optvarsize = datasize;
-                if (convert_struct_from_object(NULL,ctitem, init,
-                                               &optvarsize) < 0)
-                    return NULL;
-                datasize = optvarsize;
+                assert(ct->ct_flags & CT_IS_PTR_TO_OWNED);
+                dataoffset = offsetof(CDataObject_own_length, alignment);
+
+                if (init != Py_None) {
+                    Py_ssize_t optvarsize = datasize;
+                    if (convert_struct_from_object(NULL, ctitem, init,
+                                                   &optvarsize) < 0)
+                        return NULL;
+                    datasize = optvarsize;
+                }
             }
         }
     }
@@ -3181,7 +3234,7 @@
                 return NULL;
             ctitem = ct->ct_itemdescr;
             dataoffset = offsetof(CDataObject_own_length, alignment);
-            datasize = explicitlength * ctitem->ct_size;
+            datasize = MUL_WRAPAROUND(explicitlength, ctitem->ct_size);
             if (explicitlength > 0 &&
                     (datasize / explicitlength) != ctitem->ct_size) {
                 PyErr_SetString(PyExc_OverflowError,
@@ -3216,6 +3269,10 @@
         }
         /* store the only reference to cds into cd */
         ((CDataObject_own_structptr *)cd)->structobj = (PyObject *)cds;
+        /* store information about the allocated size of the struct */
+        if (dataoffset == offsetof(CDataObject_own_length, alignment)) {
+            ((CDataObject_own_length *)cds)->length = datasize;
+        }
         assert(explicitlength < 0);
 
         cd->c_data = cds->c_data;
@@ -4014,7 +4071,7 @@
     }
     else {
         sprintf(extra_text, "[%llu]", (unsigned PY_LONG_LONG)length);
-        arraysize = length * ctitem->ct_size;
+        arraysize = MUL_WRAPAROUND(length, ctitem->ct_size);
         if (length > 0 && (arraysize / length) != ctitem->ct_size) {
             PyErr_SetString(PyExc_OverflowError,
                             "array size would overflow a Py_ssize_t");
@@ -4287,7 +4344,7 @@
             /* not a bitfield: common case */
             int bs_flag;
 
-            if (ftype->ct_flags & CT_ARRAY && ftype->ct_length == 0)
+            if ((ftype->ct_flags & CT_ARRAY) && ftype->ct_length <= 0)
                 bs_flag = BS_EMPTY_ARRAY;
             else
                 bs_flag = BS_REGULAR;
@@ -5425,17 +5482,27 @@
     return PyInt_FromLong(align);
 }
 
+static Py_ssize_t direct_sizeof_cdata(CDataObject *cd)
+{
+    Py_ssize_t size;
+    if (cd->c_type->ct_flags & CT_ARRAY)
+        size = get_array_length(cd) * cd->c_type->ct_itemdescr->ct_size;
+    else {
+        size = -1;
+        if (cd->c_type->ct_flags & (CT_STRUCT | CT_UNION))
+            size = _cdata_var_byte_size(cd);
+        if (size < 0)
+            size = cd->c_type->ct_size;
+    }
+    return size;
+}
+
 static PyObject *b_sizeof(PyObject *self, PyObject *arg)
 {
     Py_ssize_t size;
 
     if (CData_Check(arg)) {
-        CDataObject *cd = (CDataObject *)arg;
-
-        if (cd->c_type->ct_flags & CT_ARRAY)
-            size = get_array_length(cd) * cd->c_type->ct_itemdescr->ct_size;
-        else
-            size = cd->c_type->ct_size;
+        size = direct_sizeof_cdata((CDataObject *)arg);
     }
     else if (CTypeDescr_Check(arg)) {
         size = ((CTypeDescrObject *)arg)->ct_size;
@@ -5516,7 +5583,7 @@
             return NULL;
         }
         res = ct->ct_itemdescr;
-        *offset = index * ct->ct_itemdescr->ct_size;
+        *offset = MUL_WRAPAROUND(index, ct->ct_itemdescr->ct_size);
         if ((*offset / ct->ct_itemdescr->ct_size) != index) {
             PyErr_SetString(PyExc_OverflowError,
                             "array offset would overflow a Py_ssize_t");
@@ -5829,6 +5896,9 @@
                                      &CData_Type, &cd, &size))
         return NULL;
 
+    if (size < 0)
+        size = _cdata_var_byte_size(cd);
+
     if (cd->c_type->ct_flags & CT_POINTER) {
         if (size < 0)
             size = cd->c_type->ct_itemdescr->ct_size;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.8.3/c/ffi_obj.c new/cffi-1.9.1/c/ffi_obj.c
--- old/cffi-1.8.3/c/ffi_obj.c  2016-09-17 12:21:34.000000000 +0200
+++ new/cffi-1.9.1/c/ffi_obj.c  2016-11-12 14:45:16.000000000 +0100
@@ -257,22 +257,20 @@
 static PyObject *ffi_sizeof(FFIObject *self, PyObject *arg)
 {
     Py_ssize_t size;
-    CTypeDescrObject *ct = _ffi_type(self, arg, ACCEPT_ALL);
-    if (ct == NULL)
-        return NULL;
-
-    size = ct->ct_size;
 
     if (CData_Check(arg)) {
-        CDataObject *cd = (CDataObject *)arg;
-        if (cd->c_type->ct_flags & CT_ARRAY)
-            size = get_array_length(cd) * cd->c_type->ct_itemdescr->ct_size;
+        size = direct_sizeof_cdata((CDataObject *)arg);
     }
-
-    if (size < 0) {
-        PyErr_Format(FFIError, "don't know the size of ctype '%s'",
-                     ct->ct_name);
-        return NULL;
+    else {
+        CTypeDescrObject *ct = _ffi_type(self, arg, ACCEPT_ALL);
+        if (ct == NULL)
+            return NULL;
+        size = ct->ct_size;
+        if (size < 0) {
+            PyErr_Format(FFIError, "don't know the size of ctype '%s'",
+                         ct->ct_name);
+            return NULL;
+        }
     }
     return PyInt_FromSsize_t(size);
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.8.3/c/file_emulator.h 
new/cffi-1.9.1/c/file_emulator.h
--- old/cffi-1.8.3/c/file_emulator.h    2016-09-17 12:21:34.000000000 +0200
+++ new/cffi-1.9.1/c/file_emulator.h    2016-11-12 14:45:16.000000000 +0100
@@ -31,7 +31,7 @@
 static FILE *PyFile_AsFile(PyObject *ob_file)
 {
     PyObject *ob, *ob_capsule = NULL, *ob_mode = NULL;
-    FILE *f = NULL;
+    FILE *f;
     int fd;
     char *mode;
 
@@ -80,7 +80,11 @@
         if (PyObject_SetAttrString(ob_file, "__cffi_FILE", ob_capsule) < 0)
             goto fail;
     }
-    return PyCapsule_GetPointer(ob_capsule, "FILE");
+    else {
+        f = PyCapsule_GetPointer(ob_capsule, "FILE");
+    }
+    Py_DECREF(ob_capsule);   /* assumes still at least one reference */
+    return f;
 
  fail:
     Py_XDECREF(ob_mode);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.8.3/c/libffi_msvc/ffi.h 
new/cffi-1.9.1/c/libffi_msvc/ffi.h
--- old/cffi-1.8.3/c/libffi_msvc/ffi.h  2016-09-17 12:21:34.000000000 +0200
+++ new/cffi-1.9.1/c/libffi_msvc/ffi.h  2016-11-12 14:45:16.000000000 +0100
@@ -231,6 +231,9 @@
                  void *user_data,
                  void *codeloc);
 
+/* AR: for cffi we need the following API, and not the _loc version */
+#define ffi_prep_closure(a,b,c,d)  ffi_prep_closure_loc(a,b,c,d,a)
+
 typedef struct {
   char tramp[FFI_TRAMPOLINE_SIZE];
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.8.3/c/misc_win32.h 
new/cffi-1.9.1/c/misc_win32.h
--- old/cffi-1.8.3/c/misc_win32.h       2016-09-17 12:21:34.000000000 +0200
+++ new/cffi-1.9.1/c/misc_win32.h       2016-11-12 14:45:16.000000000 +0100
@@ -234,8 +234,3 @@
     sprintf(buf, "error 0x%x", (unsigned int)dw);
     return buf;
 }
-
-/************************************************************/
-/* obscure */
-
-#define ffi_prep_closure(a,b,c,d)  ffi_prep_closure_loc(a,b,c,d,a)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.8.3/c/test_c.py new/cffi-1.9.1/c/test_c.py
--- old/cffi-1.8.3/c/test_c.py  2016-09-17 12:21:34.000000000 +0200
+++ new/cffi-1.9.1/c/test_c.py  2016-11-12 14:45:24.000000000 +0100
@@ -12,7 +12,7 @@
 # ____________________________________________________________
 
 import sys
-assert __version__ == "1.8.3", ("This test_c.py file is for testing a version"
+assert __version__ == "1.9.1", ("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,):
@@ -3172,17 +3172,19 @@
     assert d[1][0] == 'y'
     assert d[1][1].type is BArray
     assert d[1][1].offset == size_of_int()
-    assert d[1][1].bitshift == -1
+    assert d[1][1].bitshift == -2
     assert d[1][1].bitsize == -1
     #
     p = newp(new_pointer_type(BStruct))
     p.x = 42
     assert p.x == 42
-    assert typeof(p.y) is BIntP
+    assert typeof(p.y) is BArray
+    assert len(p.y) == 0
     assert p.y == cast(BIntP, p) + 1
     #
     p = newp(new_pointer_type(BStruct), [100])
     assert p.x == 100
+    assert len(p.y) == 0
     #
     # Tests for
     #    ffi.new("struct_with_var_array *", [field.., [the_array_items..]])
@@ -3197,6 +3199,10 @@
             p.y[0] = 200
             assert p.y[2] == 0
             p.y[2] = 400
+        assert len(p.y) == 3
+        assert len(p[0].y) == 3
+        assert len(buffer(p)) == sizeof(BInt) * 4
+        assert sizeof(p[0]) == sizeof(BInt) * 4
         plist.append(p)
     for i in range(20):
         p = plist[i]
@@ -3204,13 +3210,31 @@
         assert p.y[0] == 200
         assert p.y[1] == i
         assert p.y[2] == 400
-        assert list(p.y[0:3]) == [200, i, 400]
+        assert list(p.y) == [200, i, 400]
     #
     # the following assignment works, as it normally would, for any array field
-    p.y = [500, 600]
-    assert list(p.y[0:3]) == [500, 600, 400]
+    p.y = [501, 601]
+    assert list(p.y) == [501, 601, 400]
+    p[0].y = [500, 600]
+    assert list(p[0].y) == [500, 600, 400]
+    assert repr(p) == "<cdata 'foo *' owning %d bytes>" % (
+        sizeof(BStruct) + 3 * sizeof(BInt),)
+    assert repr(p[0]) == "<cdata 'foo' owning %d bytes>" % (
+        sizeof(BStruct) + 3 * sizeof(BInt),)
+    assert sizeof(p[0]) == sizeof(BStruct) + 3 * sizeof(BInt)
+    #
+    # from a non-owning pointer, we can't get the length
+    q = cast(new_pointer_type(BStruct), p)
+    assert q.y[0] == 500
+    assert q[0].y[0] == 500
+    py.test.raises(TypeError, len, q.y)
+    py.test.raises(TypeError, len, q[0].y)
+    assert typeof(q.y) is BIntP
+    assert typeof(q[0].y) is BIntP
+    assert sizeof(q[0]) == sizeof(BStruct)
     #
     # error cases
+    py.test.raises(IndexError, "p.y[4]")
     py.test.raises(TypeError, "p.y = cast(BIntP, 0)")
     py.test.raises(TypeError, "p.y = 15")
     py.test.raises(TypeError, "p.y = None")
@@ -3275,6 +3299,33 @@
         assert p.x[5] == 60
         assert p.x[6] == 70
 
+def test_struct_array_not_aligned():
+    # struct a { int x; char y; char z[]; };
+    # ends up of size 8, but 'z' is at offset 5
+    BChar = new_primitive_type("char")
+    BInt = new_primitive_type("int")
+    BCharP = new_pointer_type(BChar)
+    BArray = new_array_type(BCharP, None)
+    BStruct = new_struct_type("foo")
+    complete_struct_or_union(BStruct, [('x', BInt),
+                                       ('y', BChar),
+                                       ('z', BArray)])
+    assert sizeof(BStruct) == 2 * size_of_int()
+    def offsetof(BType, fieldname):
+        return typeoffsetof(BType, fieldname)[1]
+    base = offsetof(BStruct, 'z')
+    assert base == size_of_int() + 1
+    #
+    p = newp(new_pointer_type(BStruct), {'z': 3})
+    assert sizeof(p[0]) == base + 3
+    q = newp(new_pointer_type(BStruct), {'z': size_of_int()})
+    assert sizeof(q) == size_of_ptr()
+    assert sizeof(q[0]) == base + size_of_int()
+    assert len(p.z) == 3
+    assert len(p[0].z) == 3
+    assert len(q.z) == size_of_int()
+    assert len(q[0].z) == size_of_int()
+
 def test_ass_slice():
     BChar = new_primitive_type("char")
     BArray = new_array_type(new_pointer_type(BChar), None)
@@ -3700,3 +3751,5 @@
         assert len(w) == 2
         newp(new_pointer_type(BIntP), z3)    # fine
         assert len(w) == 2
+    # check that the warnings are associated with lines in this file
+    assert w[1].lineno == w[0].lineno + 4
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.8.3/cffi/__init__.py 
new/cffi-1.9.1/cffi/__init__.py
--- old/cffi-1.8.3/cffi/__init__.py     2016-09-17 12:21:34.000000000 +0200
+++ new/cffi-1.9.1/cffi/__init__.py     2016-11-12 14:45:24.000000000 +0100
@@ -4,8 +4,8 @@
 from .api import FFI, CDefError, FFIError
 from .ffiplatform import VerificationError, VerificationMissing
 
-__version__ = "1.8.3"
-__version_info__ = (1, 8, 3)
+__version__ = "1.9.1"
+__version_info__ = (1, 9, 1)
 
 # 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.8.3/cffi/_cffi_include.h 
new/cffi-1.9.1/cffi/_cffi_include.h
--- old/cffi-1.8.3/cffi/_cffi_include.h 2016-09-17 12:21:34.000000000 +0200
+++ new/cffi-1.9.1/cffi/_cffi_include.h 2016-11-12 14:45:16.000000000 +0100
@@ -141,9 +141,9 @@
 #define _cffi_to_c_char                                                  \
                  ((int(*)(PyObject *))_cffi_exports[9])
 #define _cffi_from_c_pointer                                             \
-    ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[10])
+    ((PyObject *(*)(char *, struct _cffi_ctypedescr *))_cffi_exports[10])
 #define _cffi_to_c_pointer                                               \
-    ((char *(*)(PyObject *, CTypeDescrObject *))_cffi_exports[11])
+    ((char *(*)(PyObject *, struct _cffi_ctypedescr *))_cffi_exports[11])
 #define _cffi_get_struct_layout                                          \
     not used any more
 #define _cffi_restore_errno                                              \
@@ -153,11 +153,11 @@
 #define _cffi_from_c_char                                                \
     ((PyObject *(*)(char))_cffi_exports[15])
 #define _cffi_from_c_deref                                               \
-    ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[16])
+    ((PyObject *(*)(char *, struct _cffi_ctypedescr *))_cffi_exports[16])
 #define _cffi_to_c                                                       \
-    ((int(*)(char *, CTypeDescrObject *, PyObject *))_cffi_exports[17])
+    ((int(*)(char *, struct _cffi_ctypedescr *, PyObject *))_cffi_exports[17])
 #define _cffi_from_c_struct                                              \
-    ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[18])
+    ((PyObject *(*)(char *, struct _cffi_ctypedescr *))_cffi_exports[18])
 #define _cffi_to_c_wchar_t                                               \
     ((wchar_t(*)(PyObject *))_cffi_exports[19])
 #define _cffi_from_c_wchar_t                                             \
@@ -167,21 +167,22 @@
 #define _cffi_to_c__Bool                                                 \
     ((_Bool(*)(PyObject *))_cffi_exports[22])
 #define _cffi_prepare_pointer_call_argument                              \
-    ((Py_ssize_t(*)(CTypeDescrObject *, PyObject *, char **))_cffi_exports[23])
+    ((Py_ssize_t(*)(struct _cffi_ctypedescr *,                           \
+                    PyObject *, char **))_cffi_exports[23])
 #define _cffi_convert_array_from_object                                  \
-    ((int(*)(char *, CTypeDescrObject *, PyObject *))_cffi_exports[24])
+    ((int(*)(char *, struct _cffi_ctypedescr *, PyObject *))_cffi_exports[24])
 #define _CFFI_CPIDX  25
 #define _cffi_call_python                                                \
     ((void(*)(struct _cffi_externpy_s *, char *))_cffi_exports[_CFFI_CPIDX])
 #define _CFFI_NUM_EXPORTS 26
 
-typedef struct _ctypedescr CTypeDescrObject;
+struct _cffi_ctypedescr;
 
 static void *_cffi_exports[_CFFI_NUM_EXPORTS];
 
 #define _cffi_type(index)   (                           \
     assert((((uintptr_t)_cffi_types[index]) & 1) == 0), \
-    (CTypeDescrObject *)_cffi_types[index])
+    (struct _cffi_ctypedescr *)_cffi_types[index])
 
 static PyObject *_cffi_init(const char *module_name, Py_ssize_t version,
                             const struct _cffi_type_context_s *ctx)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.8.3/cffi/_embedding.h 
new/cffi-1.9.1/cffi/_embedding.h
--- old/cffi-1.8.3/cffi/_embedding.h    2016-09-17 12:21:34.000000000 +0200
+++ new/cffi-1.9.1/cffi/_embedding.h    2016-11-12 14:45:24.000000000 +0100
@@ -233,7 +233,7 @@
         f = PySys_GetObject((char *)"stderr");
         if (f != NULL && f != Py_None) {
             PyFile_WriteString("\nFrom: " _CFFI_MODULE_NAME
-                               "\ncompiled with cffi version: 1.8.3"
+                               "\ncompiled with cffi version: 1.9.1"
                                "\n_cffi_backend module: ", f);
             modules = PyImport_GetModuleDict();
             mod = PyDict_GetItemString(modules, "_cffi_backend");
@@ -366,7 +366,7 @@
     const char *code;
 } _cffi_pypy_init = {
     _CFFI_MODULE_NAME,
-    _CFFI_PYTHON_STARTUP_FUNC,
+    (void(*)(const void *[]))_CFFI_PYTHON_STARTUP_FUNC,
     _CFFI_PYTHON_STARTUP_CODE,
 };
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.8.3/cffi/cparser.py 
new/cffi-1.9.1/cffi/cparser.py
--- old/cffi-1.8.3/cffi/cparser.py      2016-09-17 12:21:34.000000000 +0200
+++ new/cffi-1.9.1/cffi/cparser.py      2016-11-12 14:45:16.000000000 +0100
@@ -332,8 +332,10 @@
                         realtype = model.unknown_ptr_type(decl.name)
                     else:
                         realtype, quals = self._get_type_and_quals(
-                            decl.type, name=decl.name)
+                            decl.type, name=decl.name, partial_length_ok=True)
                     self._declare('typedef ' + decl.name, realtype, 
quals=quals)
+                elif decl.__class__.__name__ == 'Pragma':
+                    pass    # skip pragma, only in pycparser 2.15
                 else:
                     raise api.CDefError("unrecognized construct", decl)
         except api.FFIError as e:
@@ -781,11 +783,14 @@
                 exprnode.name in self._int_constants):
             return self._int_constants[exprnode.name]
         #
-        if partial_length_ok:
-            if (isinstance(exprnode, pycparser.c_ast.ID) and
+        if (isinstance(exprnode, pycparser.c_ast.ID) and
                     exprnode.name == '__dotdotdotarray__'):
+            if partial_length_ok:
                 self._partial_length = True
                 return '...'
+            raise api.FFIError(":%d: unsupported '[...]' here, cannot derive "
+                               "the actual array length in this context"
+                               % exprnode.coord.line)
         #
         raise api.FFIError(":%d: unsupported expression: expected a "
                            "simple numeric constant" % exprnode.coord.line)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.8.3/cffi/model.py new/cffi-1.9.1/cffi/model.py
--- old/cffi-1.8.3/cffi/model.py        2016-09-17 12:21:34.000000000 +0200
+++ new/cffi-1.9.1/cffi/model.py        2016-11-12 14:45:16.000000000 +0100
@@ -519,10 +519,18 @@
             smallest_value = min(self.enumvalues)
             largest_value = max(self.enumvalues)
         else:
-            raise api.CDefError("%r has no values explicitly defined: "
-                                "refusing to guess which integer type it is "
-                                "meant to be (unsigned/signed, int/long)"
-                % self._get_c_name())
+            import warnings
+            try:
+                # XXX!  The goal is to ensure that the warnings.warn()
+                # will not suppress the warning.  We want to get it
+                # several times if we reach this point several times.
+                __warningregistry__.clear()
+            except NameError:
+                pass
+            warnings.warn("%r has no values explicitly defined; "
+                          "guessing that it is equivalent to 'unsigned int'"
+                          % self._get_c_name())
+            smallest_value = largest_value = 0
         if smallest_value < 0:   # needs a signed type
             sign = 1
             candidate1 = PrimitiveType("int")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.8.3/cffi/recompiler.py 
new/cffi-1.9.1/cffi/recompiler.py
--- old/cffi-1.8.3/cffi/recompiler.py   2016-09-17 12:21:34.000000000 +0200
+++ new/cffi-1.9.1/cffi/recompiler.py   2016-11-12 14:45:16.000000000 +0100
@@ -587,8 +587,11 @@
     # ----------
     # typedefs
 
+    def _typedef_type(self, tp, name):
+        return self._global_type(tp, "(*(%s *)0)" % (name,))
+
     def _generate_cpy_typedef_collecttype(self, tp, name):
-        self._do_collect_type(tp)
+        self._do_collect_type(self._typedef_type(tp, name))
 
     def _generate_cpy_typedef_decl(self, tp, name):
         pass
@@ -598,6 +601,7 @@
         self._lsts["typename"].append(TypenameExpr(name, type_index))
 
     def _generate_cpy_typedef_ctx(self, tp, name):
+        tp = self._typedef_type(tp, name)
         self._typedef_ctx(tp, name)
         if getattr(tp, "origin", None) == "unknown_type":
             self._struct_ctx(tp, tp.name, approxname=None)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.8.3/cffi/setuptools_ext.py 
new/cffi-1.9.1/cffi/setuptools_ext.py
--- old/cffi-1.8.3/cffi/setuptools_ext.py       2016-09-17 12:21:34.000000000 
+0200
+++ new/cffi-1.9.1/cffi/setuptools_ext.py       2016-11-12 14:45:16.000000000 
+0100
@@ -1,4 +1,5 @@
 import os
+import sys
 
 try:
     basestring
@@ -74,8 +75,13 @@
     Add py_limited_api to kwds if setuptools >= 26 is in use.
     Do not alter the setting if it already exists.
     Setuptools takes care of ignoring the flag on Python 2 and PyPy.
+
+    CPython itself should ignore the flag in a debugging version
+    (by not listing .abi3.so in the extensions it supports), but
+    it doesn't so far, creating troubles.  That's why we check
+    for "not sys.flags.debug". (http://bugs.python.org/issue28401)
     """
-    if 'py_limited_api' not in kwds:
+    if 'py_limited_api' not in kwds and not sys.flags.debug:
         import setuptools
         try:
             setuptools_major_version = 
int(setuptools.__version__.partition('.')[0])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.8.3/cffi.egg-info/PKG-INFO 
new/cffi-1.9.1/cffi.egg-info/PKG-INFO
--- old/cffi-1.8.3/cffi.egg-info/PKG-INFO       2016-09-17 12:21:52.000000000 
+0200
+++ new/cffi-1.9.1/cffi.egg-info/PKG-INFO       2016-11-12 14:46:13.000000000 
+0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: cffi
-Version: 1.8.3
+Version: 1.9.1
 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.8.3/demo/embedding_test.c 
new/cffi-1.9.1/demo/embedding_test.c
--- old/cffi-1.8.3/demo/embedding_test.c        2016-09-17 12:21:34.000000000 
+0200
+++ new/cffi-1.9.1/demo/embedding_test.c        2016-11-12 14:45:16.000000000 
+0100
@@ -1,7 +1,31 @@
-/* Link this program with libembedding_test.so.
+/* There are two options:
+
+   =====1=====
+
+   Link this program with _embedding_test.so.
    E.g. with gcc:
 
       gcc -o embedding_test embedding_test.c _embedding_cffi*.so
+
+   You must then run the executable with the right command
+   (LD_LIBRARY_PATH on Linux), otherwise it won't find the
+   _embedding_cffi*.so:
+
+      LD_LIBRARY_PATH=. ./embedding_test
+
+   There are platform-specific options to gcc to avoid needing
+   that, too.  Linux:
+
+      gcc -o embedding_test embedding_test.c _embedding_cffi*.so  \
+          -Wl,-rpath=\$ORIGIN/
+
+   =====2=====
+
+   Compile and link the _embedding_test.c source code together with
+   this example (e.g. with PyPy):
+
+      gcc -o embedding_test embedding_test.c _embedding_cffi.c  \
+          -I/opt/pypy/include -pthread -lpypy-c
 */
 
 #include <stdio.h>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.8.3/doc/source/cdef.rst 
new/cffi-1.9.1/doc/source/cdef.rst
--- old/cffi-1.8.3/doc/source/cdef.rst  2016-09-17 12:21:34.000000000 +0200
+++ new/cffi-1.9.1/doc/source/cdef.rst  2016-11-12 14:45:16.000000000 +0100
@@ -58,7 +58,7 @@
     import cffi
 
     ffibuilder = cffi.FFI()
-    ffibuilder.set_source("package._foo", "real C code")   # <=
+    ffibuilder.set_source("package._foo", r"""real C code""")   # <=
     ffibuilder.cdef("C-like declarations with '...'")
 
     if __name__ == "__main__":
@@ -345,7 +345,9 @@
 module to generate.  In this mode, no C compiler is called.
 
 In **API mode,** the ``c_header_source`` argument is a string that
-will be pasted into the .c file generated.  This piece of C code
+will be pasted into the .c file generated.  Typically, it is specified as
+``r""" ...multiple lines of C code... """`` (the ``r`` prefix allows these
+lines to contain a literal ``\n``, for example).  This piece of C code
 typically contains some ``#include``, but may also contain more,
 like definitions for custom "wrapper" C functions.  The goal is that
 the .c file can be generated like this::
@@ -387,7 +389,7 @@
 
 .. code-block:: python
 
-    ffibuilder.set_source("mymodule", '''
+    ffibuilder.set_source("mymodule", r'''
     extern "C" {
         int somefunc(int somearg) { return real_cpp_func(somearg); }
     }
@@ -851,7 +853,7 @@
     import cffi
 
     ffi = cffi.FFI()
-    C_HEADER_SRC = '''
+    C_HEADER_SRC = r'''
         #include "somelib.h"
     '''
     C_KEYWORDS = dict(libraries=['somelib'])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.8.3/doc/source/conf.py 
new/cffi-1.9.1/doc/source/conf.py
--- old/cffi-1.8.3/doc/source/conf.py   2016-09-17 12:21:34.000000000 +0200
+++ new/cffi-1.9.1/doc/source/conf.py   2016-11-12 14:45:24.000000000 +0100
@@ -45,9 +45,9 @@
 # built documents.
 #
 # The short X.Y version.
-version = '1.8'
+version = '1.9'
 # The full version, including alpha/beta/rc tags.
-release = '1.8.3'
+release = '1.9.1'
 
 # 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.8.3/doc/source/embedding.rst 
new/cffi-1.9.1/doc/source/embedding.rst
--- old/cffi-1.8.3/doc/source/embedding.rst     2016-09-17 12:21:34.000000000 
+0200
+++ new/cffi-1.9.1/doc/source/embedding.rst     2016-11-12 14:45:16.000000000 
+0100
@@ -56,7 +56,7 @@
     with open('plugin.h') as f:
         ffibuilder.embedding_api(f.read())
 
-    ffibuilder.set_source("my_plugin", '''
+    ffibuilder.set_source("my_plugin", r'''
         #include "plugin.h"
     ''')
 
@@ -211,7 +211,9 @@
   As in the example above, you can also use the same ``foo.h`` from
   ``ffibuilder.set_source()``::
 
-      ffibuilder.set_source('module_name', '#include "foo.h"')
+      ffibuilder.set_source('module_name', r'''
+          #include "foo.h"
+      ''')
 
 
 .. __: using.html#working
@@ -404,7 +406,7 @@
         extern "Python" int mycb(int);
     """)
 
-    ffibuilder.set_source("my_plugin", """
+    ffibuilder.set_source("my_plugin", r"""
 
         static int mycb(int);   /* the callback: forward declaration, to make
                                    it accessible from the C code that follows 
*/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.8.3/doc/source/installation.rst 
new/cffi-1.9.1/doc/source/installation.rst
--- old/cffi-1.8.3/doc/source/installation.rst  2016-09-17 12:21:34.000000000 
+0200
+++ new/cffi-1.9.1/doc/source/installation.rst  2016-11-12 14:45:24.000000000 
+0100
@@ -51,7 +51,7 @@
 
 Download and Installation:
 
-* http://pypi.python.org/packages/source/c/cffi/cffi-1.8.3.tar.gz
+* http://pypi.python.org/packages/source/c/cffi/cffi-1.9.1.tar.gz
 
    - MD5: ...
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.8.3/doc/source/overview.rst 
new/cffi-1.9.1/doc/source/overview.rst
--- old/cffi-1.8.3/doc/source/overview.rst      2016-09-17 12:21:34.000000000 
+0200
+++ new/cffi-1.9.1/doc/source/overview.rst      2016-11-12 14:45:16.000000000 
+0100
@@ -72,7 +72,7 @@
     ffibuilder = FFI()
 
     ffibuilder.set_source("_example",
-        """ // passed to the real C compiler
+       r""" // passed to the real C compiler
             #include <sys/types.h>
             #include <pwd.h>
         """,
@@ -195,7 +195,7 @@
     ffibuilder.cdef("int foo(int *, int *, int);")
 
     ffibuilder.set_source("_example",
-    """
+    r"""
         static int foo(int *buffer_in, int *buffer_out, int x)
         {
             /* some algorithm that is seriously faster in C than in Python */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.8.3/doc/source/ref.rst 
new/cffi-1.9.1/doc/source/ref.rst
--- old/cffi-1.8.3/doc/source/ref.rst   2016-09-17 12:21:34.000000000 +0200
+++ new/cffi-1.9.1/doc/source/ref.rst   2016-11-12 14:45:16.000000000 +0100
@@ -141,7 +141,8 @@
    into a struct over a socket, rewriting the contents of mystruct[0]
 
 Remember that like in C, you can use ``array + index`` to get the pointer
-to the index'th item of an array.
+to the index'th item of an array.  (In C you might more naturally write
+``&array[index]``, but that is equivalent.)
 
 The returned object is not a built-in buffer nor memoryview object,
 because these objects' API changes too much across Python versions.
@@ -255,6 +256,16 @@
 argument in bytes.  The argument can be either a C type, or a cdata object,
 like in the equivalent ``sizeof`` operator in C.
 
+For ``array = ffi.new("T[]", n)``, then ``ffi.sizeof(array)`` returns
+``n * ffi.sizeof("T")``.  *New in version 1.9:* Similar rules apply for
+structures with aa variable-sized array at the end.  More precisely, if
+``p`` was returned by ``ffi.new("struct foo *", ...)``, then
+``ffi.sizeof(p[0])`` now returns the total allocated size.  In previous
+versions, it used to just return ``ffi.sizeof(ffi.typeof(p[0]))``, which
+is the size of the structure ignoring the variable-sized part.  (Note
+that due to alignment, it is possible for ``ffi.sizeof(p[0])`` to return
+a value smaller than ``ffi.sizeof(ffi.typeof(p[0]))``.)
+
 **ffi.alignof("C type")**: return the natural alignment size in bytes of
 the argument.  Corresponds to the ``__alignof__`` operator in GCC.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.8.3/doc/source/using.rst 
new/cffi-1.9.1/doc/source/using.rst
--- old/cffi-1.8.3/doc/source/using.rst 2016-09-17 12:21:34.000000000 +0200
+++ new/cffi-1.9.1/doc/source/using.rst 2016-11-12 14:45:16.000000000 +0100
@@ -479,7 +479,7 @@
 
         void library_function(int(*callback)(int, int));
     """)
-    ffibuilder.set_source("_my_example", """
+    ffibuilder.set_source("_my_example", r"""
         #include <some_library.h>
     """)
 
@@ -546,7 +546,7 @@
 
         extern "Python" void my_event_callback(event_t *, void *);
     """)
-    ffibuilder.set_source("_demo_cffi", """
+    ffibuilder.set_source("_demo_cffi", r"""
         #include <the_event_library.h>
     """)
 
@@ -613,7 +613,7 @@
 
 ::
 
-    ffibuilder.set_source("_demo_cffi", """
+    ffibuilder.set_source("_demo_cffi", r"""
         #include <the_event_library.h>
 
         static void my_event_callback(widget_t *, event_t *);
@@ -629,7 +629,7 @@
         extern "Python" int f(int);
         int my_algo(int);
     """)
-    ffibuilder.set_source("_example_cffi", """
+    ffibuilder.set_source("_example_cffi", r"""
         static int f(int);   /* the forward declaration */
 
         static int my_algo(int n) {
@@ -673,7 +673,7 @@
     ffibuilder.cdef("""
         extern "Python+C" int f(int);      /* not static */
     """)
-    ffibuilder.set_source("_example_cffi", """
+    ffibuilder.set_source("_example_cffi", r"""
         /* the forward declaration, setting a gcc attribute
            (this line could also be in some .h file, to be included
            both here and in the other C files of the project) */
@@ -834,7 +834,7 @@
         int (*python_callback)(int how_many, int *values);
         void *const c_callback;   /* pass this const ptr to C routines */
     """)
-    ffibuilder.set_source("_example", """
+    ffibuilder.set_source("_example", r"""
         #include <stdarg.h>
         #include <alloca.h>
         static int (*python_callback)(int how_many, int *values);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.8.3/doc/source/whatsnew.rst 
new/cffi-1.9.1/doc/source/whatsnew.rst
--- old/cffi-1.8.3/doc/source/whatsnew.rst      2016-09-17 12:21:34.000000000 
+0200
+++ new/cffi-1.9.1/doc/source/whatsnew.rst      2016-11-12 14:45:16.000000000 
+0100
@@ -3,6 +3,41 @@
 ======================
 
 
+v1.9
+====
+
+* Structs with variable-sized arrays as their last field: now we track
+  the length of the array after ``ffi.new()`` is called, just like we
+  always tracked the length of ``ffi.new("int[]", 42)``.  This lets us
+  detect out-of-range accesses to array items.  This also lets us
+  display a better ``repr()``, and have the total size returned by
+  ``ffi.sizeof()`` and ``ffi.buffer()``.  Previously both functions
+  would return a result based on the size of the declared structure
+  type, with an assumed empty array.  (Thanks andrew for starting this
+  refactoring.)
+
+* Add support in ``cdef()/set_source()`` for unspecified-length arrays
+  in typedefs: ``typedef int foo_t[...];``.  It was already supported
+  for global variables or structure fields.
+
+* I turned in v1.8 a warning from ``cffi/model.py`` into an error:
+  ``'enum xxx' has no values explicitly defined: refusing to guess which
+  integer type it is meant to be (unsigned/signed, int/long)``.  Now I'm
+  turning it back to a warning again; it seems that guessing that the
+  enum has size ``int`` is a 99%-safe bet.  (But not 100%, so it stays
+  as a warning.)
+
+* Fix leaks in the code handling ``FILE *`` arguments.  In CPython 3
+  there is a remaining issue that is hard to fix: if you pass a Python
+  file object to a ``FILE *`` argument, then ``os.dup()`` is used and
+  the new file descriptor is only closed when the GC reclaims the Python
+  file object---and not at the earlier time when you call ``close()``,
+  which only closes the original file descriptor.  If this is an issue,
+  you should avoid this automatic convertion of Python file objects:
+  instead, explicitly manipulate file descriptors and call ``fdopen()``
+  from C (...via cffi).
+
+
 v1.8.3
 ======
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.8.3/setup.py new/cffi-1.9.1/setup.py
--- old/cffi-1.8.3/setup.py     2016-09-17 12:21:34.000000000 +0200
+++ new/cffi-1.9.1/setup.py     2016-11-12 14:45:24.000000000 +0100
@@ -51,12 +51,17 @@
     see http://stackoverflow.com/questions/22313407/ .)\n""")
     sys.exit(1)
 
-def ask_supports_thread():
+def get_config():
     from distutils.core import Distribution
     from distutils.sysconfig import get_config_vars
     get_config_vars()      # workaround for a bug of distutils, e.g. on OS/X
     config = Distribution().get_command_obj('config')
-    ok = config.try_compile('__thread int some_threadlocal_variable_42;')
+    return config
+
+def ask_supports_thread():
+    config = get_config()
+    ok = (sys.platform != 'win32' and
+          config.try_compile('__thread int some_threadlocal_variable_42;'))
     if ok:
         define_macros.append(('USE__THREAD', None))
     else:
@@ -66,6 +71,10 @@
         sys.stderr.write("Note: will not use '__thread' in the C code\n")
         sys.stderr.write("The above error message can be safely ignored\n")
 
+def uses_msvc():
+    config = get_config()
+    return config.try_compile('#ifndef _MSC_VER\n#error "not MSVC"\n#endif')
+
 def use_pkg_config():
     if sys.platform == 'darwin' and os.path.exists('/usr/local/bin/brew'):
         use_homebrew_for_libffi()
@@ -86,7 +95,7 @@
         os.environ.get('PKG_CONFIG_PATH', '') + ':' + pkgconfig)
 
 
-if sys.platform == 'win32':
+if sys.platform == 'win32' and uses_msvc():
     COMPILE_LIBFFI = 'c/libffi_msvc'    # from the CPython distribution
 else:
     COMPILE_LIBFFI = None
@@ -144,7 +153,7 @@
 
 `Mailing list <https://groups.google.com/forum/#!forum/python-cffi>`_
 """,
-        version='1.8.3',
+        version='1.9.1',
         packages=['cffi'] if cpython else [],
         package_data={'cffi': ['_cffi_include.h', 'parse_c_type.h', 
                                '_embedding.h']}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.8.3/testing/cffi0/backend_tests.py 
new/cffi-1.9.1/testing/cffi0/backend_tests.py
--- old/cffi-1.8.3/testing/cffi0/backend_tests.py       2016-09-17 
12:21:34.000000000 +0200
+++ new/cffi-1.9.1/testing/cffi0/backend_tests.py       2016-11-12 
14:45:16.000000000 +0100
@@ -1355,15 +1355,15 @@
         assert ffi.getctype("e1*") == 'e1 *'
 
     def test_opaque_enum(self):
+        import warnings
         ffi = FFI(backend=self.Backend())
         ffi.cdef("enum foo;")
-        from cffi import __version_info__
-        if __version_info__ < (1, 8):
-            py.test.skip("re-enable me in version 1.8")
-        e = py.test.raises(CDefError, ffi.cast, "enum foo", -1)
-        assert str(e.value) == (
-            "'enum foo' has no values explicitly defined: refusing to guess "
-            "which integer type it is meant to be (unsigned/signed, int/long)")
+        with warnings.catch_warnings(record=True) as log:
+            n = ffi.cast("enum foo", -1)
+            assert int(n) == 0xffffffff
+        assert str(log[0].message) == (
+            "'enum foo' has no values explicitly defined; "
+            "guessing that it is equivalent to 'unsigned int'")
 
     def test_new_ctype(self):
         ffi = FFI(backend=self.Backend())
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.8.3/testing/cffi0/test_ffi_backend.py 
new/cffi-1.9.1/testing/cffi0/test_ffi_backend.py
--- old/cffi-1.8.3/testing/cffi0/test_ffi_backend.py    2016-09-17 
12:21:34.000000000 +0200
+++ new/cffi-1.9.1/testing/cffi0/test_ffi_backend.py    2016-11-12 
14:45:16.000000000 +0100
@@ -282,10 +282,20 @@
         ffi.cdef("struct foo_s { int x; int a[]; };")
         p = ffi.new("struct foo_s *", [100, [200, 300, 400]])
         assert p.x == 100
-        assert ffi.typeof(p.a) is ffi.typeof("int *")   # no length available
+        assert ffi.typeof(p.a) is ffi.typeof("int[]")
+        assert len(p.a) == 3                            # length recorded
         assert p.a[0] == 200
         assert p.a[1] == 300
         assert p.a[2] == 400
+        assert list(p.a) == [200, 300, 400]
+        q = ffi.cast("struct foo_s *", p)
+        assert q.x == 100
+        assert ffi.typeof(q.a) is ffi.typeof("int *")   # no length recorded
+        py.test.raises(TypeError, len, q.a)
+        assert q.a[0] == 200
+        assert q.a[1] == 300
+        assert q.a[2] == 400
+        py.test.raises(TypeError, list, q.a)
 
     @pytest.mark.skipif("sys.platform != 'win32'")
     def test_getwinerror(self):
@@ -479,3 +489,7 @@
         assert ffi.unpack(p+1, 7) == b"bc\x00def\x00"
         p = ffi.new("int[]", [-123456789])
         assert ffi.unpack(p, 1) == [-123456789]
+
+    def test_negative_array_size(self):
+        ffi = FFI()
+        py.test.raises(ValueError, ffi.cast, "int[-5]", 0)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.8.3/testing/cffi0/test_verify.py 
new/cffi-1.9.1/testing/cffi0/test_verify.py
--- old/cffi-1.8.3/testing/cffi0/test_verify.py 2016-09-17 12:21:34.000000000 
+0200
+++ new/cffi-1.9.1/testing/cffi0/test_verify.py 2016-11-12 14:45:16.000000000 
+0100
@@ -561,7 +561,8 @@
                      "int bar(struct foo_s *f) { return f->a[14]; }\n")
     assert ffi.sizeof('struct foo_s') == 19 * ffi.sizeof('int')
     s = ffi.new("struct foo_s *")
-    assert ffi.typeof(s.a) is ffi.typeof('int *')   # because no length
+    assert ffi.typeof(s.a) is ffi.typeof('int[]')   # implicit max length
+    assert len(s.a) == 18  # max length, computed from the size and start 
offset
     s.a[14] = 4242
     assert lib.bar(s) == 4242
     # with no declared length, out-of-bound accesses are not detected
@@ -591,10 +592,15 @@
     ffi.verify("struct foo_s { int x; int a[]; };")
     assert ffi.sizeof('struct foo_s') == 1 * ffi.sizeof('int')
     s = ffi.new("struct foo_s *", [424242, 4])
-    assert ffi.sizeof(s[0]) == 1 * ffi.sizeof('int')   # the same in C
+    assert ffi.sizeof(ffi.typeof(s[0])) == 1 * ffi.sizeof('int')
+    assert ffi.sizeof(s[0]) == 5 * ffi.sizeof('int')
+    # ^^^ explanation: if you write in C: "char x[5];", then
+    # "sizeof(x)" will evaluate to 5.  The behavior above is
+    # a generalization of that to "struct foo_s[len(a)=5] x;"
+    # if you could do that in C.
     assert s.a[3] == 0
     s = ffi.new("struct foo_s *", [424242, [-40, -30, -20, -10]])
-    assert ffi.sizeof(s[0]) == 1 * ffi.sizeof('int')
+    assert ffi.sizeof(s[0]) == 5 * ffi.sizeof('int')
     assert s.a[3] == -10
     s = ffi.new("struct foo_s *")
     assert ffi.sizeof(s[0]) == 1 * ffi.sizeof('int')
@@ -609,10 +615,10 @@
     ffi.verify("struct foo_s { int x, y; int a[]; };")
     assert ffi.sizeof('struct foo_s') == 2 * ffi.sizeof('int')
     s = ffi.new("struct foo_s *", [424242, 4])
-    assert ffi.sizeof(s[0]) == 2 * ffi.sizeof('int')
+    assert ffi.sizeof(s[0]) == 6 * ffi.sizeof('int')
     assert s.a[3] == 0
     s = ffi.new("struct foo_s *", [424242, [-40, -30, -20, -10]])
-    assert ffi.sizeof(s[0]) == 2 * ffi.sizeof('int')
+    assert ffi.sizeof(s[0]) == 6 * ffi.sizeof('int')
     assert s.a[3] == -10
     s = ffi.new("struct foo_s *")
     assert ffi.sizeof(s[0]) == 2 * ffi.sizeof('int')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.8.3/testing/cffi1/test_ffi_obj.py 
new/cffi-1.9.1/testing/cffi1/test_ffi_obj.py
--- old/cffi-1.8.3/testing/cffi1/test_ffi_obj.py        2016-09-17 
12:21:34.000000000 +0200
+++ new/cffi-1.9.1/testing/cffi1/test_ffi_obj.py        2016-11-12 
14:45:16.000000000 +0100
@@ -502,3 +502,7 @@
     assert ffi.unpack(p+1, 7) == b"bc\x00def\x00"
     p = ffi.new("int[]", [-123456789])
     assert ffi.unpack(p, 1) == [-123456789]
+
+def test_negative_array_size():
+    ffi = _cffi1_backend.FFI()
+    py.test.raises(ffi.error, ffi.cast, "int[-5]", 0)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.8.3/testing/cffi1/test_new_ffi_1.py 
new/cffi-1.9.1/testing/cffi1/test_new_ffi_1.py
--- old/cffi-1.8.3/testing/cffi1/test_new_ffi_1.py      2016-09-17 
12:21:34.000000000 +0200
+++ new/cffi-1.9.1/testing/cffi1/test_new_ffi_1.py      2016-11-12 
14:45:16.000000000 +0100
@@ -1633,10 +1633,19 @@
         # struct array_no_length { int x; int a[]; };
         p = ffi.new("struct array_no_length *", [100, [200, 300, 400]])
         assert p.x == 100
-        assert ffi.typeof(p.a) is ffi.typeof("int *")   # no length available
+        assert ffi.typeof(p.a) is ffi.typeof("int[]")   # length available
         assert p.a[0] == 200
         assert p.a[1] == 300
         assert p.a[2] == 400
+        assert len(p.a) == 3
+        assert list(p.a) == [200, 300, 400]
+        q = ffi.cast("struct array_no_length *", p)
+        assert ffi.typeof(q.a) is ffi.typeof("int *")   # no length available
+        assert q.a[0] == 200
+        assert q.a[1] == 300
+        assert q.a[2] == 400
+        py.test.raises(TypeError, len, q.a)
+        py.test.raises(TypeError, list, q.a)
 
     def test_from_buffer(self):
         import array
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.8.3/testing/cffi1/test_recompiler.py 
new/cffi-1.9.1/testing/cffi1/test_recompiler.py
--- old/cffi-1.8.3/testing/cffi1/test_recompiler.py     2016-09-17 
12:21:34.000000000 +0200
+++ new/cffi-1.9.1/testing/cffi1/test_recompiler.py     2016-11-12 
14:45:16.000000000 +0100
@@ -399,11 +399,14 @@
         pass    # ok, fail during compilation already (e.g. C++)
     else:
         assert ffi.sizeof("struct foo_s") == 24  # found by the actual C code
-        p = ffi.new("struct foo_s *")
-        # lazily build the fields and boom:
-        e = py.test.raises(ffi.error, "p.a")
-        assert str(e.value).startswith("struct foo_s: wrong size for field 'a' 
"
-                                       "(cdef says 20, but C compiler says 
24)")
+        try:
+            # lazily build the fields and boom:
+            p = ffi.new("struct foo_s *")
+            p.a
+            assert False, "should have raised"
+        except ffi.error as e:
+            assert str(e).startswith("struct foo_s: wrong size for field 'a' "
+                                     "(cdef says 20, but C compiler says 24)")
 
 def test_open_array_in_struct():
     ffi = FFI()
@@ -411,8 +414,10 @@
     verify(ffi, 'test_open_array_in_struct',
            "struct foo_s { int b; int a[]; };")
     assert ffi.sizeof("struct foo_s") == 4
-    p = ffi.new("struct foo_s *", [5, [10, 20, 30]])
+    p = ffi.new("struct foo_s *", [5, [10, 20, 30, 40]])
     assert p.a[2] == 30
+    assert ffi.sizeof(p) == ffi.sizeof("void *")
+    assert ffi.sizeof(p[0]) == 5 * ffi.sizeof("int")
 
 def test_math_sin_type():
     ffi = FFI()
@@ -998,6 +1003,7 @@
                  "struct foo_s { int x; int a[5][8]; int y; };")
     assert ffi.sizeof('struct foo_s') == 42 * ffi.sizeof('int')
     s = ffi.new("struct foo_s *")
+    assert ffi.typeof(s.a) == ffi.typeof("int[5][8]")
     assert ffi.sizeof(s.a) == 40 * ffi.sizeof('int')
     assert s.a[4][7] == 0
     py.test.raises(IndexError, 's.a[4][8]')
@@ -1012,7 +1018,7 @@
                  "struct foo_s { int x; int a[5][7]; int y; };")
     assert ffi.sizeof('struct foo_s') == 37 * ffi.sizeof('int')
     s = ffi.new("struct foo_s *")
-    assert ffi.typeof(s.a) == ffi.typeof("int(*)[7]")
+    assert ffi.typeof(s.a) == ffi.typeof("int[][7]")
     assert s.a[4][6] == 0
     py.test.raises(IndexError, 's.a[4][7]')
     assert ffi.typeof(s.a[0]) == ffi.typeof("int[7]")
@@ -1980,3 +1986,29 @@
         static struct aaa f1(int x) { struct aaa s = {0}; s.a = x; return s; }
     """)
     assert lib.f1(52).a == 52
+
+def test_typedef_array_dotdotdot():
+    ffi = FFI()
+    ffi.cdef("""
+        typedef int foo_t[...], bar_t[...];
+        int gv[...];
+        typedef int mat_t[...][...];
+        typedef int vmat_t[][...];
+        """)
+    lib = verify(ffi, "test_typedef_array_dotdotdot", """
+        typedef int foo_t[50], bar_t[50];
+        int gv[23];
+        typedef int mat_t[6][7];
+        typedef int vmat_t[][8];
+    """)
+    assert ffi.sizeof("foo_t") == 50 * ffi.sizeof("int")
+    assert ffi.sizeof("bar_t") == 50 * ffi.sizeof("int")
+    assert len(ffi.new("foo_t")) == 50
+    assert len(ffi.new("bar_t")) == 50
+    assert ffi.sizeof(lib.gv) == 23 * ffi.sizeof("int")
+    assert ffi.sizeof("mat_t") == 6 * 7 * ffi.sizeof("int")
+    assert len(ffi.new("mat_t")) == 6
+    assert len(ffi.new("mat_t")[3]) == 7
+    py.test.raises(ffi.error, ffi.sizeof, "vmat_t")
+    p = ffi.new("vmat_t", 4)
+    assert ffi.sizeof(p[3]) == 8 * ffi.sizeof("int")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cffi-1.8.3/testing/cffi1/test_verify1.py 
new/cffi-1.9.1/testing/cffi1/test_verify1.py
--- old/cffi-1.8.3/testing/cffi1/test_verify1.py        2016-09-17 
12:21:34.000000000 +0200
+++ new/cffi-1.9.1/testing/cffi1/test_verify1.py        2016-11-12 
14:45:16.000000000 +0100
@@ -546,7 +546,8 @@
                      "int bar(struct foo_s *f) { return f->a[14]; }\n")
     assert ffi.sizeof('struct foo_s') == 19 * ffi.sizeof('int')
     s = ffi.new("struct foo_s *")
-    assert ffi.typeof(s.a) is ffi.typeof('int *')   # because no length
+    assert ffi.typeof(s.a) is ffi.typeof('int[]')   # implicit max length
+    assert len(s.a) == 18  # max length, computed from the size and start 
offset
     s.a[14] = 4242
     assert lib.bar(s) == 4242
     # with no declared length, out-of-bound accesses are not detected
@@ -576,10 +577,15 @@
     ffi.verify("struct foo_s { int x; int a[]; };")
     assert ffi.sizeof('struct foo_s') == 1 * ffi.sizeof('int')
     s = ffi.new("struct foo_s *", [424242, 4])
-    assert ffi.sizeof(s[0]) == 1 * ffi.sizeof('int')   # the same in C
+    assert ffi.sizeof(ffi.typeof(s[0])) == 1 * ffi.sizeof('int')
+    assert ffi.sizeof(s[0]) == 5 * ffi.sizeof('int')
+    # ^^^ explanation: if you write in C: "char x[5];", then
+    # "sizeof(x)" will evaluate to 5.  The behavior above is
+    # a generalization of that to "struct foo_s[len(a)=5] x;"
+    # if you could do that in C.
     assert s.a[3] == 0
     s = ffi.new("struct foo_s *", [424242, [-40, -30, -20, -10]])
-    assert ffi.sizeof(s[0]) == 1 * ffi.sizeof('int')
+    assert ffi.sizeof(s[0]) == 5 * ffi.sizeof('int')
     assert s.a[3] == -10
     s = ffi.new("struct foo_s *")
     assert ffi.sizeof(s[0]) == 1 * ffi.sizeof('int')
@@ -594,10 +600,10 @@
     ffi.verify("struct foo_s { int x, y; int a[]; };")
     assert ffi.sizeof('struct foo_s') == 2 * ffi.sizeof('int')
     s = ffi.new("struct foo_s *", [424242, 4])
-    assert ffi.sizeof(s[0]) == 2 * ffi.sizeof('int')
+    assert ffi.sizeof(s[0]) == 6 * ffi.sizeof('int')
     assert s.a[3] == 0
     s = ffi.new("struct foo_s *", [424242, [-40, -30, -20, -10]])
-    assert ffi.sizeof(s[0]) == 2 * ffi.sizeof('int')
+    assert ffi.sizeof(s[0]) == 6 * ffi.sizeof('int')
     assert s.a[3] == -10
     s = ffi.new("struct foo_s *")
     assert ffi.sizeof(s[0]) == 2 * ffi.sizeof('int')


Reply via email to