summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--c/_cffi_backend.c144
-rw-r--r--c/ffi_obj.c2
-rw-r--r--c/test_c.py62
-rw-r--r--cffi/__init__.py4
-rw-r--r--cffi/_embedding.h2
-rw-r--r--cffi/recompiler.py18
-rw-r--r--cffi/verifier.py3
-rw-r--r--doc/source/conf.py2
-rw-r--r--doc/source/installation.rst8
-rw-r--r--doc/source/whatsnew.rst18
-rw-r--r--setup.py6
-rw-r--r--setup_base.py1
-rw-r--r--testing/cffi0/test_ffi_backend.py1
-rw-r--r--testing/cffi0/test_version.py7
-rw-r--r--testing/cffi1/test_re_python.py5
15 files changed, 226 insertions, 57 deletions
diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
index 440be7e..208f933 100644
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -2,7 +2,7 @@
#include <Python.h>
#include "structmember.h"
-#define CFFI_VERSION "1.14.3"
+#define CFFI_VERSION "1.14.5"
#ifdef MS_WIN32
#include <windows.h>
@@ -147,32 +147,42 @@ typedef unsigned long long int uintmax_t;
* should not be open to the fork() bug.
*
* This is also used on macOS, provided we are executing on macOS 10.15 or
- * above.
+ * above. It's a mess because it needs runtime checks in that case.
*/
#ifdef __NetBSD__
# define CFFI_CHECK_FFI_CLOSURE_ALLOC 1
+# define CFFI_CHECK_FFI_CLOSURE_ALLOC_MAYBE 1
# define CFFI_CHECK_FFI_PREP_CLOSURE_LOC 1
+# define CFFI_CHECK_FFI_PREP_CLOSURE_LOC_MAYBE 1
# define CFFI_CHECK_FFI_PREP_CIF_VAR 0
+# define CFFI_CHECK_FFI_PREP_CIF_VAR_MAYBE 0
#elif defined(__APPLE__) && defined(FFI_AVAILABLE_APPLE)
# define CFFI_CHECK_FFI_CLOSURE_ALLOC __builtin_available(macos 10.15, ios 13, watchos 6, tvos 13, *)
+# define CFFI_CHECK_FFI_CLOSURE_ALLOC_MAYBE 1
# define CFFI_CHECK_FFI_PREP_CLOSURE_LOC __builtin_available(macos 10.15, ios 13, watchos 6, tvos 13, *)
+# define CFFI_CHECK_FFI_PREP_CLOSURE_LOC_MAYBE 1
# define CFFI_CHECK_FFI_PREP_CIF_VAR __builtin_available(macos 10.15, ios 13, watchos 6, tvos 13, *)
-
-# include "malloc_closure.h"
+# define CFFI_CHECK_FFI_PREP_CIF_VAR_MAYBE 1
#else
# define CFFI_CHECK_FFI_CLOSURE_ALLOC 0
+# define CFFI_CHECK_FFI_CLOSURE_ALLOC_MAYBE 0
# define CFFI_CHECK_FFI_PREP_CLOSURE_LOC 0
+# define CFFI_CHECK_FFI_PREP_CLOSURE_LOC_MAYBE 0
# define CFFI_CHECK_FFI_PREP_CIF_VAR 0
-
-# include "malloc_closure.h"
+# define CFFI_CHECK_FFI_PREP_CIF_VAR_MAYBE 0
#endif
+/* always includes this, even if it turns out not to be used on NetBSD
+ because calls are behind "if (0)" */
+#include "malloc_closure.h"
+
+
#if PY_MAJOR_VERSION >= 3
# define STR_OR_BYTES "bytes"
# define PyText_Type PyUnicode_Type
@@ -232,6 +242,10 @@ typedef unsigned long long int uintmax_t;
# define Py_SET_REFCNT(obj, val) (Py_REFCNT(obj) = (val))
#endif
+#if PY_VERSION_HEX >= 0x03080000
+# define USE_WRITEUNRAISABLEMSG
+#endif
+
/************************************************************/
/* base type flag: exactly one of the following: */
@@ -1975,11 +1989,12 @@ static void cdataowninggc_dealloc(CDataObject *cd)
ffi_closure *closure = ((CDataObject_closure *)cd)->closure;
PyObject *args = (PyObject *)(closure->user_data);
Py_XDECREF(args);
+#if CFFI_CHECK_FFI_CLOSURE_ALLOC_MAYBE
if (CFFI_CHECK_FFI_CLOSURE_ALLOC) {
ffi_closure_free(closure);
- } else {
+ } else
+#endif
cffi_closure_free(closure);
- }
}
else {
Py_FatalError("cdata CDataOwningGC_Type with unexpected type flags");
@@ -4582,14 +4597,18 @@ static void *b_do_dlopen(PyObject *args, const char **p_printable_filename,
if (PyUnicode_Check(s))
{
s = PyUnicode_AsUTF8String(s);
- if (s == NULL)
+ if (s == NULL) {
+ PyMem_Free(filename_or_null);
return NULL;
+ }
*p_temp = s;
}
#endif
*p_printable_filename = PyText_AsUTF8(s);
- if (*p_printable_filename == NULL)
+ if (*p_printable_filename == NULL) {
+ PyMem_Free(filename_or_null);
return NULL;
+ }
}
if ((flags & (RTLD_NOW | RTLD_LAZY)) == 0)
flags |= RTLD_NOW;
@@ -4608,6 +4627,7 @@ static void *b_do_dlopen(PyObject *args, const char **p_printable_filename,
#endif
handle = dlopen(filename_or_null, flags);
+ PyMem_Free(filename_or_null);
#ifdef MS_WIN32
got_handle:
@@ -5921,8 +5941,7 @@ static cif_description_t *fb_prepare_cif(PyObject *fargs,
char *buffer;
cif_description_t *cif_descr;
struct funcbuilder_s funcbuffer;
- ffi_status status;
- char did_prep_cif_var = 0;
+ ffi_status status = (ffi_status)-1;
funcbuffer.nb_bytes = 0;
funcbuffer.bufferp = NULL;
@@ -5947,16 +5966,17 @@ static cif_description_t *fb_prepare_cif(PyObject *fargs,
cif_descr = (cif_description_t *)buffer;
/* use `ffi_prep_cif_var` if necessary and available */
+#if CFFI_CHECK_FFI_PREP_CIF_VAR_MAYBE
if (variadic_nargs_declared >= 0) {
if (CFFI_CHECK_FFI_PREP_CIF_VAR) {
status = ffi_prep_cif_var(&cif_descr->cif, fabi,
variadic_nargs_declared, funcbuffer.nargs,
funcbuffer.rtype, funcbuffer.atypes);
- did_prep_cif_var = 1;
}
}
+#endif
- if (!did_prep_cif_var) {
+ if (status == (ffi_status)-1) {
status = ffi_prep_cif(&cif_descr->cif, fabi, funcbuffer.nargs,
funcbuffer.rtype, funcbuffer.atypes);
}
@@ -6133,6 +6153,43 @@ static void _my_PyErr_WriteUnraisable(PyObject *t, PyObject *v, PyObject *tb,
char *extra_error_line)
{
/* like PyErr_WriteUnraisable(), but write a full traceback */
+#ifdef USE_WRITEUNRAISABLEMSG
+
+ /* PyErr_WriteUnraisable actually writes the full traceback anyway
+ from Python 3.4, but we can't really get the formatting of the
+ custom text to be what we want. We can do better from Python
+ 3.8 by calling the new _PyErr_WriteUnraisableMsg().
+ Luckily it's also Python 3.8 that adds new functionality that
+ people might want: the new sys.unraisablehook().
+ */
+ PyObject *s;
+ int first_char;
+ assert(objdescr != NULL && objdescr[0] != 0); /* non-empty */
+ first_char = objdescr[0];
+ if (first_char >= 'A' && first_char <= 'Z')
+ first_char += 'a' - 'A'; /* lower() the very first character */
+ if (extra_error_line == NULL)
+ extra_error_line = "";
+
+ if (obj != NULL)
+ s = PyUnicode_FromFormat("%c%s%R%s",
+ first_char, objdescr + 1, obj, extra_error_line);
+ else
+ s = PyUnicode_FromFormat("%c%s%s",
+ first_char, objdescr + 1, extra_error_line);
+
+ PyErr_Restore(t, v, tb);
+ if (s != NULL) {
+ _PyErr_WriteUnraisableMsg(PyText_AS_UTF8(s), NULL);
+ Py_DECREF(s);
+ }
+ else
+ PyErr_WriteUnraisable(obj); /* best effort */
+ PyErr_Clear();
+
+#else
+
+ /* version for Python 2.7 and < 3.8 */
PyObject *f;
#if PY_MAJOR_VERSION >= 3
/* jump through hoops to ensure the tb is attached to v, on Python 3 */
@@ -6157,6 +6214,8 @@ static void _my_PyErr_WriteUnraisable(PyObject *t, PyObject *v, PyObject *tb,
Py_XDECREF(t);
Py_XDECREF(v);
Py_XDECREF(tb);
+
+#endif
}
static void general_invoke_callback(int decode_args_from_libffi,
@@ -6206,7 +6265,11 @@ static void general_invoke_callback(int decode_args_from_libffi,
goto error;
if (convert_from_object_fficallback(result, SIGNATURE(1), py_res,
decode_args_from_libffi) < 0) {
+#ifdef USE_WRITEUNRAISABLEMSG
+ extra_error_line = ", trying to convert the result back to C";
+#else
extra_error_line = "Trying to convert the result back to C:\n";
+#endif
goto error;
}
done:
@@ -6258,10 +6321,16 @@ static void general_invoke_callback(int decode_args_from_libffi,
_my_PyErr_WriteUnraisable(exc1, val1, tb1,
"From cffi callback ", py_ob,
extra_error_line);
+#ifdef USE_WRITEUNRAISABLEMSG
+ _my_PyErr_WriteUnraisable(exc2, val2, tb2,
+ "during handling of the above exception by 'onerror'",
+ NULL, NULL);
+#else
extra_error_line = ("\nDuring the call to 'onerror', "
"another exception occurred:\n\n");
_my_PyErr_WriteUnraisable(exc2, val2, tb2,
NULL, NULL, extra_error_line);
+#endif
_cffi_stop_error_capture(ecap);
}
}
@@ -6340,6 +6409,17 @@ static PyObject *prepare_callback_info_tuple(CTypeDescrObject *ct,
return infotuple;
}
+/* messily try to silence a gcc/clang deprecation warning for
+ ffi_prep_closure. Don't miss the "pragma pop" after the function.
+ This is done around the whole function because very old GCCs don't
+ support it inside a function. */
+#if defined(__clang__)
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#elif defined(__GNUC__)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
static PyObject *b_callback(PyObject *self, PyObject *args)
{
CTypeDescrObject *ct;
@@ -6359,9 +6439,12 @@ static PyObject *b_callback(PyObject *self, PyObject *args)
if (infotuple == NULL)
return NULL;
+#if CFFI_CHECK_FFI_CLOSURE_ALLOC_MAYBE
if (CFFI_CHECK_FFI_CLOSURE_ALLOC) {
closure = ffi_closure_alloc(sizeof(ffi_closure), &closure_exec);
- } else {
+ } else
+#endif
+ {
closure = cffi_closure_alloc();
closure_exec = closure;
}
@@ -6382,8 +6465,8 @@ static PyObject *b_callback(PyObject *self, PyObject *args)
cd->head.c_type = ct;
cd->head.c_data = (char *)closure_exec;
cd->head.c_weakreflist = NULL;
+ closure->user_data = NULL;
cd->closure = closure;
- PyObject_GC_Track(cd);
cif_descr = (cif_description_t *)ct->ct_extra;
if (cif_descr == NULL) {
@@ -6393,30 +6476,20 @@ static PyObject *b_callback(PyObject *self, PyObject *args)
goto error;
}
+#if CFFI_CHECK_FFI_PREP_CLOSURE_LOC_MAYBE
if (CFFI_CHECK_FFI_PREP_CLOSURE_LOC) {
status = ffi_prep_closure_loc(closure, &cif_descr->cif,
invoke_callback, infotuple, closure_exec);
}
- else {
+ else
+#endif
+ {
#if defined(__APPLE__) && defined(FFI_AVAILABLE_APPLE) && !FFI_LEGACY_CLOSURE_API
PyErr_Format(PyExc_SystemError, "ffi_prep_closure_loc() is missing");
goto error;
#else
-/* messily try to silence a gcc/clang deprecation warning here */
-# if defined(__clang__)
-# pragma clang diagnostic push
-# pragma clang diagnostic ignored "-Wdeprecated-declarations"
-# elif defined(__GNUC__)
-# pragma GCC diagnostic push
-# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-# endif
status = ffi_prep_closure(closure, &cif_descr->cif,
invoke_callback, infotuple);
-# if defined(__clang__)
-# pragma clang diagnostic pop
-# elif defined(__GNUC__)
-# pragma GCC diagnostic pop
-# endif
#endif
}
@@ -6440,23 +6513,30 @@ static PyObject *b_callback(PyObject *self, PyObject *args)
"different from the 'ffi.h' file seen at compile-time)");
goto error;
}
+ PyObject_GC_Track(cd);
return (PyObject *)cd;
error:
closure->user_data = NULL;
if (cd == NULL) {
+#if CFFI_CHECK_FFI_CLOSURE_ALLOC_MAYBE
if (CFFI_CHECK_FFI_CLOSURE_ALLOC) {
ffi_closure_free(closure);
}
- else {
+ else
+#endif
cffi_closure_free(closure);
- }
}
else
Py_DECREF(cd);
Py_XDECREF(infotuple);
return NULL;
}
+#if defined(__clang__)
+# pragma clang diagnostic pop
+#elif defined(__GNUC__)
+# pragma GCC diagnostic pop
+#endif
static PyObject *b_new_enum_type(PyObject *self, PyObject *args)
{
diff --git a/c/ffi_obj.c b/c/ffi_obj.c
index 05c3a6d..f154146 100644
--- a/c/ffi_obj.c
+++ b/c/ffi_obj.c
@@ -1070,10 +1070,10 @@ static PyObject *ffi_init_once(FFIObject *self, PyObject *args, PyObject *kwds)
if (res != NULL) {
tup = PyTuple_Pack(2, Py_True, res);
if (tup == NULL || PyDict_SetItem(cache, tag, tup) < 0) {
- Py_XDECREF(tup);
Py_DECREF(res);
res = NULL;
}
+ Py_XDECREF(tup);
}
}
diff --git a/c/test_c.py b/c/test_c.py
index 95ca812..788500e 100644
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -17,7 +17,7 @@ from _cffi_backend import __version__
# ____________________________________________________________
import sys
-assert __version__ == "1.14.3", ("This test_c.py file is for testing a version"
+assert __version__ == "1.14.5", ("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,):
@@ -1331,7 +1331,9 @@ def test_callback_exception():
except ImportError:
import io as cStringIO # Python 3
import linecache
- def matches(istr, ipattern):
+ def matches(istr, ipattern, ipattern38):
+ if sys.version_info >= (3, 8):
+ ipattern = ipattern38
str, pattern = istr, ipattern
while '$' in pattern:
i = pattern.index('$')
@@ -1375,6 +1377,14 @@ Traceback (most recent call last):
File "$", line $, in check_value
$
ValueError: 42
+""", """\
+Exception ignored from cffi callback <function$Zcb1 at 0x$>:
+Traceback (most recent call last):
+ File "$", line $, in Zcb1
+ $
+ File "$", line $, in check_value
+ $
+ValueError: 42
""")
sys.stderr = cStringIO.StringIO()
bigvalue = 20000
@@ -1383,6 +1393,12 @@ ValueError: 42
From cffi callback <function$Zcb1 at 0x$>:
Trying to convert the result back to C:
OverflowError: integer 60000 does not fit 'short'
+""", """\
+Exception ignored from cffi callback <function$Zcb1 at 0x$>, trying to convert the result back to C:
+Traceback (most recent call last):
+ File "$", line $, in test_callback_exception
+ $
+OverflowError: integer 60000 does not fit 'short'
""")
sys.stderr = cStringIO.StringIO()
bigvalue = 20000
@@ -1420,6 +1436,17 @@ OverflowError: integer 60000 does not fit 'short'
During the call to 'onerror', another exception occurred:
TypeError: $integer$
+""", """\
+Exception ignored from cffi callback <function$Zcb1 at 0x$>, trying to convert the result back to C:
+Traceback (most recent call last):
+ File "$", line $, in test_callback_exception
+ $
+OverflowError: integer 60000 does not fit 'short'
+Exception ignored during handling of the above exception by 'onerror':
+Traceback (most recent call last):
+ File "$", line $, in test_callback_exception
+ $
+TypeError: $integer$
""")
#
sys.stderr = cStringIO.StringIO()
@@ -1436,6 +1463,17 @@ Traceback (most recent call last):
File "$", line $, in oops
$
AttributeError: 'str' object has no attribute 'append'
+""", """\
+Exception ignored from cffi callback <function$Zcb1 at 0x$>, trying to convert the result back to C:
+Traceback (most recent call last):
+ File "$", line $, in test_callback_exception
+ $
+OverflowError: integer 60000 does not fit 'short'
+Exception ignored during handling of the above exception by 'onerror':
+Traceback (most recent call last):
+ File "$", line $, in oops
+ $
+AttributeError: 'str' object has no attribute 'append'
""")
finally:
sys.stderr = orig_stderr
@@ -1470,7 +1508,7 @@ def test_a_lot_of_callbacks():
def make_callback(m):
def cb(n):
return n + m
- return callback(BFunc, cb, 42) # 'cb' and 'BFunc' go out of scope
+ return callback(BFunc, cb, 42) # 'cb' goes out of scope
#
flist = [make_callback(i) for i in range(BIGNUM)]
for i, f in enumerate(flist):
@@ -3974,6 +4012,20 @@ def test_from_buffer_types():
with pytest.raises(ValueError):
release(pv[0])
+def test_issue483():
+ BInt = new_primitive_type("int")
+ BIntP = new_pointer_type(BInt)
+ BIntA = new_array_type(BIntP, None)
+ lst = list(range(25))
+ bytestring = bytearray(buffer(newp(BIntA, lst))[:] + b'XYZ')
+ p1 = from_buffer(BIntA, bytestring) # int[]
+ assert len(buffer(p1)) == 25 * size_of_int()
+ assert sizeof(p1) == 25 * size_of_int()
+ #
+ p2 = from_buffer(BIntP, bytestring)
+ assert sizeof(p2) == size_of_ptr()
+ assert len(buffer(p2)) == size_of_int() # first element only, by default
+
def test_memmove():
Short = new_primitive_type("short")
ShortA = new_array_type(new_pointer_type(Short), None)
@@ -4515,5 +4567,5 @@ def test_unaligned_types():
pbuf1 = cast(new_pointer_type(p), pbuf + 1)
pbuf1[0] = num
assert pbuf1[0] == num
- assert buf[0] == '\x00'
- assert buf[1 + size] == '\x00'
+ assert buf[0] == b'\x00'
+ assert buf[1 + size] == b'\x00'
diff --git a/cffi/__init__.py b/cffi/__init__.py
index 264afa1..b79c21f 100644
--- a/cffi/__init__.py
+++ b/cffi/__init__.py
@@ -5,8 +5,8 @@ from .api import FFI
from .error import CDefError, FFIError, VerificationError, VerificationMissing
from .error import PkgConfigError
-__version__ = "1.14.3"
-__version_info__ = (1, 14, 3)
+__version__ = "1.14.5"
+__version_info__ = (1, 14, 5)
# 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 --git a/cffi/_embedding.h b/cffi/_embedding.h
index fdce222..c36d793 100644
--- a/cffi/_embedding.h
+++ b/cffi/_embedding.h
@@ -224,7 +224,7 @@ static int _cffi_initialize_python(void)
if (f != NULL && f != Py_None) {
PyFile_WriteString("\nFrom: " _CFFI_MODULE_NAME
- "\ncompiled with cffi version: 1.14.3"
+ "\ncompiled with cffi version: 1.14.5"
"\n_cffi_backend module: ", f);
modules = PyImport_GetModuleDict();
mod = PyDict_GetItemString(modules, "_cffi_backend");
diff --git a/cffi/recompiler.py b/cffi/recompiler.py
index 457d6f9..5369722 100644
--- a/cffi/recompiler.py
+++ b/cffi/recompiler.py
@@ -193,6 +193,17 @@ class Recompiler:
assert isinstance(op, CffiOp)
self.cffi_types = tuple(self.cffi_types) # don't change any more
+ def _enum_fields(self, tp):
+ # When producing C, expand all anonymous struct/union fields.
+ # That's necessary to have C code checking the offsets of the
+ # individual fields contained in them. When producing Python,
+ # don't do it and instead write it like it is, with the
+ # corresponding fields having an empty name. Empty names are
+ # recognized at runtime when we import the generated Python
+ # file.
+ expand_anonymous_struct_union = not self.target_is_python
+ return tp.enumfields(expand_anonymous_struct_union)
+
def _do_collect_type(self, tp):
if not isinstance(tp, model.BaseTypeByIdentity):
if isinstance(tp, tuple):
@@ -206,7 +217,7 @@ class Recompiler:
elif isinstance(tp, model.StructOrUnion):
if tp.fldtypes is not None and (
tp not in self.ffi._parser._included_declarations):
- for name1, tp1, _, _ in tp.enumfields():
+ for name1, tp1, _, _ in self._enum_fields(tp):
self._do_collect_type(self._field_type(tp, name1, tp1))
else:
for _, x in tp._get_items():
@@ -864,7 +875,7 @@ class Recompiler:
prnt('{')
prnt(' /* only to generate compile-time warnings or errors */')
prnt(' (void)p;')
- for fname, ftype, fbitsize, fqual in tp.enumfields():
+ for fname, ftype, fbitsize, fqual in self._enum_fields(tp):
try:
if ftype.is_integer_type() or fbitsize >= 0:
# accept all integers, but complain on float or double
@@ -920,8 +931,7 @@ class Recompiler:
flags = '|'.join(flags) or '0'
c_fields = []
if reason_for_not_expanding is None:
- expand_anonymous_struct_union = not self.target_is_python
- enumfields = list(tp.enumfields(expand_anonymous_struct_union))
+ enumfields = list(self._enum_fields(tp))
for fldname, fldtype, fbitsize, fqual in enumfields:
fldtype = self._field_type(tp, fldname, fldtype)
self._check_not_opaque(fldtype,
diff --git a/cffi/verifier.py b/cffi/verifier.py
index 84fc8b5..c445675 100644
--- a/cffi/verifier.py
+++ b/cffi/verifier.py
@@ -50,7 +50,8 @@ class Verifier(object):
if tag:
raise TypeError("can't specify both 'modulename' and 'tag'")
else:
- key = '\x00'.join([sys.version[:3], __version_verifier_modules__,
+ key = '\x00'.join(['%d.%d' % sys.version_info[:2],
+ __version_verifier_modules__,
preamble, flattened_kwds] +
ffi._cdefsources)
if sys.version_info >= (3,):
diff --git a/doc/source/conf.py b/doc/source/conf.py
index 2315b93..2a7e353 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -47,7 +47,7 @@ copyright = u'2012-2018, Armin Rigo, Maciej Fijalkowski'
# The short X.Y version.
version = '1.14'
# The full version, including alpha/beta/rc tags.
-release = '1.14.3'
+release = '1.14.5'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/doc/source/installation.rst b/doc/source/installation.rst
index 3c010bc..ebd2a34 100644
--- a/doc/source/installation.rst
+++ b/doc/source/installation.rst
@@ -52,13 +52,13 @@ Download and Installation:
* https://pypi.python.org/pypi/cffi
-* Checksums of the "source" package version 1.14.3:
+* Checksums of the "source" package version 1.14.5:
- - MD5: c2a47ffd5d183b193ac8ed3414dcfd07
+ - MD5: 272cb183bf0365530e3c0d8f446cd89d
- - SHA: 7199374653c1927e8d3c523b6498b149acdb6f7e
+ - SHA1: 21cdeccd7b7b121d35eae1b8e91d78f9ec83da98
- - SHA256: f92f789e4f9241cd262ad7a555ca2c648a98178a953af117ef7fad46aa1d5591
+ - SHA256: fd78e5fee591709f32ef6edb9a015b4aa1a5022598e36227500c8f4e02328d9c
* Or grab the most current version from the `Heptapod page`_:
``hg clone https://foss.heptapod.net/pypy/cffi``
diff --git a/doc/source/whatsnew.rst b/doc/source/whatsnew.rst
index 0658e0d..f6111d5 100644
--- a/doc/source/whatsnew.rst
+++ b/doc/source/whatsnew.rst
@@ -3,6 +3,24 @@ What's New
======================
+v1.14.5
+=======
+
+* Source fix for old gcc versions
+
+* This and future releases should include wheels on more platforms,
+ thanks to our new release managers Matt and Matt!
+
+v1.14.4
+=======
+
+Release done for pip reasons.
+
+v1.14.3
+=======
+
+Release done for pip reasons.
+
v1.14.2
=======
diff --git a/setup.py b/setup.py
index 6c6ba77..619d97a 100644
--- a/setup.py
+++ b/setup.py
@@ -76,10 +76,6 @@ def get_config():
config = Distribution().get_command_obj('config')
return config
-def macosx_deployment_target():
- from distutils.sysconfig import get_config_var
- return tuple(map(int, get_config_var("MACOSX_DEPLOYMENT_TARGET").split('.')))
-
def ask_supports_thread():
config = get_config()
ok = (sys.platform != 'win32' and
@@ -196,7 +192,7 @@ Contact
`Mailing list <https://groups.google.com/forum/#!forum/python-cffi>`_
""",
- version='1.14.3',
+ version='1.14.5',
packages=['cffi'] if cpython else [],
package_data={'cffi': ['_cffi_include.h', 'parse_c_type.h',
'_embedding.h', '_cffi_errors.h']}
diff --git a/setup_base.py b/setup_base.py
index 667c7d5..4cf6ea5 100644
--- a/setup_base.py
+++ b/setup_base.py
@@ -8,6 +8,7 @@ from setup import library_dirs, extra_compile_args, extra_link_args
if __name__ == '__main__':
from distutils.core import setup
from distutils.extension import Extension
+
standard = '__pypy__' not in sys.builtin_module_names
setup(packages=['cffi'],
requires=['pycparser'],
diff --git a/testing/cffi0/test_ffi_backend.py b/testing/cffi0/test_ffi_backend.py
index 3552196..8e29bc4 100644
--- a/testing/cffi0/test_ffi_backend.py
+++ b/testing/cffi0/test_ffi_backend.py
@@ -179,6 +179,7 @@ class TestBitfield:
setters = ['case %d: s.%s = value; break;' % iname
for iname in enumerate(fnames)]
lib = ffi1.verify("""
+ #include <string.h>
struct s1 { %s };
struct sa { char a; struct s1 b; };
#define Gofs_y offsetof(struct s1, y)
diff --git a/testing/cffi0/test_version.py b/testing/cffi0/test_version.py
index 9325685..d380b98 100644
--- a/testing/cffi0/test_version.py
+++ b/testing/cffi0/test_version.py
@@ -36,7 +36,12 @@ def test_doc_version_file():
v = cffi.__version__.replace('+', '')
p = os.path.join(parent, 'doc', 'source', 'installation.rst')
content = open(p).read()
- assert (" package version %s:" % v) in content
+ if " package version %s:" % v not in content:
+ for i in range(5):
+ if " package version %s-%d:" % (v, i) in content:
+ break
+ else:
+ assert 0, "doc/source/installation.rst needs updating"
def test_setup_version():
parent = os.path.dirname(os.path.dirname(cffi.__file__))
diff --git a/testing/cffi1/test_re_python.py b/testing/cffi1/test_re_python.py
index dce4f40..2ae0dd1 100644
--- a/testing/cffi1/test_re_python.py
+++ b/testing/cffi1/test_re_python.py
@@ -74,6 +74,7 @@ def setup_module(mod):
int strlen(const char *);
struct with_union { union { int a; char b; }; };
union with_struct { struct { int a; char b; }; };
+ struct with_struct_with_union { struct { union { int x; }; } cp; };
struct NVGcolor { union { float rgba[4]; struct { float r,g,b,a; }; }; };
typedef struct selfref { struct selfref *next; } *selfref_ptr_t;
""")
@@ -248,6 +249,10 @@ def test_anonymous_union_inside_struct():
assert ffi.offsetof("union with_struct", "b") == INT
assert ffi.sizeof("union with_struct") >= INT + 1
#
+ assert ffi.sizeof("struct with_struct_with_union") == INT
+ p = ffi.new("struct with_struct_with_union *")
+ assert p.cp.x == 0
+ #
FLOAT = ffi.sizeof("float")
assert ffi.sizeof("struct NVGcolor") == FLOAT * 4
assert ffi.offsetof("struct NVGcolor", "rgba") == 0