summaryrefslogtreecommitdiff
path: root/c/_cffi_backend.c
diff options
context:
space:
mode:
Diffstat (limited to 'c/_cffi_backend.c')
-rw-r--r--c/_cffi_backend.c144
1 files changed, 112 insertions, 32 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)
{