From 52e4027dc033892cc1fce6fce62dde02b64eb4f1 Mon Sep 17 00:00:00 2001
From: Armin Rigo <arigo@tunes.org>
Date: Fri, 25 Dec 2015 17:12:46 +0200
Subject: workaround a gcc 5.3.x bug by clarifying cffi_allocator_t

Bug-cffi: https://bitbucket.org/cffi/cffi/issues/240/cffi-crash-on-debian-unstable-with-gcc-5
Bug-gcc: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69037
Origin: upstream, https://bitbucket.org/cffi/cffi/commits/f52d1e25624c8fcdd70088b53db91a3e27bc8f23
Patch-Name: workaround-gcc-69037
---
 c/_cffi_backend.c | 24 ++++++++++++------------
 c/ffi_obj.c       | 38 ++++++++++++++++----------------------
 2 files changed, 28 insertions(+), 34 deletions(-)

diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
index b4a1cd7..de36145 100644
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -279,8 +279,11 @@ typedef struct {
 # include "wchar_helper.h"
 #endif
 
-typedef PyObject *const cffi_allocator_t[3];
-static cffi_allocator_t default_allocator = { NULL, NULL, NULL };
+typedef struct _cffi_allocator_s {
+    PyObject *ca_alloc, *ca_free;
+    int ca_dont_clear;
+} cffi_allocator_t;
+static const cffi_allocator_t default_allocator = { NULL, NULL, 0 };
 static PyObject *FFIError;
 static PyObject *unique_cache;
 
@@ -3019,21 +3022,18 @@ static CDataObject *allocate_gcp_object(CDataObject *origobj,
 static CDataObject *allocate_with_allocator(Py_ssize_t basesize,
                                             Py_ssize_t datasize,
                                             CTypeDescrObject *ct,
-                                            cffi_allocator_t allocator)
+                                            const cffi_allocator_t *allocator)
 {
     CDataObject *cd;
-    PyObject *my_alloc = allocator[0];
-    PyObject *my_free = allocator[1];
-    PyObject *dont_clear_after_alloc = allocator[2];
 
-    if (my_alloc == NULL) {   /* alloc */
+    if (allocator->ca_alloc == NULL) {
         cd = allocate_owning_object(basesize + datasize, ct);
         if (cd == NULL)
             return NULL;
         cd->c_data = ((char *)cd) + basesize;
     }
     else {
-        PyObject *res = PyObject_CallFunction(my_alloc, "n", datasize);
+        PyObject *res = PyObject_CallFunction(allocator->ca_alloc, "n", datasize);
         if (res == NULL)
             return NULL;
 
@@ -3058,16 +3058,16 @@ static CDataObject *allocate_with_allocator(Py_ssize_t basesize,
             return NULL;
         }
 
-        cd = allocate_gcp_object(cd, ct, my_free);
+        cd = allocate_gcp_object(cd, ct, allocator->ca_free);
         Py_DECREF(res);
     }
-    if (dont_clear_after_alloc == NULL)
+    if (!allocator->ca_dont_clear)
         memset(cd->c_data, 0, datasize);
     return cd;
 }
 
 static PyObject *direct_newp(CTypeDescrObject *ct, PyObject *init,
-                             cffi_allocator_t allocator)
+                             const cffi_allocator_t *allocator)
 {
     CTypeDescrObject *ctitem;
     CDataObject *cd;
@@ -3172,7 +3172,7 @@ static PyObject *b_newp(PyObject *self, PyObject *args)
     PyObject *init = Py_None;
     if (!PyArg_ParseTuple(args, "O!|O:newp", &CTypeDescr_Type, &ct, &init))
         return NULL;
-    return direct_newp(ct, init, default_allocator);
+    return direct_newp(ct, init, &default_allocator);
 }
 
 static int
diff --git a/c/ffi_obj.c b/c/ffi_obj.c
index 1b01d1c..fa62142 100644
--- a/c/ffi_obj.c
+++ b/c/ffi_obj.c
@@ -335,7 +335,7 @@ PyDoc_STRVAR(ffi_new_doc,
 "pointer to the memory somewhere else, e.g. into another structure.");
 
 static PyObject *_ffi_new(FFIObject *self, PyObject *args, PyObject *kwds,
-                          cffi_allocator_t allocator)
+                          const cffi_allocator_t *allocator)
 {
     CTypeDescrObject *ct;
     PyObject *arg, *init = Py_None;
@@ -353,15 +353,22 @@ static PyObject *_ffi_new(FFIObject *self, PyObject *args, PyObject *kwds,
 
 static PyObject *ffi_new(FFIObject *self, PyObject *args, PyObject *kwds)
 {
-    return _ffi_new(self, args, kwds, default_allocator);
+    return _ffi_new(self, args, kwds, &default_allocator);
 }
 
 static PyObject *_ffi_new_with_allocator(PyObject *allocator, PyObject *args,
                                          PyObject *kwds)
 {
+    cffi_allocator_t alloc1;
+    PyObject *my_alloc, *my_free;
+    my_alloc = PyTuple_GET_ITEM(allocator, 1);
+    my_free  = PyTuple_GET_ITEM(allocator, 2);
+    alloc1.ca_alloc = (my_alloc == Py_None ? NULL : my_alloc);
+    alloc1.ca_free  = (my_free  == Py_None ? NULL : my_free);
+    alloc1.ca_dont_clear = (PyTuple_GET_ITEM(allocator, 3) == Py_False);
+
     return _ffi_new((FFIObject *)PyTuple_GET_ITEM(allocator, 0),
-                    args, kwds,
-                    &PyTuple_GET_ITEM(allocator, 1));
+                    args, kwds, &alloc1);
 }
 
 PyDoc_STRVAR(ffi_new_allocator_doc,
@@ -396,27 +403,14 @@ static PyObject *ffi_new_allocator(FFIObject *self, PyObject *args,
         return NULL;
     }
 
-    allocator = PyTuple_New(4);
+    allocator = PyTuple_Pack(4,
+                             (PyObject *)self,
+                             my_alloc,
+                             my_free,
+                             PyBool_FromLong(should_clear_after_alloc));
     if (allocator == NULL)
         return NULL;
 
-    Py_INCREF(self);
-    PyTuple_SET_ITEM(allocator, 0, (PyObject *)self);
-
-    if (my_alloc != Py_None) {
-        Py_INCREF(my_alloc);
-        PyTuple_SET_ITEM(allocator, 1, my_alloc);
-    }
-    if (my_free != Py_None) {
-        Py_INCREF(my_free);
-        PyTuple_SET_ITEM(allocator, 2, my_free);
-    }
-    if (!should_clear_after_alloc) {
-        PyObject *my_true = Py_True;
-        Py_INCREF(my_true);
-        PyTuple_SET_ITEM(allocator, 3, my_true);  /* dont_clear_after_alloc */
-    }
-
     {
         static PyMethodDef md = {"allocator",
                                  (PyCFunction)_ffi_new_with_allocator,
