summaryrefslogtreecommitdiff
path: root/c
diff options
context:
space:
mode:
authorLucia Li <luciali@google.com>2021-11-08 21:45:14 +0800
committerLucia Li <luciali@google.com>2021-11-09 11:01:46 +0800
commit6aa63b08263172a979012747497f4207cc341bb0 (patch)
tree64f8c90740adbe25c30379d6567fd2acafcbd2dd /c
parent3e013ad5e4325c9a301ddde47e997bfd797167cd (diff)
downloadcffi-6aa63b08263172a979012747497f4207cc341bb0.tar.gz
Upgrade cffi from 1.12.2 to 1.15.0
Source is fetched from https://foss.heptapod.net/pypy/cffi/-/archive/branch/release-1.15/cffi-branch-release-1.15.zip Build cffi manually and update Android.bp Bug: 205265538 Test: None Change-Id: I91a5ed3b96029b3988602aba6a00c0e0748d0600
Diffstat (limited to 'c')
-rw-r--r--c/.libs_cffi_backend/libffi-45372312.so.6.0.4bin149064 -> 0 bytes
-rwxr-xr-xc/.libs_cffi_backend/libffi-9c61262e.so.8.1.0bin0 -> 63080 bytes
-rw-r--r--c/Android.bp2
-rw-r--r--c/_cffi_backend.c803
-rwxr-xr-x[-rw-r--r--]c/_cffi_backend.sobin787992 -> 791800 bytes
-rw-r--r--c/call_python.c38
-rw-r--r--c/cdlopen.c5
-rw-r--r--c/cffi1_module.c17
-rw-r--r--c/cglob.c2
-rw-r--r--c/ffi_obj.c4
-rw-r--r--c/lib_obj.c12
-rw-r--r--c/libffi_arm64/README5
-rw-r--r--c/libffi_arm64/ffi.libbin0 -> 7872 bytes
-rw-r--r--c/libffi_arm64/include/ffi.h515
-rw-r--r--c/libffi_arm64/include/fficonfig.h215
-rw-r--r--c/libffi_arm64/include/ffitarget.h92
-rw-r--r--c/libffi_x86_x64/LICENSE (renamed from c/libffi_msvc/LICENSE)0
-rw-r--r--c/libffi_x86_x64/README (renamed from c/libffi_msvc/README)0
-rw-r--r--c/libffi_x86_x64/README.ctypes (renamed from c/libffi_msvc/README.ctypes)0
-rw-r--r--c/libffi_x86_x64/ffi.c (renamed from c/libffi_msvc/ffi.c)37
-rw-r--r--c/libffi_x86_x64/ffi.h (renamed from c/libffi_msvc/ffi.h)0
-rw-r--r--c/libffi_x86_x64/ffi_common.h (renamed from c/libffi_msvc/ffi_common.h)0
-rw-r--r--c/libffi_x86_x64/fficonfig.h (renamed from c/libffi_msvc/fficonfig.h)0
-rw-r--r--c/libffi_x86_x64/ffitarget.h (renamed from c/libffi_msvc/ffitarget.h)0
-rw-r--r--c/libffi_x86_x64/prep_cif.c (renamed from c/libffi_msvc/prep_cif.c)5
-rw-r--r--c/libffi_x86_x64/types.c (renamed from c/libffi_msvc/types.c)0
-rw-r--r--c/libffi_x86_x64/win32.c (renamed from c/libffi_msvc/win32.c)0
-rw-r--r--c/libffi_x86_x64/win64.asm (renamed from c/libffi_msvc/win64.asm)0
-rw-r--r--c/libffi_x86_x64/win64.obj (renamed from c/libffi_msvc/win64.obj)bin1176 -> 1176 bytes
-rw-r--r--c/misc_win32.h5
-rw-r--r--c/realize_c_type.c43
-rw-r--r--c/test_c.py567
32 files changed, 1975 insertions, 392 deletions
diff --git a/c/.libs_cffi_backend/libffi-45372312.so.6.0.4 b/c/.libs_cffi_backend/libffi-45372312.so.6.0.4
deleted file mode 100644
index 59e65c0..0000000
--- a/c/.libs_cffi_backend/libffi-45372312.so.6.0.4
+++ /dev/null
Binary files differ
diff --git a/c/.libs_cffi_backend/libffi-9c61262e.so.8.1.0 b/c/.libs_cffi_backend/libffi-9c61262e.so.8.1.0
new file mode 100755
index 0000000..82b4232
--- /dev/null
+++ b/c/.libs_cffi_backend/libffi-9c61262e.so.8.1.0
Binary files differ
diff --git a/c/Android.bp b/c/Android.bp
index 7ddc006..a187416 100644
--- a/c/Android.bp
+++ b/c/Android.bp
@@ -55,6 +55,6 @@ python_library {
filegroup {
name: "py-cffi-backend-libffi-files",
srcs: [
- ".libs_cffi_backend/libffi-45372312.so.6.0.4",
+ ".libs_cffi_backend/libffi-9c61262e.so.8.1.0",
],
}
diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
index c39866a..ffecbf9 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.12.2"
+#define CFFI_VERSION "1.15.0"
#ifdef MS_WIN32
#include <windows.h>
@@ -80,18 +80,46 @@
* That sounds like a horribly bad idea to me, and is the reason for why
* I prefer CFFI crashing cleanly.
*
- * Currently, we use libffi's ffi_closure_alloc() only on NetBSD. It is
+ * Currently, we use libffi's ffi_closure_alloc() on NetBSD. It is
* known that on the NetBSD kernel, a different strategy is used which
* should not be open to the fork() bug.
+ *
+ * This is also used on macOS, provided we are executing on macOS 10.15 or
+ * above. It's a mess because it needs runtime checks in that case.
*/
#ifdef __NetBSD__
-# define CFFI_TRUST_LIBFFI
-#endif
-#ifndef CFFI_TRUST_LIBFFI
-# include "malloc_closure.h"
+# 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, *)
+# 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
+# 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"
@@ -148,6 +176,14 @@
(PyCObject_FromVoidPtr(pointer, destructor))
#endif
+#if PY_VERSION_HEX < 0x030900a4
+# 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: */
@@ -174,7 +210,7 @@
#define CT_IS_BOOL 0x00080000
#define CT_IS_FILE 0x00100000
#define CT_IS_VOID_PTR 0x00200000
-#define CT_WITH_VAR_ARRAY 0x00400000
+#define CT_WITH_VAR_ARRAY 0x00400000 /* with open-ended array, anywhere */
/* unused 0x00800000 */
#define CT_LAZY_FIELD_LIST 0x01000000
#define CT_WITH_PACKED_CHANGE 0x02000000
@@ -238,12 +274,14 @@ static PyTypeObject CField_Type;
static PyTypeObject CData_Type;
static PyTypeObject CDataOwning_Type;
static PyTypeObject CDataOwningGC_Type;
+static PyTypeObject CDataFromBuf_Type;
static PyTypeObject CDataGCP_Type;
#define CTypeDescr_Check(ob) (Py_TYPE(ob) == &CTypeDescr_Type)
#define CData_Check(ob) (Py_TYPE(ob) == &CData_Type || \
Py_TYPE(ob) == &CDataOwning_Type || \
Py_TYPE(ob) == &CDataOwningGC_Type || \
+ Py_TYPE(ob) == &CDataFromBuf_Type || \
Py_TYPE(ob) == &CDataGCP_Type)
#define CDataOwn_Check(ob) (Py_TYPE(ob) == &CDataOwning_Type || \
Py_TYPE(ob) == &CDataOwningGC_Type)
@@ -277,14 +315,14 @@ typedef struct {
typedef struct {
CDataObject head;
- PyObject *structobj;
+ PyObject *structobj; /* for ffi.new_handle() or ffi.new("struct *") */
} CDataObject_own_structptr;
typedef struct {
CDataObject head;
Py_ssize_t length; /* same as CDataObject_own_length up to here */
Py_buffer *bufferview;
-} CDataObject_owngc_frombuf;
+} CDataObject_frombuf;
typedef struct {
CDataObject head;
@@ -402,10 +440,10 @@ ctypedescr_dealloc(CTypeDescrObject *ct)
if (ct->ct_unique_key != NULL) {
/* revive dead object temporarily for DelItem */
- Py_REFCNT(ct) = 43;
+ Py_SET_REFCNT(ct, 43);
PyDict_DelItem(unique_cache, ct->ct_unique_key);
assert(Py_REFCNT(ct) == 42);
- Py_REFCNT(ct) = 0;
+ Py_SET_REFCNT(ct, 0);
Py_DECREF(ct->ct_unique_key);
}
Py_XDECREF(ct->ct_itemdescr);
@@ -651,7 +689,7 @@ static PyMethodDef ctypedescr_methods[] = {
static PyTypeObject CTypeDescr_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
- "_cffi_backend.CTypeDescr",
+ "_cffi_backend.CType",
offsetof(CTypeDescrObject, ct_name),
sizeof(char),
(destructor)ctypedescr_dealloc, /* tp_dealloc */
@@ -1331,6 +1369,29 @@ convert_field_from_object(char *data, CFieldObject *cf, PyObject *value)
}
static int
+add_varsize_length(Py_ssize_t offset, Py_ssize_t itemsize,
+ Py_ssize_t varsizelength, Py_ssize_t *optvarsize)
+{
+ /* update '*optvarsize' to account for an array of 'varsizelength'
+ elements, each of size 'itemsize', that starts at 'offset'. */
+ Py_ssize_t size = ADD_WRAPAROUND(offset,
+ MUL_WRAPAROUND(itemsize, varsizelength));
+ if (size < 0 ||
+ ((size - offset) / itemsize) != varsizelength) {
+ PyErr_SetString(PyExc_OverflowError,
+ "array size would overflow a Py_ssize_t");
+ return -1;
+ }
+ if (size > *optvarsize)
+ *optvarsize = size;
+ return 0;
+}
+
+static int
+convert_struct_from_object(char *data, CTypeDescrObject *ct, PyObject *init,
+ Py_ssize_t *optvarsize); /* forward */
+
+static int
convert_vfield_from_object(char *data, CFieldObject *cf, PyObject *value,
Py_ssize_t *optvarsize)
{
@@ -1343,20 +1404,11 @@ convert_vfield_from_object(char *data, CFieldObject *cf, PyObject *value,
if (optvarsize != NULL) {
/* in this mode, the only purpose of this function is to compute
the real size of the structure from a var-sized C99 array */
- Py_ssize_t size, itemsize;
assert(data == NULL);
- itemsize = cf->cf_type->ct_itemdescr->ct_size;
- size = ADD_WRAPAROUND(cf->cf_offset,
- MUL_WRAPAROUND(itemsize, varsizelength));
- if (size < 0 ||
- ((size - cf->cf_offset) / itemsize) != varsizelength) {
- PyErr_SetString(PyExc_OverflowError,
- "array size would overflow a Py_ssize_t");
- return -1;
- }
- if (size > *optvarsize)
- *optvarsize = size;
- return 0;
+ return add_varsize_length(cf->cf_offset,
+ cf->cf_type->ct_itemdescr->ct_size,
+ varsizelength,
+ optvarsize);
}
/* if 'value' was only an integer, get_new_array_length() returns
it and convert 'value' to be None. Detect if this was the case,
@@ -1365,8 +1417,16 @@ convert_vfield_from_object(char *data, CFieldObject *cf, PyObject *value,
if (value == Py_None)
return 0;
}
- if (optvarsize == NULL)
+ if (optvarsize == NULL) {
return convert_field_from_object(data, cf, value);
+ }
+ else if ((cf->cf_type->ct_flags & CT_WITH_VAR_ARRAY) != 0 &&
+ !CData_Check(value)) {
+ Py_ssize_t subsize = cf->cf_type->ct_size;
+ if (convert_struct_from_object(NULL, cf->cf_type, value, &subsize) < 0)
+ return -1;
+ return add_varsize_length(cf->cf_offset, 1, subsize, optvarsize);
+ }
else
return 0;
}
@@ -1831,6 +1891,7 @@ static void cdataowning_dealloc(CDataObject *cd)
assert(!(cd->c_type->ct_flags & (CT_IS_VOID_PTR | CT_FUNCTIONPTR)));
if (cd->c_type->ct_flags & CT_IS_PTR_TO_OWNED) {
+ /* for ffi.new("struct *") */
Py_DECREF(((CDataObject_own_structptr *)cd)->structobj);
}
#if defined(CFFI_MEM_DEBUG) || defined(CFFI_MEM_LEAK)
@@ -1851,9 +1912,6 @@ static void cdataowning_dealloc(CDataObject *cd)
static void cdataowninggc_dealloc(CDataObject *cd)
{
- assert(!(cd->c_type->ct_flags & (CT_IS_PTR_TO_OWNED |
- CT_PRIMITIVE_ANY |
- CT_STRUCT | CT_UNION)));
PyObject_GC_UnTrack(cd);
if (cd->c_type->ct_flags & CT_IS_VOID_PTR) { /* a handle */
@@ -1864,20 +1922,28 @@ static void cdataowninggc_dealloc(CDataObject *cd)
ffi_closure *closure = ((CDataObject_closure *)cd)->closure;
PyObject *args = (PyObject *)(closure->user_data);
Py_XDECREF(args);
-#ifdef CFFI_TRUST_LIBFFI
- ffi_closure_free(closure);
-#else
- cffi_closure_free(closure);
+#if CFFI_CHECK_FFI_CLOSURE_ALLOC_MAYBE
+ if (CFFI_CHECK_FFI_CLOSURE_ALLOC) {
+ ffi_closure_free(closure);
+ } else
#endif
+ cffi_closure_free(closure);
}
- else if (cd->c_type->ct_flags & CT_ARRAY) { /* from_buffer */
- Py_buffer *view = ((CDataObject_owngc_frombuf *)cd)->bufferview;
- PyBuffer_Release(view);
- PyObject_Free(view);
+ else {
+ Py_FatalError("cdata CDataOwningGC_Type with unexpected type flags");
}
cdata_dealloc(cd);
}
+static void cdatafrombuf_dealloc(CDataObject *cd)
+{
+ Py_buffer *view = ((CDataObject_frombuf *)cd)->bufferview;
+ cdata_dealloc(cd);
+
+ PyBuffer_Release(view);
+ PyObject_Free(view);
+}
+
static int cdataowninggc_traverse(CDataObject *cd, visitproc visit, void *arg)
{
if (cd->c_type->ct_flags & CT_IS_VOID_PTR) { /* a handle */
@@ -1889,10 +1955,13 @@ static int cdataowninggc_traverse(CDataObject *cd, visitproc visit, void *arg)
PyObject *args = (PyObject *)(closure->user_data);
Py_VISIT(args);
}
- else if (cd->c_type->ct_flags & CT_ARRAY) { /* from_buffer */
- Py_buffer *view = ((CDataObject_owngc_frombuf *)cd)->bufferview;
- Py_VISIT(view->obj);
- }
+ return 0;
+}
+
+static int cdatafrombuf_traverse(CDataObject *cd, visitproc visit, void *arg)
+{
+ Py_buffer *view = ((CDataObject_frombuf *)cd)->bufferview;
+ Py_VISIT(view->obj);
return 0;
}
@@ -1911,10 +1980,13 @@ static int cdataowninggc_clear(CDataObject *cd)
closure->user_data = NULL;
Py_XDECREF(args);
}
- else if (cd->c_type->ct_flags & CT_ARRAY) { /* from_buffer */
- Py_buffer *view = ((CDataObject_owngc_frombuf *)cd)->bufferview;
- PyBuffer_Release(view);
- }
+ return 0;
+}
+
+static int cdatafrombuf_clear(CDataObject *cd)
+{
+ Py_buffer *view = ((CDataObject_frombuf *)cd)->bufferview;
+ PyBuffer_Release(view);
return 0;
}
@@ -2096,6 +2168,35 @@ static Py_ssize_t _cdata_var_byte_size(CDataObject *cd)
return -1;
}
+static PyObject *_frombuf_repr(CDataObject *cd, const char *cd_type_name)
+{
+ Py_buffer *view = ((CDataObject_frombuf *)cd)->bufferview;
+ const char *obj_tp_name;
+ if (view->obj == NULL) {
+ return PyText_FromFormat(
+ "<cdata '%s' buffer RELEASED>",
+ cd_type_name);
+ }
+
+ obj_tp_name = Py_TYPE(view->obj)->tp_name;
+ if (cd->c_type->ct_flags & CT_ARRAY)
+ {
+ Py_ssize_t buflen = get_array_length(cd);
+ return PyText_FromFormat(
+ "<cdata '%s' buffer len %zd from '%.200s' object>",
+ cd_type_name,
+ buflen,
+ obj_tp_name);
+ }
+ else
+ {
+ return PyText_FromFormat(
+ "<cdata '%s' buffer from '%.200s' object>",
+ cd_type_name,
+ obj_tp_name);
+ }
+}
+
static PyObject *cdataowning_repr(CDataObject *cd)
{
Py_ssize_t size = _cdata_var_byte_size(cd);
@@ -2125,16 +2226,12 @@ static PyObject *cdataowninggc_repr(CDataObject *cd)
else
return _cdata_repr2(cd, "calling", PyTuple_GET_ITEM(args, 1));
}
- else if (cd->c_type->ct_flags & CT_ARRAY) { /* from_buffer */
- Py_buffer *view = ((CDataObject_owngc_frombuf *)cd)->bufferview;
- Py_ssize_t buflen = get_array_length(cd);
- return PyText_FromFormat(
- "<cdata '%s' buffer len %zd from '%.200s' object>",
- cd->c_type->ct_name,
- buflen,
- view->obj ? Py_TYPE(view->obj)->tp_name : "(null)");
- }
- return cdataowning_repr(cd);
+ return cdataowning_repr(cd); /* but should be unreachable */
+}
+
+static PyObject *cdatafrombuf_repr(CDataObject *cd)
+{
+ return _frombuf_repr(cd, cd->c_type->ct_name);
}
static int cdata_nonzero(CDataObject *cd)
@@ -2171,7 +2268,10 @@ static PyObject *cdata_int(CDataObject *cd)
return PyInt_FromLong(value);
}
if (cd->c_type->ct_flags & (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_UNSIGNED)) {
- return convert_to_object(cd->c_data, cd->c_type);
+ PyObject *result = convert_to_object(cd->c_data, cd->c_type);
+ if (result != NULL && PyBool_Check(result))
+ result = PyInt_FromLong(PyInt_AsLong(result));
+ return result;
}
else if (cd->c_type->ct_flags & CT_PRIMITIVE_CHAR) {
/*READ(cd->c_data, cd->c_type->ct_size)*/
@@ -2313,7 +2413,11 @@ static PyObject *cdata_richcompare(PyObject *v, PyObject *w, int op)
return pyres;
}
-static long cdata_hash(CDataObject *v)
+#if PY_MAJOR_VERSION < 3
+typedef long Py_hash_t;
+#endif
+
+static Py_hash_t cdata_hash(PyObject *v)
{
if (((CDataObject *)v)->c_type->ct_flags & CT_PRIMITIVE_ANY) {
PyObject *vv = convert_to_object(((CDataObject *)v)->c_data,
@@ -2321,13 +2425,13 @@ static long cdata_hash(CDataObject *v)
if (vv == NULL)
return -1;
if (!CData_Check(vv)) {
- long hash = PyObject_Hash(vv);
+ Py_hash_t hash = PyObject_Hash(vv);
Py_DECREF(vv);
return hash;
}
Py_DECREF(vv);
}
- return _Py_HashPointer(v->c_data);
+ return _Py_HashPointer(((CDataObject *)v)->c_data);
}
static Py_ssize_t
@@ -2821,7 +2925,8 @@ static PyObject *
convert_struct_to_owning_object(char *data, CTypeDescrObject *ct); /*forward*/
static cif_description_t *
-fb_prepare_cif(PyObject *fargs, CTypeDescrObject *, ffi_abi); /*forward*/
+fb_prepare_cif(PyObject *fargs, CTypeDescrObject *, Py_ssize_t, ffi_abi);
+ /*forward*/
static PyObject *new_primitive_type(const char *name); /*forward*/
@@ -2924,12 +3029,22 @@ cdata_call(CDataObject *cd, PyObject *args, PyObject *kwds)
CTypeDescrObject *fresult;
char *resultdata;
char *errormsg;
+ struct freeme_s {
+ struct freeme_s *next;
+ union_alignment alignment;
+ } *freeme = NULL;
if (!(cd->c_type->ct_flags & CT_FUNCTIONPTR)) {
PyErr_Format(PyExc_TypeError, "cdata '%s' is not callable",
cd->c_type->ct_name);
return NULL;
}
+ if (cd->c_data == NULL) {
+ PyErr_Format(PyExc_RuntimeError,
+ "cannot call null pointer pointer from cdata '%s'",
+ cd->c_type->ct_name);
+ return NULL;
+ }
if (kwds != NULL && PyDict_Size(kwds) != 0) {
PyErr_SetString(PyExc_TypeError,
"a cdata function cannot be called with keyword arguments");
@@ -3004,7 +3119,7 @@ cdata_call(CDataObject *cd, PyObject *args, PyObject *kwds)
#else
fabi = PyLong_AS_LONG(PyTuple_GET_ITEM(signature, 0));
#endif
- cif_descr = fb_prepare_cif(fvarargs, fresult, fabi);
+ cif_descr = fb_prepare_cif(fvarargs, fresult, nargs_declared, fabi);
if (cif_descr == NULL)
goto error;
}
@@ -3038,7 +3153,21 @@ cdata_call(CDataObject *cd, PyObject *args, PyObject *kwds)
else if (datasize < 0)
goto error;
else {
- tmpbuf = alloca(datasize);
+ if (datasize <= 512) {
+ tmpbuf = alloca(datasize);
+ }
+ else {
+ struct freeme_s *fp = (struct freeme_s *)PyObject_Malloc(
+ offsetof(struct freeme_s, alignment) +
+ (size_t)datasize);
+ if (fp == NULL) {
+ PyErr_NoMemory();
+ goto error;
+ }
+ fp->next = freeme;
+ freeme = fp;
+ tmpbuf = (char *)&fp->alignment;
+ }
memset(tmpbuf, 0, datasize);
*(char **)data = tmpbuf;
if (convert_array_from_object(tmpbuf, argtype, obj) < 0)
@@ -3083,6 +3212,11 @@ cdata_call(CDataObject *cd, PyObject *args, PyObject *kwds)
/* fall-through */
error:
+ while (freeme != NULL) {
+ void *p = (void *)freeme;
+ freeme = freeme->next;
+ PyObject_Free(p);
+ }
if (buffer)
PyObject_Free(buffer);
if (fvarargs != NULL) {
@@ -3139,9 +3273,8 @@ static int explicit_release_case(PyObject *cd)
if ((ct->ct_flags & (CT_POINTER | CT_ARRAY)) != 0) /* ffi.new() */
return 0;
}
- else if (Py_TYPE(cd) == &CDataOwningGC_Type) {
- if (ct->ct_flags & CT_ARRAY) /* ffi.from_buffer() */
- return 1;
+ else if (Py_TYPE(cd) == &CDataFromBuf_Type) {
+ return 1; /* ffi.from_buffer() */
}
else if (Py_TYPE(cd) == &CDataGCP_Type) {
return 2; /* ffi.gc() */
@@ -3178,14 +3311,14 @@ static PyObject *cdata_exit(PyObject *cd, PyObject *args)
PyObject *x = ((CDataObject_own_structptr *)cd)->structobj;
if (Py_TYPE(x) == &CDataGCP_Type) {
/* this is a special case for
- ffi.new_allocator()("struct-or-union") */
+ ffi.new_allocator()("struct-or-union *") */
cdatagcp_finalize((CDataObject_gcp *)x);
}
}
break;
case 1: /* ffi.from_buffer() */
- view = ((CDataObject_owngc_frombuf *)cd)->bufferview;
+ view = ((CDataObject_frombuf *)cd)->bufferview;
PyBuffer_Release(view);
break;
@@ -3259,7 +3392,7 @@ static PyMethodDef cdata_methods[] = {
static PyTypeObject CData_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
- "_cffi_backend.CData",
+ "_cffi_backend._CDataBase",
sizeof(CDataObject),
0,
(destructor)cdata_dealloc, /* tp_dealloc */
@@ -3271,14 +3404,16 @@ static PyTypeObject CData_Type = {
&CData_as_number, /* tp_as_number */
0, /* tp_as_sequence */
&CData_as_mapping, /* tp_as_mapping */
- (hashfunc)cdata_hash, /* tp_hash */
+ cdata_hash, /* tp_hash */
(ternaryfunc)cdata_call, /* tp_call */
0, /* tp_str */
(getattrofunc)cdata_getattro, /* tp_getattro */
(setattrofunc)cdata_setattro, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
- 0, /* tp_doc */
+ "The internal base type for CData objects. Use FFI.CData to access "
+ "it. Always check with isinstance(): subtypes are sometimes returned "
+ "on CPython, for performance reasons.", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
cdata_richcompare, /* tp_richcompare */
@@ -3301,7 +3436,7 @@ static PyTypeObject CData_Type = {
static PyTypeObject CDataOwning_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
- "_cffi_backend.CDataOwn",
+ "_cffi_backend.__CDataOwn",
sizeof(CDataObject),
0,
(destructor)cdataowning_dealloc, /* tp_dealloc */
@@ -3320,7 +3455,8 @@ static PyTypeObject CDataOwning_Type = {
0, /* inherited */ /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
- 0, /* tp_doc */
+ "This is an internal subtype of _CDataBase for performance only on "
+ "CPython. Check with isinstance(x, ffi.CData).", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* inherited */ /* tp_richcompare */
@@ -3343,8 +3479,8 @@ static PyTypeObject CDataOwning_Type = {
static PyTypeObject CDataOwningGC_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
- "_cffi_backend.CDataOwnGC",
- sizeof(CDataObject_owngc_frombuf),
+ "_cffi_backend.__CDataOwnGC",
+ sizeof(CDataObject_own_structptr),
0,
(destructor)cdataowninggc_dealloc, /* tp_dealloc */
0, /* tp_print */
@@ -3363,7 +3499,8 @@ static PyTypeObject CDataOwningGC_Type = {
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES /* tp_flags */
| Py_TPFLAGS_HAVE_GC,
- 0, /* tp_doc */
+ "This is an internal subtype of _CDataBase for performance only on "
+ "CPython. Check with isinstance(x, ffi.CData).", /* tp_doc */
(traverseproc)cdataowninggc_traverse, /* tp_traverse */
(inquiry)cdataowninggc_clear, /* tp_clear */
0, /* inherited */ /* tp_richcompare */
@@ -3384,9 +3521,53 @@ static PyTypeObject CDataOwningGC_Type = {
PyObject_GC_Del, /* tp_free */
};
+static PyTypeObject CDataFromBuf_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "_cffi_backend.__CDataFromBuf",
+ sizeof(CDataObject_frombuf),
+ 0,
+ (destructor)cdatafrombuf_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ (reprfunc)cdatafrombuf_repr, /* tp_repr */
+ 0, /* inherited */ /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* inherited */ /* tp_as_mapping */
+ 0, /* inherited */ /* tp_hash */
+ 0, /* inherited */ /* tp_call */
+ 0, /* tp_str */
+ 0, /* inherited */ /* tp_getattro */
+ 0, /* inherited */ /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES /* tp_flags */
+ | Py_TPFLAGS_HAVE_GC,
+ "This is an internal subtype of _CDataBase for performance only on "
+ "CPython. Check with isinstance(x, ffi.CData).", /* tp_doc */
+ (traverseproc)cdatafrombuf_traverse, /* tp_traverse */
+ (inquiry)cdatafrombuf_clear, /* tp_clear */
+ 0, /* inherited */ /* tp_richcompare */
+ 0, /* inherited */ /* tp_weaklistoffset */
+ 0, /* inherited */ /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* inherited */ /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &CData_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+ PyObject_GC_Del, /* tp_free */
+};
+
static PyTypeObject CDataGCP_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
- "_cffi_backend.CDataGCP",
+ "_cffi_backend.__CDataGCP",
sizeof(CDataObject_gcp),
0,
(destructor)cdatagcp_dealloc, /* tp_dealloc */
@@ -3409,7 +3590,8 @@ static PyTypeObject CDataGCP_Type = {
| Py_TPFLAGS_HAVE_FINALIZE
#endif
| Py_TPFLAGS_HAVE_GC,
- 0, /* tp_doc */
+ "This is an internal subtype of _CDataBase for performance only on "
+ "CPython. Check with isinstance(x, ffi.CData).", /* tp_doc */
(traverseproc)cdatagcp_traverse, /* tp_traverse */
0, /* tp_clear */
0, /* inherited */ /* tp_richcompare */
@@ -3470,7 +3652,7 @@ cdataiter_dealloc(CDataIterObject *it)
static PyTypeObject CDataIter_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
- "_cffi_backend.CDataIter", /* tp_name */
+ "_cffi_backend.__CData_iterator", /* tp_name */
sizeof(CDataIterObject), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
@@ -4086,11 +4268,12 @@ typedef struct {
PyObject_HEAD
void *dl_handle;
char *dl_name;
+ int dl_auto_close;
} DynLibObject;
static void dl_dealloc(DynLibObject *dlobj)
{
- if (dlobj->dl_handle != NULL)
+ if (dlobj->dl_handle != NULL && dlobj->dl_auto_close)
dlclose(dlobj->dl_handle);
free(dlobj->dl_name);
PyObject_Del(dlobj);
@@ -4224,7 +4407,7 @@ static PyMethodDef dl_methods[] = {
static PyTypeObject dl_type = {
PyVarObject_HEAD_INIT(NULL, 0)
- "_cffi_backend.Library", /* tp_name */
+ "_cffi_backend.CLibrary", /* tp_name */
sizeof(DynLibObject), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
@@ -4255,7 +4438,7 @@ static PyTypeObject dl_type = {
};
static void *b_do_dlopen(PyObject *args, const char **p_printable_filename,
- PyObject **p_temp)
+ PyObject **p_temp, int *auto_close)
{
/* Logic to call the correct version of dlopen(). Returns NULL in case of error.
Otherwise, '*p_printable_filename' will point to a printable char version of
@@ -4266,6 +4449,7 @@ static void *b_do_dlopen(PyObject *args, const char **p_printable_filename,
char *filename_or_null;
int flags = 0;
*p_temp = NULL;
+ *auto_close = 1;
if (PyTuple_GET_SIZE(args) == 0 || PyTuple_GET_ITEM(args, 0) == Py_None) {
PyObject *dummy;
@@ -4275,13 +4459,37 @@ static void *b_do_dlopen(PyObject *args, const char **p_printable_filename,
filename_or_null = NULL;
*p_printable_filename = "<None>";
}
+ else if (CData_Check(PyTuple_GET_ITEM(args, 0)))
+ {
+ CDataObject *cd;
+ if (!PyArg_ParseTuple(args, "O|i:load_library", &cd, &flags))
+ return NULL;
+ /* 'flags' is accepted but ignored in this case */
+ if ((cd->c_type->ct_flags & CT_IS_VOID_PTR) == 0) {
+ PyErr_Format(PyExc_TypeError,
+ "dlopen() takes a file name or 'void *' handle, not '%s'",
+ cd->c_type->ct_name);
+ return NULL;
+ }
+ handle = cd->c_data;
+ if (handle == NULL) {
+ PyErr_Format(PyExc_RuntimeError, "cannot call dlopen(NULL)");
+ return NULL;
+ }
+ *p_temp = PyText_FromFormat("%p", handle);
+ *p_printable_filename = PyText_AsUTF8(*p_temp);
+ *auto_close = 0;
+ return handle;
+ }
else
{
PyObject *s = PyTuple_GET_ITEM(args, 0);
#ifdef MS_WIN32
- Py_UNICODE *filenameW;
- if (PyArg_ParseTuple(args, "u|i:load_library", &filenameW, &flags))
+ PyObject *filename_unicode;
+ if (PyArg_ParseTuple(args, "U|i:load_library", &filename_unicode, &flags))
{
+ Py_ssize_t sz1;
+ wchar_t *w1;
#if PY_MAJOR_VERSION < 3
s = PyUnicode_AsUTF8String(s);
if (s == NULL)
@@ -4292,7 +4500,15 @@ static void *b_do_dlopen(PyObject *args, const char **p_printable_filename,
if (*p_printable_filename == NULL)
return NULL;
- handle = dlopenW(filenameW);
+ sz1 = PyUnicode_GetSize(filename_unicode) + 1;
+ sz1 *= 2; /* should not be needed, but you never know */
+ w1 = alloca(sizeof(wchar_t) * sz1);
+ sz1 = PyUnicode_AsWideChar((PyUnicodeObject *)filename_unicode,
+ w1, sz1 - 1);
+ if (sz1 < 0)
+ return NULL;
+ w1[sz1] = 0;
+ handle = dlopenW(w1);
goto got_handle;
}
PyErr_Clear();
@@ -4304,19 +4520,31 @@ 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;
+#ifdef MS_WIN32
+ if (filename_or_null == NULL) {
+ PyErr_SetString(PyExc_OSError, "dlopen(None) not supported on Windows");
+ return NULL;
+ }
+#endif
+
handle = dlopen(filename_or_null, flags);
+ PyMem_Free(filename_or_null);
#ifdef MS_WIN32
got_handle:
@@ -4336,8 +4564,9 @@ static PyObject *b_load_library(PyObject *self, PyObject *args)
PyObject *temp;
void *handle;
DynLibObject *dlobj = NULL;
+ int auto_close;
- handle = b_do_dlopen(args, &printable_filename, &temp);
+ handle = b_do_dlopen(args, &printable_filename, &temp, &auto_close);
if (handle == NULL)
goto error;
@@ -4348,6 +4577,7 @@ static PyObject *b_load_library(PyObject *self, PyObject *args)
}
dlobj->dl_handle = handle;
dlobj->dl_name = strdup(printable_filename);
+ dlobj->dl_auto_close = auto_close;
error:
Py_XDECREF(temp);
@@ -4831,7 +5061,9 @@ static int complete_sflags(int sflags)
#ifdef MS_WIN32
sflags |= SF_MSVC_BITFIELDS;
#else
-# if defined(__arm__) || defined(__aarch64__)
+# if defined(__APPLE__) && defined(__arm64__)
+ sflags |= SF_GCC_X86_BITFIELDS;
+# elif defined(__arm__) || defined(__aarch64__)
sflags |= SF_GCC_ARM_BITFIELDS;
# else
sflags |= SF_GCC_X86_BITFIELDS;
@@ -4859,8 +5091,8 @@ static int detect_custom_layout(CTypeDescrObject *ct, int sflags,
if (sflags & SF_STD_FIELD_POS) {
PyErr_Format(FFIError,
"%s: %s%s%s (cdef says %zd, but C compiler says %zd)."
- " fix it or use \"...;\" in the cdef for %s to "
- "make it flexible",
+ " fix it or use \"...;\" as the last field in the "
+ "cdef for %s to make it flexible",
ct->ct_name, msg1, txt, msg2,
cdef_value, compiler_value,
ct->ct_name);
@@ -4871,12 +5103,16 @@ static int detect_custom_layout(CTypeDescrObject *ct, int sflags,
return 0;
}
+#define ROUNDUP_BYTES(bytes, bits) ((bytes) + ((bits) > 0))
+
static PyObject *b_complete_struct_or_union(PyObject *self, PyObject *args)
{
CTypeDescrObject *ct;
PyObject *fields, *interned_fields, *ignored;
int is_union, alignment;
- Py_ssize_t boffset, i, nb_fields, boffsetmax, alignedsize, boffsetorg;
+ Py_ssize_t byteoffset, i, nb_fields, byteoffsetmax, alignedsize;
+ int bitoffset;
+ Py_ssize_t byteoffsetorg;
Py_ssize_t totalsize = -1;
int totalalignment = -1;
CFieldObject **previous;
@@ -4915,8 +5151,9 @@ static PyObject *b_complete_struct_or_union(PyObject *self, PyObject *args)
ct->ct_flags &= ~(CT_CUSTOM_FIELD_POS | CT_WITH_PACKED_CHANGE);
alignment = 1;
- boffset = 0; /* this number is in *bits*, not bytes! */
- boffsetmax = 0; /* the maximum value of boffset, in bits too */
+ byteoffset = 0; /* the real value is 'byteoffset+bitoffset*8', which */
+ bitoffset = 0; /* counts the offset in bits */
+ byteoffsetmax = 0; /* the maximum value of byteoffset-rounded-up-to-byte */
prev_bitfield_size = 0;
prev_bitfield_free = 0;
nb_fields = PyList_GET_SIZE(fields);
@@ -4951,9 +5188,22 @@ static PyObject *b_complete_struct_or_union(PyObject *self, PyObject *args)
goto error;
}
}
+ else if (ftype->ct_flags & (CT_STRUCT|CT_UNION)) {
+ if (force_lazy_struct(ftype) < 0) /* for CT_WITH_VAR_ARRAY */
+ return NULL;
+
+ /* GCC (or maybe C99) accepts var-sized struct fields that are not
+ the last field of a larger struct. That's why there is no
+ check here for "last field": we propagate the flag
+ CT_WITH_VAR_ARRAY to any struct that contains either an open-
+ ended array or another struct that recursively contains an
+ open-ended array. */
+ if (ftype->ct_flags & CT_WITH_VAR_ARRAY)
+ ct->ct_flags |= CT_WITH_VAR_ARRAY;
+ }
if (is_union)
- boffset = 0; /* reset each field at offset 0 */
+ byteoffset = bitoffset = 0; /* reset each field at offset 0 */
/* update the total alignment requirement, but skip it if the
field is an anonymous bitfield or if SF_PACKED */
@@ -4988,20 +5238,26 @@ static PyObject *b_complete_struct_or_union(PyObject *self, PyObject *args)
bs_flag = BS_REGULAR;
/* align this field to its own 'falign' by inserting padding */
- boffsetorg = (boffset + falignorg*8-1) & ~(falignorg*8-1); /*bits!*/
- boffset = (boffset + falign*8-1) & ~(falign*8-1); /* bits! */
- if (boffsetorg != boffset) {
+
+ /* first, pad to the next byte,
+ * then pad to 'falign' or 'falignorg' bytes */
+ byteoffset = ROUNDUP_BYTES(byteoffset, bitoffset);
+ bitoffset = 0;
+ byteoffsetorg = (byteoffset + falignorg-1) & ~(falignorg-1);
+ byteoffset = (byteoffset + falign-1) & ~(falign-1);
+
+ if (byteoffsetorg != byteoffset) {
ct->ct_flags |= CT_WITH_PACKED_CHANGE;
}
if (foffset >= 0) {
/* a forced field position: ignore the offset just computed,
except to know if we must set CT_CUSTOM_FIELD_POS */
- if (detect_custom_layout(ct, sflags, boffset / 8, foffset,
+ if (detect_custom_layout(ct, sflags, byteoffset, foffset,
"wrong offset for field '",
PyText_AS_UTF8(fname), "'") < 0)
goto error;
- boffset = foffset * 8;
+ byteoffset = foffset;
}
if (PyText_GetSize(fname) == 0 &&
@@ -5015,7 +5271,7 @@ static PyObject *b_complete_struct_or_union(PyObject *self, PyObject *args)
*previous = _add_field(interned_fields,
get_field_name(ftype, cfsrc),
cfsrc->cf_type,
- boffset / 8 + cfsrc->cf_offset,
+ byteoffset + cfsrc->cf_offset,
cfsrc->cf_bitshift,
cfsrc->cf_bitsize,
cfsrc->cf_flags | fflags);
@@ -5028,13 +5284,13 @@ static PyObject *b_complete_struct_or_union(PyObject *self, PyObject *args)
}
else {
*previous = _add_field(interned_fields, fname, ftype,
- boffset / 8, bs_flag, -1, fflags);
+ byteoffset, bs_flag, -1, fflags);
if (*previous == NULL)
goto error;
previous = &(*previous)->cf_next;
}
if (ftype->ct_size >= 0)
- boffset += ftype->ct_size * 8;
+ byteoffset += ftype->ct_size;
prev_bitfield_size = 0;
}
else {
@@ -5071,7 +5327,7 @@ static PyObject *b_complete_struct_or_union(PyObject *self, PyObject *args)
/* compute the starting position of the theoretical field
that covers a complete 'ftype', inside of which we will
locate the real bitfield */
- field_offset_bytes = boffset / 8;
+ field_offset_bytes = byteoffset;
field_offset_bytes &= ~(falign - 1);
if (fbitsize == 0) {
@@ -5084,12 +5340,13 @@ static PyObject *b_complete_struct_or_union(PyObject *self, PyObject *args)
if (!(sflags & SF_MSVC_BITFIELDS)) {
/* GCC's notion of "ftype :0;" */
- /* pad boffset to a value aligned for "ftype" */
- if (boffset > field_offset_bytes * 8) {
+ /* pad byteoffset to a value aligned for "ftype" */
+ if (ROUNDUP_BYTES(byteoffset, bitoffset) > field_offset_bytes) {
field_offset_bytes += falign;
- assert(boffset < field_offset_bytes * 8);
+ assert(byteoffset < field_offset_bytes);
}
- boffset = field_offset_bytes * 8;
+ byteoffset = field_offset_bytes;
+ bitoffset = 0;
}
else {
/* MSVC's notion of "ftype :0;" */
@@ -5106,7 +5363,8 @@ static PyObject *b_complete_struct_or_union(PyObject *self, PyObject *args)
/* Can the field start at the offset given by 'boffset'? It
can if it would entirely fit into an aligned ftype field. */
- bits_already_occupied = boffset - (field_offset_bytes * 8);
+ bits_already_occupied = (byteoffset-field_offset_bytes) * 8
+ + bitoffset;
if (bits_already_occupied + fbitsize > 8 * ftype->ct_size) {
/* it would not fit, we need to start at the next
@@ -5120,15 +5378,18 @@ static PyObject *b_complete_struct_or_union(PyObject *self, PyObject *args)
goto error;
}
field_offset_bytes += falign;
- assert(boffset < field_offset_bytes * 8);
- boffset = field_offset_bytes * 8;
+ assert(byteoffset < field_offset_bytes);
+ byteoffset = field_offset_bytes;
+ bitoffset = 0;
bitshift = 0;
}
else {
bitshift = bits_already_occupied;
assert(bitshift >= 0);
}
- boffset += fbitsize;
+ bitoffset += fbitsize;
+ byteoffset += (bitoffset >> 3);
+ bitoffset &= 7;
}
else {
/* MSVC's algorithm */
@@ -5144,38 +5405,43 @@ static PyObject *b_complete_struct_or_union(PyObject *self, PyObject *args)
}
else {
/* no: start a new full field */
- boffset = (boffset + falign*8-1) & ~(falign*8-1); /*align*/
- boffset += ftype->ct_size * 8;
+ byteoffset = ROUNDUP_BYTES(byteoffset, bitoffset);
+ bitoffset = 0;
+ /* align */
+ byteoffset = (byteoffset + falign-1) & ~(falign-1);
+ byteoffset += ftype->ct_size;
bitshift = 0;
prev_bitfield_size = ftype->ct_size;
prev_bitfield_free = 8 * prev_bitfield_size;
}
prev_bitfield_free -= fbitsize;
- field_offset_bytes = boffset / 8 - ftype->ct_size;
+ field_offset_bytes = byteoffset - ftype->ct_size;
}
-
if (sflags & SF_GCC_BIG_ENDIAN)
bitshift = 8 * ftype->ct_size - fbitsize - bitshift;
- *previous = _add_field(interned_fields, fname, ftype,
+ if (PyText_GetSize(fname) > 0) {
+
+ *previous = _add_field(interned_fields, fname, ftype,
field_offset_bytes, bitshift, fbitsize,
fflags);
- if (*previous == NULL)
- goto error;
- previous = &(*previous)->cf_next;
+ if (*previous == NULL)
+ goto error;
+ previous = &(*previous)->cf_next;
+ }
}
}
- if (boffset > boffsetmax)
- boffsetmax = boffset;
+ assert(bitoffset == (bitoffset & 7));
+ if (ROUNDUP_BYTES(byteoffset, bitoffset) > byteoffsetmax)
+ byteoffsetmax = ROUNDUP_BYTES(byteoffset, bitoffset);
}
*previous = NULL;
/* Like C, if the size of this structure would be zero, we compute it
as 1 instead. But for ctypes support, we allow the manually-
specified totalsize to be zero in this case. */
- boffsetmax = (boffsetmax + 7) / 8; /* bits -> bytes */
- alignedsize = (boffsetmax + alignment - 1) & ~(alignment-1);
+ alignedsize = (byteoffsetmax + alignment - 1) & ~(alignment-1);
if (alignedsize == 0)
alignedsize = 1;
@@ -5186,10 +5452,10 @@ static PyObject *b_complete_struct_or_union(PyObject *self, PyObject *args)
if (detect_custom_layout(ct, sflags, alignedsize,
totalsize, "wrong total size", "", "") < 0)
goto error;
- if (totalsize < boffsetmax) {
+ if (totalsize < byteoffsetmax) {
PyErr_Format(PyExc_TypeError,
"%s cannot be of size %zd: there are fields at least "
- "up to %zd", ct->ct_name, totalsize, boffsetmax);
+ "up to %zd", ct->ct_name, totalsize, byteoffsetmax);
goto error;
}
}
@@ -5585,11 +5851,14 @@ static CTypeDescrObject *fb_prepare_ctype(struct funcbuilder_s *fb,
static cif_description_t *fb_prepare_cif(PyObject *fargs,
CTypeDescrObject *fresult,
+ Py_ssize_t variadic_nargs_declared,
ffi_abi fabi)
+
{
char *buffer;
cif_description_t *cif_descr;
struct funcbuilder_s funcbuffer;
+ ffi_status status = (ffi_status)-1;
funcbuffer.nb_bytes = 0;
funcbuffer.bufferp = NULL;
@@ -5612,8 +5881,24 @@ static cif_description_t *fb_prepare_cif(PyObject *fargs,
assert(funcbuffer.bufferp == buffer + funcbuffer.nb_bytes);
cif_descr = (cif_description_t *)buffer;
- if (ffi_prep_cif(&cif_descr->cif, fabi, funcbuffer.nargs,
- funcbuffer.rtype, funcbuffer.atypes) != FFI_OK) {
+
+ /* 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);
+ }
+ }
+#endif
+
+ if (status == (ffi_status)-1) {
+ status = ffi_prep_cif(&cif_descr->cif, fabi, funcbuffer.nargs,
+ funcbuffer.rtype, funcbuffer.atypes);
+ }
+
+ if (status != FFI_OK) {
PyErr_SetString(PyExc_SystemError,
"libffi failed to build this function type");
goto error;
@@ -5657,7 +5942,7 @@ static PyObject *new_function_type(PyObject *fargs, /* tuple */
is computed here. */
cif_description_t *cif_descr;
- cif_descr = fb_prepare_cif(fargs, fresult, fabi);
+ cif_descr = fb_prepare_cif(fargs, fresult, -1, fabi);
if (cif_descr == NULL) {
if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) {
PyErr_Clear(); /* will get the exception if we see an
@@ -5785,6 +6070,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 */
@@ -5809,6 +6131,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,
@@ -5858,7 +6182,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:
@@ -5910,10 +6238,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);
}
}
@@ -5981,15 +6315,28 @@ static PyObject *prepare_callback_info_tuple(CTypeDescrObject *ct,
infotuple = Py_BuildValue("OOOO", ct, ob, py_rawerr, onerror_ob);
Py_DECREF(py_rawerr);
-#ifdef WITH_THREAD
+#if defined(WITH_THREAD) && PY_VERSION_HEX < 0x03070000
/* We must setup the GIL here, in case the callback is invoked in
- some other non-Pythonic thread. This is the same as ctypes. */
+ some other non-Pythonic thread. This is the same as ctypes.
+ But PyEval_InitThreads() is always a no-op from CPython 3.7
+ (the call from ctypes was removed some time later I think). */
PyEval_InitThreads();
#endif
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;
@@ -5998,6 +6345,7 @@ static PyObject *b_callback(PyObject *self, PyObject *args)
PyObject *infotuple;
cif_description_t *cif_descr;
ffi_closure *closure;
+ ffi_status status;
void *closure_exec;
if (!PyArg_ParseTuple(args, "O!O|OO:callback", &CTypeDescr_Type, &ct, &ob,
@@ -6008,14 +6356,23 @@ static PyObject *b_callback(PyObject *self, PyObject *args)
if (infotuple == NULL)
return NULL;
-#ifdef CFFI_TRUST_LIBFFI
- closure = ffi_closure_alloc(sizeof(ffi_closure), &closure_exec);
-#else
- closure = cffi_closure_alloc();
- closure_exec = closure;
+#if CFFI_CHECK_FFI_CLOSURE_ALLOC_MAYBE
+ if (CFFI_CHECK_FFI_CLOSURE_ALLOC) {
+ closure = ffi_closure_alloc(sizeof(ffi_closure), &closure_exec);
+ } else
#endif
+ {
+ closure = cffi_closure_alloc();
+ closure_exec = closure;
+ }
+
if (closure == NULL) {
Py_DECREF(infotuple);
+ PyErr_SetString(PyExc_MemoryError,
+ "Cannot allocate write+execute memory for ffi.callback(). "
+ "You might be running on a system that prevents this. "
+ "For more information, see "
+ "https://cffi.readthedocs.io/en/latest/using.html#callbacks");
return NULL;
}
cd = PyObject_GC_New(CDataObject_closure, &CDataOwningGC_Type);
@@ -6025,8 +6382,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) {
@@ -6035,17 +6392,30 @@ static PyObject *b_callback(PyObject *self, PyObject *args)
"return type or with '...'", ct->ct_name);
goto error;
}
-#ifdef CFFI_TRUST_LIBFFI
- if (ffi_prep_closure_loc(closure, &cif_descr->cif,
- invoke_callback, infotuple, closure_exec) != FFI_OK) {
+
+#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
+#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
- if (ffi_prep_closure(closure, &cif_descr->cif,
- invoke_callback, infotuple) != FFI_OK) {
+ status = ffi_prep_closure(closure, &cif_descr->cif,
+ invoke_callback, infotuple);
#endif
+ }
+
+ if (status != FFI_OK) {
PyErr_SetString(PyExc_SystemError,
"libffi failed to build this callback");
goto error;
}
+
if (closure->user_data != infotuple) {
/* Issue #266. Should not occur, but could, if we are using
at runtime a version of libffi compiled with a different
@@ -6060,22 +6430,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) {
-#ifdef CFFI_TRUST_LIBFFI
- ffi_closure_free(closure);
-#else
- cffi_closure_free(closure);
+#if CFFI_CHECK_FFI_CLOSURE_ALLOC_MAYBE
+ if (CFFI_CHECK_FFI_CLOSURE_ALLOC) {
+ ffi_closure_free(closure);
+ }
+ 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)
{
@@ -6697,7 +7075,7 @@ static PyObject *newp_handle(CTypeDescrObject *ct_voidp, PyObject *x)
&CDataOwningGC_Type);
if (cd == NULL)
return NULL;
- Py_INCREF(ct_voidp);
+ Py_INCREF(ct_voidp); /* must be "void *" */
cd->head.c_type = ct_voidp;
cd->head.c_data = (char *)cd;
cd->head.c_weakreflist = NULL;
@@ -6815,10 +7193,11 @@ static PyObject *direct_from_buffer(CTypeDescrObject *ct, PyObject *x,
{
CDataObject *cd;
Py_buffer *view;
- Py_ssize_t arraylength;
+ Py_ssize_t arraylength, minimumlength = 0;
- if (!(ct->ct_flags & CT_ARRAY)) {
- PyErr_Format(PyExc_TypeError, "expected an array ctype, got '%s'",
+ if (!(ct->ct_flags & (CT_ARRAY | CT_POINTER))) {
+ PyErr_Format(PyExc_TypeError,
+ "expected a pointer or array ctype, got '%s'",
ct->ct_name);
return NULL;
}
@@ -6841,43 +7220,51 @@ static PyObject *direct_from_buffer(CTypeDescrObject *ct, PyObject *x,
if (_my_PyObject_GetContiguousBuffer(x, view, require_writable) < 0)
goto error1;
- if (ct->ct_length >= 0) {
- /* it's an array with a fixed length; make sure that the
- buffer contains enough bytes. */
- if (view->len < ct->ct_size) {
- PyErr_Format(PyExc_ValueError,
- "buffer is too small (%zd bytes) for '%s' (%zd bytes)",
- view->len, ct->ct_name, ct->ct_size);
- goto error2;
- }
- arraylength = ct->ct_length;
+ if (ct->ct_flags & CT_POINTER)
+ {
+ arraylength = view->len; /* number of bytes, not used so far */
}
else {
- /* it's an open 'array[]' */
- if (ct->ct_itemdescr->ct_size == 1) {
- /* fast path, performance only */
- arraylength = view->len;
- }
- else if (ct->ct_itemdescr->ct_size > 0) {
- /* give it as many items as fit the buffer. Ignore a
- partial last element. */
- arraylength = view->len / ct->ct_itemdescr->ct_size;
+ /* ct->ct_flags & CT_ARRAY */
+ if (ct->ct_length >= 0) {
+ /* it's an array with a fixed length; make sure that the
+ buffer contains enough bytes. */
+ minimumlength = ct->ct_size;
+ arraylength = ct->ct_length;
}
else {
- /* it's an array 'empty[]'. Unsupported obscure case:
- the problem is that setting the length of the result
- to anything large (like SSIZE_T_MAX) is dangerous,
- because if someone tries to loop over it, it will
- turn effectively into an infinite loop. */
- PyErr_Format(PyExc_ZeroDivisionError,
- "from_buffer('%s', ..): the actual length of the array "
- "cannot be computed", ct->ct_name);
- goto error2;
+ /* it's an open 'array[]' */
+ if (ct->ct_itemdescr->ct_size == 1) {
+ /* fast path, performance only */
+ arraylength = view->len;
+ }
+ else if (ct->ct_itemdescr->ct_size > 0) {
+ /* give it as many items as fit the buffer. Ignore a
+ partial last element. */
+ arraylength = view->len / ct->ct_itemdescr->ct_size;
+ }
+ else {
+ /* it's an array 'empty[]'. Unsupported obscure case:
+ the problem is that setting the length of the result
+ to anything large (like SSIZE_T_MAX) is dangerous,
+ because if someone tries to loop over it, it will
+ turn effectively into an infinite loop. */
+ PyErr_Format(PyExc_ZeroDivisionError,
+ "from_buffer('%s', ..): the actual length of the array "
+ "cannot be computed", ct->ct_name);
+ goto error2;
+ }
}
}
+ if (view->len < minimumlength) {
+ PyErr_Format(PyExc_ValueError,
+ "buffer is too small (%zd bytes) for '%s' (%zd bytes)",
+ view->len, ct->ct_name, minimumlength);
+ goto error2;
+ }
- cd = (CDataObject *)PyObject_GC_New(CDataObject_owngc_frombuf,
- &CDataOwningGC_Type);
+ cd = (CDataObject *)PyObject_GC_New(CDataObject_frombuf,
+ &CDataFromBuf_Type);
if (cd == NULL)
goto error2;
@@ -6885,8 +7272,8 @@ static PyObject *direct_from_buffer(CTypeDescrObject *ct, PyObject *x,
cd->c_type = ct;
cd->c_data = view->buf;
cd->c_weakreflist = NULL;
- ((CDataObject_owngc_frombuf *)cd)->length = arraylength;
- ((CDataObject_owngc_frombuf *)cd)->bufferview = view;
+ ((CDataObject_frombuf *)cd)->length = arraylength;
+ ((CDataObject_frombuf *)cd)->bufferview = view;
PyObject_GC_Track(cd);
return (PyObject *)cd;
@@ -7576,6 +7963,22 @@ init_cffi_backend(void)
PyObject *m, *v;
int i;
static char init_done = 0;
+ static PyTypeObject *all_types[] = {
+ &dl_type,
+ &CTypeDescr_Type,
+ &CField_Type,
+ &CData_Type,
+ &CDataOwning_Type,
+ &CDataOwningGC_Type,
+ &CDataFromBuf_Type,
+ &CDataGCP_Type,
+ &CDataIter_Type,
+ &MiniBuffer_Type,
+ &FFI_Type,
+ &Lib_Type,
+ &GlobSupport_Type,
+ NULL
+ };
v = PySys_GetObject("version");
if (v == NULL || !PyText_Check(v) ||
@@ -7601,24 +8004,22 @@ init_cffi_backend(void)
INITERROR;
}
- if (PyType_Ready(&dl_type) < 0)
- INITERROR;
- if (PyType_Ready(&CTypeDescr_Type) < 0)
- INITERROR;
- if (PyType_Ready(&CField_Type) < 0)
- INITERROR;
- if (PyType_Ready(&CData_Type) < 0)
- INITERROR;
- if (PyType_Ready(&CDataOwning_Type) < 0)
- INITERROR;
- if (PyType_Ready(&CDataOwningGC_Type) < 0)
- INITERROR;
- if (PyType_Ready(&CDataGCP_Type) < 0)
- INITERROR;
- if (PyType_Ready(&CDataIter_Type) < 0)
- INITERROR;
- if (PyType_Ready(&MiniBuffer_Type) < 0)
- INITERROR;
+ /* readify all types and add them to the module */
+ for (i = 0; all_types[i] != NULL; i++) {
+ PyTypeObject *tp = all_types[i];
+ PyObject *tpo = (PyObject *)tp;
+ if (strncmp(tp->tp_name, "_cffi_backend.", 14) != 0) {
+ PyErr_Format(PyExc_ImportError,
+ "'%s' is an ill-formed type name", tp->tp_name);
+ INITERROR;
+ }
+ if (PyType_Ready(tp) < 0)
+ INITERROR;
+
+ Py_INCREF(tpo);
+ if (PyModule_AddObject(m, tp->tp_name + 14, tpo) < 0)
+ INITERROR;
+ }
if (!init_done) {
v = PyText_FromString("_cffi_backend");
@@ -7664,10 +8065,6 @@ init_cffi_backend(void)
INITERROR;
}
- Py_INCREF(&MiniBuffer_Type);
- if (PyModule_AddObject(m, "buffer", (PyObject *)&MiniBuffer_Type) < 0)
- INITERROR;
-
init_cffi_tls();
if (PyErr_Occurred())
INITERROR;
diff --git a/c/_cffi_backend.so b/c/_cffi_backend.so
index 7055ae6..31f7528 100644..100755
--- a/c/_cffi_backend.so
+++ b/c/_cffi_backend.so
Binary files differ
diff --git a/c/call_python.c b/c/call_python.c
index 8fdcb90..d3d2e17 100644
--- a/c/call_python.c
+++ b/c/call_python.c
@@ -1,10 +1,18 @@
#if PY_VERSION_HEX >= 0x03080000
-# define Py_BUILD_CORE
-/* for access to the fields of PyInterpreterState */
-# include "internal/pycore_pystate.h"
-# undef Py_BUILD_CORE
+# define HAVE_PYINTERPSTATE_GETDICT
#endif
+
+static PyObject *_current_interp_key(void)
+{
+ PyInterpreterState *interp = PyThreadState_GET()->interp;
+#ifdef HAVE_PYINTERPSTATE_GETDICT
+ return PyInterpreterState_GetDict(interp); /* shared reference */
+#else
+ return interp->modules;
+#endif
+}
+
static PyObject *_get_interpstate_dict(void)
{
/* Hack around to return a dict that is subinterpreter-local.
@@ -14,8 +22,9 @@ static PyObject *_get_interpstate_dict(void)
*/
static PyObject *attr_name = NULL;
PyThreadState *tstate;
- PyObject *d, *builtins;
+ PyObject *d, *interpdict;
int err;
+ PyInterpreterState *interp;
tstate = PyThreadState_GET();
if (tstate == NULL) {
@@ -23,8 +32,13 @@ static PyObject *_get_interpstate_dict(void)
return NULL;
}
- builtins = tstate->interp->builtins;
- if (builtins == NULL) {
+ interp = tstate->interp;
+#ifdef HAVE_PYINTERPSTATE_GETDICT
+ interpdict = PyInterpreterState_GetDict(interp); /* shared reference */
+#else
+ interpdict = interp->builtins;
+#endif
+ if (interpdict == NULL) {
/* subinterpreter was cleared already, or is being cleared right now,
to a point that is too much for us to continue */
return NULL;
@@ -38,13 +52,13 @@ static PyObject *_get_interpstate_dict(void)
goto error;
}
- d = PyDict_GetItem(builtins, attr_name);
+ d = PyDict_GetItem(interpdict, attr_name);
if (d == NULL) {
d = PyDict_New();
if (d == NULL)
goto error;
- err = PyDict_SetItem(builtins, attr_name, d);
- Py_DECREF(d); /* if successful, there is one ref left in builtins */
+ err = PyDict_SetItem(interpdict, attr_name, d);
+ Py_DECREF(d); /* if successful, there is one ref left in interpdict */
if (err < 0)
goto error;
}
@@ -163,7 +177,7 @@ static int _update_cache_to_call_python(struct _cffi_externpy_s *externpy)
if (infotuple == NULL)
return 3; /* no ffi.def_extern() from this subinterpreter */
- new1 = PyThreadState_GET()->interp->modules;
+ new1 = _current_interp_key();
Py_INCREF(new1);
Py_INCREF(infotuple);
old1 = (PyObject *)externpy->reserved1;
@@ -252,7 +266,7 @@ static void cffi_call_python(struct _cffi_externpy_s *externpy, char *args)
}
else {
PyGILState_STATE state = gil_ensure();
- if (externpy->reserved1 != PyThreadState_GET()->interp->modules) {
+ if (externpy->reserved1 != _current_interp_key()) {
/* Update the (reserved1, reserved2) cache. This will fail
if we didn't call @ffi.def_extern() in this particular
subinterpreter. */
diff --git a/c/cdlopen.c b/c/cdlopen.c
index ad33bbd..0ed319b 100644
--- a/c/cdlopen.c
+++ b/c/cdlopen.c
@@ -43,12 +43,13 @@ static PyObject *ffi_dlopen(PyObject *self, PyObject *args)
const char *modname;
PyObject *temp, *result = NULL;
void *handle;
+ int auto_close;
- handle = b_do_dlopen(args, &modname, &temp);
+ handle = b_do_dlopen(args, &modname, &temp, &auto_close);
if (handle != NULL)
{
result = (PyObject *)lib_internal_new((FFIObject *)self,
- modname, handle);
+ modname, handle, auto_close);
}
Py_XDECREF(temp);
return result;
diff --git a/c/cffi1_module.c b/c/cffi1_module.c
index 2b98e8e..06a84fe 100644
--- a/c/cffi1_module.c
+++ b/c/cffi1_module.c
@@ -26,11 +26,6 @@ static int init_ffi_lib(PyObject *m)
int i, res;
static char init_done = 0;
- if (PyType_Ready(&FFI_Type) < 0)
- return -1;
- if (PyType_Ready(&Lib_Type) < 0)
- return -1;
-
if (!init_done) {
if (init_global_types_dict(FFI_Type.tp_dict) < 0)
return -1;
@@ -62,16 +57,6 @@ static int init_ffi_lib(PyObject *m)
}
init_done = 1;
}
-
- x = (PyObject *)&FFI_Type;
- Py_INCREF(x);
- if (PyModule_AddObject(m, "FFI", x) < 0)
- return -1;
- x = (PyObject *)&Lib_Type;
- Py_INCREF(x);
- if (PyModule_AddObject(m, "Lib", x) < 0)
- return -1;
-
return 0;
}
@@ -199,7 +184,7 @@ static PyObject *b_init_cffi_1_0_external_module(PyObject *self, PyObject *arg)
if (ffi == NULL || PyModule_AddObject(m, "ffi", (PyObject *)ffi) < 0)
return NULL;
- lib = lib_internal_new(ffi, module_name, NULL);
+ lib = lib_internal_new(ffi, module_name, NULL, 0);
if (lib == NULL || PyModule_AddObject(m, "lib", (PyObject *)lib) < 0)
return NULL;
diff --git a/c/cglob.c b/c/cglob.c
index 9ee4025..e97767c 100644
--- a/c/cglob.c
+++ b/c/cglob.c
@@ -20,7 +20,7 @@ static void glob_support_dealloc(GlobSupportObject *gs)
static PyTypeObject GlobSupport_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
- "FFIGlobSupport",
+ "_cffi_backend.__FFIGlobSupport",
sizeof(GlobSupportObject),
0,
(destructor)glob_support_dealloc, /* tp_dealloc */
diff --git a/c/ffi_obj.c b/c/ffi_obj.c
index 1e8cc6f..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);
}
}
@@ -1137,7 +1137,7 @@ static PyGetSetDef ffi_getsets[] = {
static PyTypeObject FFI_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
- "CompiledFFI",
+ "_cffi_backend.FFI",
sizeof(FFIObject),
0,
(destructor)ffi_dealloc, /* tp_dealloc */
diff --git a/c/lib_obj.c b/c/lib_obj.c
index 7cd40ec..38bf3d5 100644
--- a/c/lib_obj.c
+++ b/c/lib_obj.c
@@ -29,6 +29,7 @@ struct LibObject_s {
PyObject *l_libname; /* some string that gives the name of the lib */
FFIObject *l_ffi; /* reference back to the ffi object */
void *l_libhandle; /* the dlopen()ed handle, if any */
+ int l_auto_close; /* if we must dlclose() this handle */
};
static struct CPyExtFunc_s *_cpyextfunc_get(PyObject *x)
@@ -91,7 +92,8 @@ static void *cdlopen_fetch(PyObject *libname, void *libhandle,
static void lib_dealloc(LibObject *lib)
{
PyObject_GC_UnTrack(lib);
- cdlopen_close_ignore_errors(lib->l_libhandle);
+ if (lib->l_auto_close)
+ cdlopen_close_ignore_errors(lib->l_libhandle);
Py_DECREF(lib->l_dict);
Py_DECREF(lib->l_libname);
Py_DECREF(lib->l_ffi);
@@ -587,7 +589,7 @@ static PyMethodDef lib_methods[] = {
static PyTypeObject Lib_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
- "CompiledLib",
+ "_cffi_backend.Lib",
sizeof(LibObject),
0,
(destructor)lib_dealloc, /* tp_dealloc */
@@ -624,7 +626,7 @@ static PyTypeObject Lib_Type = {
};
static LibObject *lib_internal_new(FFIObject *ffi, const char *module_name,
- void *dlopen_libhandle)
+ void *dlopen_libhandle, int auto_close)
{
LibObject *lib;
PyObject *libname, *dict;
@@ -647,6 +649,7 @@ static LibObject *lib_internal_new(FFIObject *ffi, const char *module_name,
Py_INCREF(ffi);
lib->l_ffi = ffi;
lib->l_libhandle = dlopen_libhandle;
+ lib->l_auto_close = auto_close;
return lib;
err3:
@@ -654,7 +657,8 @@ static LibObject *lib_internal_new(FFIObject *ffi, const char *module_name,
err2:
Py_DECREF(libname);
err1:
- cdlopen_close_ignore_errors(dlopen_libhandle);
+ if (auto_close)
+ cdlopen_close_ignore_errors(dlopen_libhandle);
return NULL;
}
diff --git a/c/libffi_arm64/README b/c/libffi_arm64/README
new file mode 100644
index 0000000..3b8f133
--- /dev/null
+++ b/c/libffi_arm64/README
@@ -0,0 +1,5 @@
+Libffi package for ARM64 is copied from cpython binary dependencies
+
+https://github.com/python/cpython-bin-deps/archive/libffi.zip
+
+The library file has been renamed from libffi-7.lib to ffi.lib to avoid special casing \ No newline at end of file
diff --git a/c/libffi_arm64/ffi.lib b/c/libffi_arm64/ffi.lib
new file mode 100644
index 0000000..4a8b84b
--- /dev/null
+++ b/c/libffi_arm64/ffi.lib
Binary files differ
diff --git a/c/libffi_arm64/include/ffi.h b/c/libffi_arm64/include/ffi.h
new file mode 100644
index 0000000..d91c3e1
--- /dev/null
+++ b/c/libffi_arm64/include/ffi.h
@@ -0,0 +1,515 @@
+/* -----------------------------------------------------------------*-C-*-
+ libffi 3.3-rc0 - Copyright (c) 2011, 2014 Anthony Green
+ - Copyright (c) 1996-2003, 2007, 2008 Red Hat, Inc.
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation
+ files (the ``Software''), to deal in the Software without
+ restriction, including without limitation the rights to use, copy,
+ modify, merge, publish, distribute, sublicense, and/or sell copies
+ of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+
+ ----------------------------------------------------------------------- */
+
+/* -------------------------------------------------------------------
+ Most of the API is documented in doc/libffi.texi.
+
+ The raw API is designed to bypass some of the argument packing and
+ unpacking on architectures for which it can be avoided. Routines
+ are provided to emulate the raw API if the underlying platform
+ doesn't allow faster implementation.
+
+ More details on the raw API can be found in:
+
+ http://gcc.gnu.org/ml/java/1999-q3/msg00138.html
+
+ and
+
+ http://gcc.gnu.org/ml/java/1999-q3/msg00174.html
+ -------------------------------------------------------------------- */
+
+#ifndef LIBFFI_H
+#define LIBFFI_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Specify which architecture libffi is configured for. */
+#ifndef ARM_WIN64
+#define ARM_WIN64
+#endif
+
+/* ---- System configuration information --------------------------------- */
+
+#include <ffitarget.h>
+
+#ifndef LIBFFI_ASM
+
+#if defined(_MSC_VER) && !defined(__clang__)
+#define __attribute__(X)
+#endif
+
+#include <stddef.h>
+#include <limits.h>
+
+/* LONG_LONG_MAX is not always defined (not if STRICT_ANSI, for example).
+ But we can find it either under the correct ANSI name, or under GNU
+ C's internal name. */
+
+#define FFI_64_BIT_MAX 9223372036854775807
+
+#ifdef LONG_LONG_MAX
+# define FFI_LONG_LONG_MAX LONG_LONG_MAX
+#else
+# ifdef LLONG_MAX
+# define FFI_LONG_LONG_MAX LLONG_MAX
+# ifdef _AIX52 /* or newer has C99 LLONG_MAX */
+# undef FFI_64_BIT_MAX
+# define FFI_64_BIT_MAX 9223372036854775807LL
+# endif /* _AIX52 or newer */
+# else
+# ifdef __GNUC__
+# define FFI_LONG_LONG_MAX __LONG_LONG_MAX__
+# endif
+# ifdef _AIX /* AIX 5.1 and earlier have LONGLONG_MAX */
+# ifndef __PPC64__
+# if defined (__IBMC__) || defined (__IBMCPP__)
+# define FFI_LONG_LONG_MAX LONGLONG_MAX
+# endif
+# endif /* __PPC64__ */
+# undef FFI_64_BIT_MAX
+# define FFI_64_BIT_MAX 9223372036854775807LL
+# endif
+# endif
+#endif
+
+/* The closure code assumes that this works on pointers, i.e. a size_t
+ can hold a pointer. */
+
+typedef struct _ffi_type
+{
+ size_t size;
+ unsigned short alignment;
+ unsigned short type;
+ struct _ffi_type **elements;
+} ffi_type;
+
+/* Need minimal decorations for DLLs to work on Windows. GCC has
+ autoimport and autoexport. Always mark externally visible symbols
+ as dllimport for MSVC clients, even if it means an extra indirection
+ when using the static version of the library.
+ Besides, as a workaround, they can define FFI_BUILDING if they
+ *know* they are going to link with the static library. */
+#if defined _MSC_VER
+# if defined FFI_BUILDING_DLL /* Building libffi.DLL with msvcc.sh */
+# define FFI_API __declspec(dllexport)
+# elif !defined FFI_BUILDING /* Importing libffi.DLL */
+# define FFI_API __declspec(dllimport)
+# else /* Building/linking static library */
+# define FFI_API
+# endif
+#else
+# define FFI_API
+#endif
+
+/* The externally visible type declarations also need the MSVC DLL
+ decorations, or they will not be exported from the object file. */
+#if defined LIBFFI_HIDE_BASIC_TYPES
+# define FFI_EXTERN FFI_API
+#else
+# define FFI_EXTERN extern FFI_API
+#endif
+
+#ifndef LIBFFI_HIDE_BASIC_TYPES
+#if SCHAR_MAX == 127
+# define ffi_type_uchar ffi_type_uint8
+# define ffi_type_schar ffi_type_sint8
+#else
+ #error "char size not supported"
+#endif
+
+#if SHRT_MAX == 32767
+# define ffi_type_ushort ffi_type_uint16
+# define ffi_type_sshort ffi_type_sint16
+#elif SHRT_MAX == 2147483647
+# define ffi_type_ushort ffi_type_uint32
+# define ffi_type_sshort ffi_type_sint32
+#else
+ #error "short size not supported"
+#endif
+
+#if INT_MAX == 32767
+# define ffi_type_uint ffi_type_uint16
+# define ffi_type_sint ffi_type_sint16
+#elif INT_MAX == 2147483647
+# define ffi_type_uint ffi_type_uint32
+# define ffi_type_sint ffi_type_sint32
+#elif INT_MAX == 9223372036854775807
+# define ffi_type_uint ffi_type_uint64
+# define ffi_type_sint ffi_type_sint64
+#else
+ #error "int size not supported"
+#endif
+
+#if LONG_MAX == 2147483647
+# if FFI_LONG_LONG_MAX != FFI_64_BIT_MAX
+ #error "no 64-bit data type supported"
+# endif
+#elif LONG_MAX != FFI_64_BIT_MAX
+ #error "long size not supported"
+#endif
+
+#if LONG_MAX == 2147483647
+# define ffi_type_ulong ffi_type_uint32
+# define ffi_type_slong ffi_type_sint32
+#elif LONG_MAX == FFI_64_BIT_MAX
+# define ffi_type_ulong ffi_type_uint64
+# define ffi_type_slong ffi_type_sint64
+#else
+ #error "long size not supported"
+#endif
+
+/* These are defined in types.c. */
+FFI_EXTERN ffi_type ffi_type_void;
+FFI_EXTERN ffi_type ffi_type_uint8;
+FFI_EXTERN ffi_type ffi_type_sint8;
+FFI_EXTERN ffi_type ffi_type_uint16;
+FFI_EXTERN ffi_type ffi_type_sint16;
+FFI_EXTERN ffi_type ffi_type_uint32;
+FFI_EXTERN ffi_type ffi_type_sint32;
+FFI_EXTERN ffi_type ffi_type_uint64;
+FFI_EXTERN ffi_type ffi_type_sint64;
+FFI_EXTERN ffi_type ffi_type_float;
+FFI_EXTERN ffi_type ffi_type_double;
+FFI_EXTERN ffi_type ffi_type_pointer;
+
+#if 0
+FFI_EXTERN ffi_type ffi_type_longdouble;
+#else
+#define ffi_type_longdouble ffi_type_double
+#endif
+
+#ifdef FFI_TARGET_HAS_COMPLEX_TYPE
+FFI_EXTERN ffi_type ffi_type_complex_float;
+FFI_EXTERN ffi_type ffi_type_complex_double;
+#if 0
+FFI_EXTERN ffi_type ffi_type_complex_longdouble;
+#else
+#define ffi_type_complex_longdouble ffi_type_complex_double
+#endif
+#endif
+#endif /* LIBFFI_HIDE_BASIC_TYPES */
+
+typedef enum {
+ FFI_OK = 0,
+ FFI_BAD_TYPEDEF,
+ FFI_BAD_ABI
+} ffi_status;
+
+typedef struct {
+ ffi_abi abi;
+ unsigned nargs;
+ ffi_type **arg_types;
+ ffi_type *rtype;
+ unsigned bytes;
+ unsigned flags;
+#ifdef FFI_EXTRA_CIF_FIELDS
+ FFI_EXTRA_CIF_FIELDS;
+#endif
+} ffi_cif;
+
+/* ---- Definitions for the raw API -------------------------------------- */
+
+#ifndef FFI_SIZEOF_ARG
+# if LONG_MAX == 2147483647
+# define FFI_SIZEOF_ARG 4
+# elif LONG_MAX == FFI_64_BIT_MAX
+# define FFI_SIZEOF_ARG 8
+# endif
+#endif
+
+#ifndef FFI_SIZEOF_JAVA_RAW
+# define FFI_SIZEOF_JAVA_RAW FFI_SIZEOF_ARG
+#endif
+
+typedef union {
+ ffi_sarg sint;
+ ffi_arg uint;
+ float flt;
+ char data[FFI_SIZEOF_ARG];
+ void* ptr;
+} ffi_raw;
+
+#if FFI_SIZEOF_JAVA_RAW == 4 && FFI_SIZEOF_ARG == 8
+/* This is a special case for mips64/n32 ABI (and perhaps others) where
+ sizeof(void *) is 4 and FFI_SIZEOF_ARG is 8. */
+typedef union {
+ signed int sint;
+ unsigned int uint;
+ float flt;
+ char data[FFI_SIZEOF_JAVA_RAW];
+ void* ptr;
+} ffi_java_raw;
+#else
+typedef ffi_raw ffi_java_raw;
+#endif
+
+
+FFI_API
+void ffi_raw_call (ffi_cif *cif,
+ void (*fn)(void),
+ void *rvalue,
+ ffi_raw *avalue);
+
+FFI_API void ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw);
+FFI_API void ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args);
+FFI_API size_t ffi_raw_size (ffi_cif *cif);
+
+/* This is analogous to the raw API, except it uses Java parameter
+ packing, even on 64-bit machines. I.e. on 64-bit machines longs
+ and doubles are followed by an empty 64-bit word. */
+
+#if !FFI_NATIVE_RAW_API
+FFI_API
+void ffi_java_raw_call (ffi_cif *cif,
+ void (*fn)(void),
+ void *rvalue,
+ ffi_java_raw *avalue);
+#endif
+
+FFI_API
+void ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_java_raw *raw);
+FFI_API
+void ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_java_raw *raw, void **args);
+FFI_API
+size_t ffi_java_raw_size (ffi_cif *cif);
+
+/* ---- Definitions for closures ----------------------------------------- */
+
+#if FFI_CLOSURES
+
+#ifdef _MSC_VER
+__declspec(align(8))
+#endif
+typedef struct {
+#if 0
+ void *trampoline_table;
+ void *trampoline_table_entry;
+#else
+ char tramp[FFI_TRAMPOLINE_SIZE];
+#endif
+ ffi_cif *cif;
+ void (*fun)(ffi_cif*,void*,void**,void*);
+ void *user_data;
+} ffi_closure
+#ifdef __GNUC__
+ __attribute__((aligned (8)))
+#endif
+ ;
+
+#ifndef __GNUC__
+# ifdef __sgi
+# pragma pack 0
+# endif
+#endif
+
+FFI_API void *ffi_closure_alloc (size_t size, void **code);
+FFI_API void ffi_closure_free (void *);
+
+FFI_API ffi_status
+ffi_prep_closure (ffi_closure*,
+ ffi_cif *,
+ void (*fun)(ffi_cif*,void*,void**,void*),
+ void *user_data)
+#if defined(__GNUC__) && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 405)
+ __attribute__((deprecated ("use ffi_prep_closure_loc instead")))
+#elif defined(__GNUC__) && __GNUC__ >= 3
+ __attribute__((deprecated))
+#endif
+ ;
+
+FFI_API ffi_status
+ffi_prep_closure_loc (ffi_closure*,
+ ffi_cif *,
+ void (*fun)(ffi_cif*,void*,void**,void*),
+ void *user_data,
+ void*codeloc);
+
+#ifdef __sgi
+# pragma pack 8
+#endif
+typedef struct {
+#if 0
+ void *trampoline_table;
+ void *trampoline_table_entry;
+#else
+ char tramp[FFI_TRAMPOLINE_SIZE];
+#endif
+ ffi_cif *cif;
+
+#if !FFI_NATIVE_RAW_API
+
+ /* If this is enabled, then a raw closure has the same layout
+ as a regular closure. We use this to install an intermediate
+ handler to do the transaltion, void** -> ffi_raw*. */
+
+ void (*translate_args)(ffi_cif*,void*,void**,void*);
+ void *this_closure;
+
+#endif
+
+ void (*fun)(ffi_cif*,void*,ffi_raw*,void*);
+ void *user_data;
+
+} ffi_raw_closure;
+
+typedef struct {
+#if 0
+ void *trampoline_table;
+ void *trampoline_table_entry;
+#else
+ char tramp[FFI_TRAMPOLINE_SIZE];
+#endif
+
+ ffi_cif *cif;
+
+#if !FFI_NATIVE_RAW_API
+
+ /* If this is enabled, then a raw closure has the same layout
+ as a regular closure. We use this to install an intermediate
+ handler to do the translation, void** -> ffi_raw*. */
+
+ void (*translate_args)(ffi_cif*,void*,void**,void*);
+ void *this_closure;
+
+#endif
+
+ void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*);
+ void *user_data;
+
+} ffi_java_raw_closure;
+
+FFI_API ffi_status
+ffi_prep_raw_closure (ffi_raw_closure*,
+ ffi_cif *cif,
+ void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
+ void *user_data);
+
+FFI_API ffi_status
+ffi_prep_raw_closure_loc (ffi_raw_closure*,
+ ffi_cif *cif,
+ void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
+ void *user_data,
+ void *codeloc);
+
+#if !FFI_NATIVE_RAW_API
+FFI_API ffi_status
+ffi_prep_java_raw_closure (ffi_java_raw_closure*,
+ ffi_cif *cif,
+ void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*),
+ void *user_data);
+
+FFI_API ffi_status
+ffi_prep_java_raw_closure_loc (ffi_java_raw_closure*,
+ ffi_cif *cif,
+ void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*),
+ void *user_data,
+ void *codeloc);
+#endif
+
+#endif /* FFI_CLOSURES */
+
+#if FFI_GO_CLOSURES
+
+typedef struct {
+ void *tramp;
+ ffi_cif *cif;
+ void (*fun)(ffi_cif*,void*,void**,void*);
+} ffi_go_closure;
+
+FFI_API ffi_status ffi_prep_go_closure (ffi_go_closure*, ffi_cif *,
+ void (*fun)(ffi_cif*,void*,void**,void*));
+
+FFI_API void ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
+ void **avalue, void *closure);
+
+#endif /* FFI_GO_CLOSURES */
+
+/* ---- Public interface definition -------------------------------------- */
+
+FFI_API
+ffi_status ffi_prep_cif(ffi_cif *cif,
+ ffi_abi abi,
+ unsigned int nargs,
+ ffi_type *rtype,
+ ffi_type **atypes);
+
+FFI_API
+ffi_status ffi_prep_cif_var(ffi_cif *cif,
+ ffi_abi abi,
+ unsigned int nfixedargs,
+ unsigned int ntotalargs,
+ ffi_type *rtype,
+ ffi_type **atypes);
+
+FFI_API
+void ffi_call(ffi_cif *cif,
+ void (*fn)(void),
+ void *rvalue,
+ void **avalue);
+
+FFI_API
+ffi_status ffi_get_struct_offsets (ffi_abi abi, ffi_type *struct_type,
+ size_t *offsets);
+
+/* Useful for eliminating compiler warnings. */
+#define FFI_FN(f) ((void (*)(void))f)
+
+/* ---- Definitions shared with assembly code ---------------------------- */
+
+#endif
+
+/* If these change, update src/mips/ffitarget.h. */
+#define FFI_TYPE_VOID 0
+#define FFI_TYPE_INT 1
+#define FFI_TYPE_FLOAT 2
+#define FFI_TYPE_DOUBLE 3
+#if 0
+#define FFI_TYPE_LONGDOUBLE 4
+#else
+#define FFI_TYPE_LONGDOUBLE FFI_TYPE_DOUBLE
+#endif
+#define FFI_TYPE_UINT8 5
+#define FFI_TYPE_SINT8 6
+#define FFI_TYPE_UINT16 7
+#define FFI_TYPE_SINT16 8
+#define FFI_TYPE_UINT32 9
+#define FFI_TYPE_SINT32 10
+#define FFI_TYPE_UINT64 11
+#define FFI_TYPE_SINT64 12
+#define FFI_TYPE_STRUCT 13
+#define FFI_TYPE_POINTER 14
+#define FFI_TYPE_COMPLEX 15
+
+/* This should always refer to the last type code (for sanity checks). */
+#define FFI_TYPE_LAST FFI_TYPE_COMPLEX
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/libffi_arm64/include/fficonfig.h b/c/libffi_arm64/include/fficonfig.h
new file mode 100644
index 0000000..5768c29
--- /dev/null
+++ b/c/libffi_arm64/include/fficonfig.h
@@ -0,0 +1,215 @@
+/* fficonfig.h. Generated from fficonfig.h.in by configure. */
+/* fficonfig.h.in. Generated from configure.ac by autoheader. */
+
+/* Define if building universal (internal helper macro) */
+/* #undef AC_APPLE_UNIVERSAL_BUILD */
+
+/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
+ systems. This function is required for `alloca.c' support on those systems.
+ */
+/* #undef CRAY_STACKSEG_END */
+
+/* Define to 1 if using `alloca.c'. */
+/* #undef C_ALLOCA */
+
+/* Define to the flags needed for the .section .eh_frame directive. */
+/* #undef EH_FRAME_FLAGS */
+
+/* Define this if you want extra debugging. */
+/* #undef FFI_DEBUG */
+
+/* Cannot use PROT_EXEC on this target, so, we revert to alternative means */
+/* #undef FFI_EXEC_TRAMPOLINE_TABLE */
+
+/* Define this if you want to enable pax emulated trampolines */
+/* #undef FFI_MMAP_EXEC_EMUTRAMP_PAX */
+
+/* Cannot use malloc on this target, so, we revert to alternative means */
+/* #undef FFI_MMAP_EXEC_WRIT */
+
+/* Define this if you do not want support for the raw API. */
+/* #undef FFI_NO_RAW_API */
+
+/* Define this if you do not want support for aggregate types. */
+/* #undef FFI_NO_STRUCTS */
+
+/* Define to 1 if you have `alloca', as a function or macro. */
+#define HAVE_ALLOCA 1
+
+/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
+ */
+/* #undef HAVE_ALLOCA_H */
+
+/* Define if your assembler supports .cfi_* directives. */
+/* #undef HAVE_AS_CFI_PSEUDO_OP */
+
+/* Define if your assembler supports .register. */
+/* #undef HAVE_AS_REGISTER_PSEUDO_OP */
+
+/* Define if the compiler uses zarch features. */
+/* #undef HAVE_AS_S390_ZARCH */
+
+/* Define if your assembler and linker support unaligned PC relative relocs.
+ */
+/* #undef HAVE_AS_SPARC_UA_PCREL */
+
+/* Define if your assembler supports unwind section type. */
+/* #undef HAVE_AS_X86_64_UNWIND_SECTION_TYPE */
+
+/* Define if your assembler supports PC relative relocs. */
+/* #undef HAVE_AS_X86_PCREL */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+/* #undef HAVE_DLFCN_H */
+
+/* Define if __attribute__((visibility("hidden"))) is supported. */
+/* #undef HAVE_HIDDEN_VISIBILITY_ATTRIBUTE */
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define if you have the long double type and it is bigger than a double */
+/* #undef HAVE_LONG_DOUBLE */
+
+/* Define if you support more than one size of the long double type */
+/* #undef HAVE_LONG_DOUBLE_VARIANT */
+
+/* Define to 1 if you have the `memcpy' function. */
+/* #undef HAVE_MEMCPY */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `mkostemp' function. */
+/* #undef HAVE_MKOSTEMP */
+
+/* Define to 1 if you have the `mmap' function. */
+/* #undef HAVE_MMAP */
+
+/* Define if mmap with MAP_ANON(YMOUS) works. */
+/* #undef HAVE_MMAP_ANON */
+
+/* Define if mmap of /dev/zero works. */
+/* #undef HAVE_MMAP_DEV_ZERO */
+
+/* Define if read-only mmap of a plain file works. */
+/* #undef HAVE_MMAP_FILE */
+
+/* Define if .eh_frame sections should be read-only. */
+/* #undef HAVE_RO_EH_FRAME */
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+/* #undef HAVE_STRINGS_H */
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/mman.h> header file. */
+/* #undef HAVE_SYS_MMAN_H */
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+/* #undef HAVE_UNISTD_H */
+
+/* Define to 1 if GNU symbol versioning is used for libatomic. */
+/* #undef LIBFFI_GNU_SYMBOL_VERSIONING */
+
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
+#define LT_OBJDIR ".libs/"
+
+/* Name of package */
+#define PACKAGE "libffi"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "http://github.com/libffi/libffi/issues"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "libffi"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "libffi 3.3-rc0"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "libffi"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "3.3-rc0"
+
+/* The size of `double', as computed by sizeof. */
+#define SIZEOF_DOUBLE 8
+
+/* The size of `long double', as computed by sizeof. */
+#define SIZEOF_LONG_DOUBLE 8
+
+/* The size of `size_t', as computed by sizeof. */
+#define SIZEOF_SIZE_T 8
+
+/* If using the C implementation of alloca, define if you know the
+ direction of stack growth for your system; otherwise it will be
+ automatically deduced at runtime.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown */
+/* #undef STACK_DIRECTION */
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define if symbols are underscored. */
+/* #undef SYMBOL_UNDERSCORE */
+
+/* Define this if you are using Purify and want to suppress spurious messages.
+ */
+/* #undef USING_PURIFY */
+
+/* Version number of package */
+#define VERSION "3.3-rc0"
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+ significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+# define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+/* # undef WORDS_BIGENDIAN */
+# endif
+#endif
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+
+#ifdef HAVE_HIDDEN_VISIBILITY_ATTRIBUTE
+#ifdef LIBFFI_ASM
+#ifdef __APPLE__
+#define FFI_HIDDEN(name) .private_extern name
+#else
+#define FFI_HIDDEN(name) .hidden name
+#endif
+#else
+#define FFI_HIDDEN __attribute__ ((visibility ("hidden")))
+#endif
+#else
+#ifdef LIBFFI_ASM
+#define FFI_HIDDEN(name)
+#else
+#define FFI_HIDDEN
+#endif
+#endif
+
diff --git a/c/libffi_arm64/include/ffitarget.h b/c/libffi_arm64/include/ffitarget.h
new file mode 100644
index 0000000..ecb6d2d
--- /dev/null
+++ b/c/libffi_arm64/include/ffitarget.h
@@ -0,0 +1,92 @@
+/* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+``Software''), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef LIBFFI_TARGET_H
+#define LIBFFI_TARGET_H
+
+#ifndef LIBFFI_H
+#error "Please do not include ffitarget.h directly into your source. Use ffi.h instead."
+#endif
+
+#ifndef LIBFFI_ASM
+#ifdef __ILP32__
+#define FFI_SIZEOF_ARG 8
+#define FFI_SIZEOF_JAVA_RAW 4
+typedef unsigned long long ffi_arg;
+typedef signed long long ffi_sarg;
+#elif defined(_M_ARM64)
+#define FFI_SIZEOF_ARG 8
+typedef unsigned long long ffi_arg;
+typedef signed long long ffi_sarg;
+#else
+typedef unsigned long ffi_arg;
+typedef signed long ffi_sarg;
+#endif
+
+typedef enum ffi_abi
+ {
+ FFI_FIRST_ABI = 0,
+ FFI_SYSV,
+ FFI_LAST_ABI,
+ FFI_DEFAULT_ABI = FFI_SYSV
+ } ffi_abi;
+#endif
+
+/* ---- Definitions for closures ----------------------------------------- */
+
+#define FFI_CLOSURES 1
+#define FFI_NATIVE_RAW_API 0
+
+#if defined (FFI_EXEC_TRAMPOLINE_TABLE) && FFI_EXEC_TRAMPOLINE_TABLE
+
+#ifdef __MACH__
+#define FFI_TRAMPOLINE_SIZE 16
+#define FFI_TRAMPOLINE_CLOSURE_OFFSET 16
+#else
+#error "No trampoline table implementation"
+#endif
+
+#else
+#define FFI_TRAMPOLINE_SIZE 24
+#define FFI_TRAMPOLINE_CLOSURE_OFFSET FFI_TRAMPOLINE_SIZE
+#endif
+
+#ifdef _M_ARM64
+#define FFI_EXTRA_CIF_FIELDS unsigned is_variadic
+#endif
+
+/* ---- Internal ---- */
+
+#if defined (__APPLE__)
+#define FFI_TARGET_SPECIFIC_VARIADIC
+#define FFI_EXTRA_CIF_FIELDS unsigned aarch64_nfixedargs
+#elif !defined(_M_ARM64)
+/* iOS and Windows reserve x18 for the system. Disable Go closures until
+ a new static chain is chosen. */
+#define FFI_GO_CLOSURES 1
+#endif
+
+#ifndef _M_ARM64
+/* No complex type on Windows */
+#define FFI_TARGET_HAS_COMPLEX_TYPE
+#endif
+
+#endif
diff --git a/c/libffi_msvc/LICENSE b/c/libffi_x86_x64/LICENSE
index f591795..f591795 100644
--- a/c/libffi_msvc/LICENSE
+++ b/c/libffi_x86_x64/LICENSE
diff --git a/c/libffi_msvc/README b/c/libffi_x86_x64/README
index 97a12cf..97a12cf 100644
--- a/c/libffi_msvc/README
+++ b/c/libffi_x86_x64/README
diff --git a/c/libffi_msvc/README.ctypes b/c/libffi_x86_x64/README.ctypes
index 17e8a40..17e8a40 100644
--- a/c/libffi_msvc/README.ctypes
+++ b/c/libffi_x86_x64/README.ctypes
diff --git a/c/libffi_msvc/ffi.c b/c/libffi_x86_x64/ffi.c
index 836f171..b9e324f 100644
--- a/c/libffi_msvc/ffi.c
+++ b/c/libffi_x86_x64/ffi.c
@@ -103,7 +103,7 @@ void ffi_prep_args(char *stack, extended_cif *ecif)
}
}
#ifdef _WIN64
- else if (z > 8)
+ else if (z != 1 && z != 2 && z != 4 && z != 8)
{
/* On Win64, if a single argument takes more than 8 bytes,
then it is always passed by reference. */
@@ -144,9 +144,11 @@ ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
/* MSVC returns small structures in registers. Put in cif->flags
the value FFI_TYPE_STRUCT only if the structure is big enough;
otherwise, put the 4- or 8-bytes integer type. */
- if (cif->rtype->size <= 4)
+ if (cif->rtype->size == 1 ||
+ cif->rtype->size == 2 ||
+ cif->rtype->size == 4)
cif->flags = FFI_TYPE_INT;
- else if (cif->rtype->size <= 8)
+ else if (cif->rtype->size == 8)
cif->flags = FFI_TYPE_SINT64;
else
cif->flags = FFI_TYPE_STRUCT;
@@ -287,16 +289,12 @@ ffi_closure_SYSV (ffi_closure *closure, char *argp)
_asm fld DWORD PTR [eax] ;
// asm ("flds (%0)" : : "r" (resp) : "st" );
}
- else if (rtype == FFI_TYPE_DOUBLE)
+ else if (rtype == FFI_TYPE_DOUBLE || rtype == FFI_TYPE_LONGDOUBLE)
{
_asm mov eax, resp ;
_asm fld QWORD PTR [eax] ;
// asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" );
}
- else if (rtype == FFI_TYPE_LONGDOUBLE)
- {
-// asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" );
- }
else if (rtype == FFI_TYPE_SINT64)
{
_asm mov edx, resp ;
@@ -307,6 +305,10 @@ ffi_closure_SYSV (ffi_closure *closure, char *argp)
// : : "r"(resp)
// : "eax", "edx");
}
+ else if (rtype == FFI_TYPE_STRUCT)
+ {
+ _asm mov eax, resp ;
+ }
#else
/* now, do a generic return based on the value of rtype */
if (rtype == FFI_TYPE_INT)
@@ -317,14 +319,10 @@ ffi_closure_SYSV (ffi_closure *closure, char *argp)
{
asm ("flds (%0)" : : "r" (resp) : "st" );
}
- else if (rtype == FFI_TYPE_DOUBLE)
+ else if (rtype == FFI_TYPE_DOUBLE || rtype == FFI_TYPE_LONGDOUBLE)
{
asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" );
}
- else if (rtype == FFI_TYPE_LONGDOUBLE)
- {
- asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" );
- }
else if (rtype == FFI_TYPE_SINT64)
{
asm ("movl 0(%0),%%eax;"
@@ -332,6 +330,10 @@ ffi_closure_SYSV (ffi_closure *closure, char *argp)
: : "r"(resp)
: "eax", "edx");
}
+ else if (rtype == FFI_TYPE_STRUCT)
+ {
+ asm ("movl %0,%%eax" : : "r" (resp) : "eax");
+ }
#endif
#endif
@@ -340,6 +342,8 @@ ffi_closure_SYSV (ffi_closure *closure, char *argp)
result types except for floats; we have to 'mov xmm0, rax' in the
caller to correct this.
*/
+ if (rtype == FFI_TYPE_STRUCT)
+ return resp;
return *(void **)resp;
#endif
}
@@ -378,7 +382,7 @@ ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
/* because we're little endian, this is what it turns into. */
#ifdef _WIN64
- if (z > 8)
+ if (z != 1 && z != 2 && z != 4 && z != 8)
{
/* On Win64, if a single argument takes more than 8 bytes,
then it is always passed by reference. */
@@ -447,6 +451,11 @@ ffi_prep_closure_loc (ffi_closure* closure,
|| cif->arg_types[3]->type == FFI_TYPE_DOUBLE))
mask |= 8;
+ /* if we return a non-small struct, then the first argument is a pointer
+ * to the return area, and all real arguments are shifted by one */
+ if (cif->flags == FFI_TYPE_STRUCT)
+ mask = (mask & ~8) << 1;
+
/* 41 BB ---- mov r11d,mask */
BYTES("\x41\xBB"); INT(mask);
diff --git a/c/libffi_msvc/ffi.h b/c/libffi_x86_x64/ffi.h
index 97cdb59..97cdb59 100644
--- a/c/libffi_msvc/ffi.h
+++ b/c/libffi_x86_x64/ffi.h
diff --git a/c/libffi_msvc/ffi_common.h b/c/libffi_x86_x64/ffi_common.h
index 43fb83b..43fb83b 100644
--- a/c/libffi_msvc/ffi_common.h
+++ b/c/libffi_x86_x64/ffi_common.h
diff --git a/c/libffi_msvc/fficonfig.h b/c/libffi_x86_x64/fficonfig.h
index c14f653..c14f653 100644
--- a/c/libffi_msvc/fficonfig.h
+++ b/c/libffi_x86_x64/fficonfig.h
diff --git a/c/libffi_msvc/ffitarget.h b/c/libffi_x86_x64/ffitarget.h
index 85f5ee8..85f5ee8 100644
--- a/c/libffi_msvc/ffitarget.h
+++ b/c/libffi_x86_x64/ffitarget.h
diff --git a/c/libffi_msvc/prep_cif.c b/c/libffi_x86_x64/prep_cif.c
index 5dacfff..df94a98 100644
--- a/c/libffi_msvc/prep_cif.c
+++ b/c/libffi_x86_x64/prep_cif.c
@@ -117,7 +117,10 @@ ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif,
/* Make space for the return structure pointer */
if (cif->rtype->type == FFI_TYPE_STRUCT
#ifdef _WIN32
- && (cif->rtype->size > 8) /* MSVC returns small structs in registers */
+ && (cif->rtype->size != 1) /* MSVC returns small structs in registers */
+ && (cif->rtype->size != 2)
+ && (cif->rtype->size != 4)
+ && (cif->rtype->size != 8)
#endif
#ifdef SPARC
&& (cif->abi != FFI_V9 || cif->rtype->size > 32)
diff --git a/c/libffi_msvc/types.c b/c/libffi_x86_x64/types.c
index 4433ac2..4433ac2 100644
--- a/c/libffi_msvc/types.c
+++ b/c/libffi_x86_x64/types.c
diff --git a/c/libffi_msvc/win32.c b/c/libffi_x86_x64/win32.c
index d1149a8..d1149a8 100644
--- a/c/libffi_msvc/win32.c
+++ b/c/libffi_x86_x64/win32.c
diff --git a/c/libffi_msvc/win64.asm b/c/libffi_x86_x64/win64.asm
index 301188b..301188b 100644
--- a/c/libffi_msvc/win64.asm
+++ b/c/libffi_x86_x64/win64.asm
diff --git a/c/libffi_msvc/win64.obj b/c/libffi_x86_x64/win64.obj
index 38d3cd1..38d3cd1 100644
--- a/c/libffi_msvc/win64.obj
+++ b/c/libffi_x86_x64/win64.obj
Binary files differ
diff --git a/c/misc_win32.h b/c/misc_win32.h
index 07b76c1..156cf5d 100644
--- a/c/misc_win32.h
+++ b/c/misc_win32.h
@@ -124,8 +124,10 @@ static PyObject *b_getwinerror(PyObject *self, PyObject *args, PyObject *kwds)
s_buf[--len] = L'\0';
message = PyUnicode_FromWideChar(s_buf, len);
}
- if (message != NULL)
+ if (message != NULL) {
v = Py_BuildValue("(iO)", err, message);
+ Py_DECREF(message);
+ }
else
v = NULL;
LocalFree(s_buf);
@@ -168,7 +170,6 @@ static PyObject *b_getwinerror(PyObject *self, PyObject *args, PyObject *kwds)
/* Only seen this in out of mem situations */
sprintf(s_small_buf, "Windows Error 0x%X", err);
s = s_small_buf;
- s_buf = NULL;
} else {
s = s_buf;
/* remove trailing cr/lf and dots */
diff --git a/c/realize_c_type.c b/c/realize_c_type.c
index 082c488..82629b7 100644
--- a/c/realize_c_type.c
+++ b/c/realize_c_type.c
@@ -413,19 +413,12 @@ _realize_c_struct_or_union(builder_c_t *builder, int sindex)
}
static PyObject *
-realize_c_type_or_func(builder_c_t *builder,
- _cffi_opcode_t opcodes[], int index)
+realize_c_type_or_func_now(builder_c_t *builder, _cffi_opcode_t op,
+ _cffi_opcode_t opcodes[], int index)
{
PyObject *x, *y, *z;
- _cffi_opcode_t op = opcodes[index];
Py_ssize_t length = -1;
- if ((((uintptr_t)op) & 1) == 0) {
- x = (PyObject *)op;
- Py_INCREF(x);
- return x;
- }
-
switch (_CFFI_GETOP(op)) {
case _CFFI_OP_PRIMITIVE:
@@ -643,6 +636,36 @@ realize_c_type_or_func(builder_c_t *builder,
return NULL;
}
+ return x;
+}
+
+static int _realize_recursion_level;
+
+static PyObject *
+realize_c_type_or_func(builder_c_t *builder,
+ _cffi_opcode_t opcodes[], int index)
+{
+ PyObject *x;
+ _cffi_opcode_t op = opcodes[index];
+
+ if ((((uintptr_t)op) & 1) == 0) {
+ x = (PyObject *)op;
+ Py_INCREF(x);
+ return x;
+ }
+
+ if (_realize_recursion_level >= 1000) {
+ PyErr_Format(PyExc_RuntimeError,
+ "type-building recursion too deep or infinite. "
+ "This is known to occur e.g. in ``struct s { void(*callable)"
+ "(struct s); }''. Please report if you get this error and "
+ "really need support for your case.");
+ return NULL;
+ }
+ _realize_recursion_level++;
+ x = realize_c_type_or_func_now(builder, op, opcodes, index);
+ _realize_recursion_level--;
+
if (x != NULL && opcodes == builder->ctx.types && opcodes[index] != x) {
assert((((uintptr_t)x) & 1) == 0);
assert((((uintptr_t)opcodes[index]) & 1) == 1);
@@ -650,7 +673,7 @@ realize_c_type_or_func(builder_c_t *builder,
opcodes[index] = x;
}
return x;
-};
+}
static CTypeDescrObject *
realize_c_func_return_type(builder_c_t *builder,
diff --git a/c/test_c.py b/c/test_c.py
index da5f751..654584d 100644
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -1,18 +1,23 @@
import py
+import pytest
+
def _setup_path():
import os, sys
- if '__pypy__' in sys.builtin_module_names:
- py.test.skip("_cffi_backend.c: not tested on top of pypy, "
- "use pypy/module/_cffi_backend/test/ instead.")
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
_setup_path()
from _cffi_backend import *
-from _cffi_backend import _testfunc, _get_types, _get_common_types, __version__
+from _cffi_backend import _get_types, _get_common_types
+try:
+ from _cffi_backend import _testfunc
+except ImportError:
+ def _testfunc(num):
+ pytest.skip("_testunc() not available")
+from _cffi_backend import __version__
# ____________________________________________________________
import sys
-assert __version__ == "1.12.2", ("This test_c.py file is for testing a version"
+assert __version__ == "1.15.0", ("This test_c.py file is for testing a version"
" of cffi that differs from the one that we"
" get from 'import _cffi_backend'")
if sys.version_info < (3,):
@@ -63,8 +68,10 @@ def find_and_load_library(name, flags=RTLD_NOW):
path = ctypes.util.find_library(name)
if path is None and name == 'c':
assert sys.platform == 'win32'
- assert sys.version_info >= (3,)
- py.test.skip("dlopen(None) cannot work on Windows with Python 3")
+ assert (sys.version_info >= (3,) or
+ '__pypy__' in sys.builtin_module_names)
+ py.test.skip("dlopen(None) cannot work on Windows "
+ "with PyPy or Python 3")
return load_library(path, flags)
def test_load_library():
@@ -107,7 +114,7 @@ def test_cast_to_signed_char():
p = new_primitive_type("signed char")
x = cast(p, -65 + 17*256)
assert repr(x) == "<cdata 'signed char' -65>"
- assert repr(type(x)) == "<%s '_cffi_backend.CData'>" % type_or_class
+ assert repr(type(x)) == "<%s '_cffi_backend._CDataBase'>" % type_or_class
assert int(x) == -65
x = cast(p, -66 + (1<<199)*256)
assert repr(x) == "<cdata 'signed char' -66>"
@@ -315,8 +322,10 @@ def test_reading_pointer_to_int():
assert p[0] == 0
p = newp(BPtr, 5000)
assert p[0] == 5000
- py.test.raises(IndexError, "p[1]")
- py.test.raises(IndexError, "p[-1]")
+ with pytest.raises(IndexError):
+ p[1]
+ with pytest.raises(IndexError):
+ p[-1]
def test_reading_pointer_to_float():
BFloat = new_primitive_type("float")
@@ -444,7 +453,8 @@ def test_cmp_none():
def test_invalid_indexing():
p = new_primitive_type("int")
x = cast(p, 42)
- py.test.raises(TypeError, "x[0]")
+ with pytest.raises(TypeError):
+ x[0]
def test_default_str():
BChar = new_primitive_type("char")
@@ -537,13 +547,16 @@ def test_array_instance():
assert len(a) == LENGTH
for i in range(LENGTH):
assert a[i] == 0
- py.test.raises(IndexError, "a[LENGTH]")
- py.test.raises(IndexError, "a[-1]")
+ with pytest.raises(IndexError):
+ a[LENGTH]
+ with pytest.raises(IndexError):
+ a[-1]
for i in range(LENGTH):
a[i] = i * i + 1
for i in range(LENGTH):
assert a[i] == i * i + 1
- e = py.test.raises(IndexError, "a[LENGTH+100] = 500")
+ with pytest.raises(IndexError) as e:
+ a[LENGTH+100] = 500
assert ('(expected %d < %d)' % (LENGTH+100, LENGTH)) in str(e.value)
py.test.raises(TypeError, int, a)
@@ -558,10 +571,14 @@ def test_array_of_unknown_length_instance():
a[i] -= i
for i in range(42):
assert a[i] == -i
- py.test.raises(IndexError, "a[42]")
- py.test.raises(IndexError, "a[-1]")
- py.test.raises(IndexError, "a[42] = 123")
- py.test.raises(IndexError, "a[-1] = 456")
+ with pytest.raises(IndexError):
+ a[42]
+ with pytest.raises(IndexError):
+ a[-1]
+ with pytest.raises(IndexError):
+ a[42] = 123
+ with pytest.raises(IndexError):
+ a[-1] = 456
def test_array_of_unknown_length_instance_with_initializer():
p = new_primitive_type("int")
@@ -609,10 +626,14 @@ def test_array_sub():
assert a == (p - 1)
BPtr = new_pointer_type(new_primitive_type("short"))
q = newp(BPtr, None)
- py.test.raises(TypeError, "p - q")
- py.test.raises(TypeError, "q - p")
- py.test.raises(TypeError, "a - q")
- e = py.test.raises(TypeError, "q - a")
+ with pytest.raises(TypeError):
+ p - q
+ with pytest.raises(TypeError):
+ q - p
+ with pytest.raises(TypeError):
+ a - q
+ with pytest.raises(TypeError) as e:
+ q - a
assert str(e.value) == "cannot subtract cdata 'short *' and cdata 'int *'"
def test_ptr_sub_unaligned():
@@ -625,8 +646,10 @@ def test_ptr_sub_unaligned():
assert b - a == (bi - 1240) // size_of_int()
assert a - b == (1240 - bi) // size_of_int()
else:
- py.test.raises(ValueError, "b - a")
- py.test.raises(ValueError, "a - b")
+ with pytest.raises(ValueError):
+ b - a
+ with pytest.raises(ValueError):
+ a - b
def test_cast_primitive_from_cdata():
p = new_primitive_type("int")
@@ -777,10 +800,12 @@ def test_struct_instance():
BStruct = new_struct_type("struct foo")
BStructPtr = new_pointer_type(BStruct)
p = cast(BStructPtr, 42)
- e = py.test.raises(AttributeError, "p.a1") # opaque
+ with pytest.raises(AttributeError) as e:
+ p.a1 # opaque
assert str(e.value) == ("cdata 'struct foo *' points to an opaque type: "
"cannot read fields")
- e = py.test.raises(AttributeError, "p.a1 = 10") # opaque
+ with pytest.raises(AttributeError) as e:
+ p.a1 = 10 # opaque
assert str(e.value) == ("cdata 'struct foo *' points to an opaque type: "
"cannot write fields")
@@ -792,30 +817,41 @@ def test_struct_instance():
s.a2 = 123
assert s.a1 == 0
assert s.a2 == 123
- py.test.raises(OverflowError, "s.a1 = sys.maxsize+1")
+ with pytest.raises(OverflowError):
+ s.a1 = sys.maxsize+1
assert s.a1 == 0
- e = py.test.raises(AttributeError, "p.foobar")
+ with pytest.raises(AttributeError) as e:
+ p.foobar
assert str(e.value) == "cdata 'struct foo *' has no field 'foobar'"
- e = py.test.raises(AttributeError, "p.foobar = 42")
+ with pytest.raises(AttributeError) as e:
+ p.foobar = 42
assert str(e.value) == "cdata 'struct foo *' has no field 'foobar'"
- e = py.test.raises(AttributeError, "s.foobar")
+ with pytest.raises(AttributeError) as e:
+ s.foobar
assert str(e.value) == "cdata 'struct foo' has no field 'foobar'"
- e = py.test.raises(AttributeError, "s.foobar = 42")
+ with pytest.raises(AttributeError) as e:
+ s.foobar = 42
assert str(e.value) == "cdata 'struct foo' has no field 'foobar'"
j = cast(BInt, 42)
- e = py.test.raises(AttributeError, "j.foobar")
+ with pytest.raises(AttributeError) as e:
+ j.foobar
assert str(e.value) == "cdata 'int' has no attribute 'foobar'"
- e = py.test.raises(AttributeError, "j.foobar = 42")
+ with pytest.raises(AttributeError) as e:
+ j.foobar = 42
assert str(e.value) == "cdata 'int' has no attribute 'foobar'"
j = cast(new_pointer_type(BInt), 42)
- e = py.test.raises(AttributeError, "j.foobar")
+ with pytest.raises(AttributeError) as e:
+ j.foobar
assert str(e.value) == "cdata 'int *' has no attribute 'foobar'"
- e = py.test.raises(AttributeError, "j.foobar = 42")
+ with pytest.raises(AttributeError) as e:
+ j.foobar = 42
assert str(e.value) == "cdata 'int *' has no attribute 'foobar'"
pp = newp(new_pointer_type(BStructPtr), p)
- e = py.test.raises(AttributeError, "pp.a1")
+ with pytest.raises(AttributeError) as e:
+ pp.a1
assert str(e.value) == "cdata 'struct foo * *' has no attribute 'a1'"
- e = py.test.raises(AttributeError, "pp.a1 = 42")
+ with pytest.raises(AttributeError) as e:
+ pp.a1 = 42
assert str(e.value) == "cdata 'struct foo * *' has no attribute 'a1'"
def test_union_instance():
@@ -1295,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('$')
@@ -1328,6 +1366,8 @@ def test_callback_exception():
try:
linecache.getline = lambda *args: 'LINE' # hack: speed up PyPy tests
sys.stderr = cStringIO.StringIO()
+ if hasattr(sys, '__unraisablehook__'): # work around pytest
+ sys.unraisablehook = sys.__unraisablehook__ # on recent CPythons
assert f(100) == 300
assert sys.stderr.getvalue() == ''
assert f(10000) == -42
@@ -1339,6 +1379,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
@@ -1347,6 +1395,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
@@ -1384,11 +1438,24 @@ 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()
seen = "not a list" # this makes the oops() function crash
assert ff(bigvalue) == -42
+ # the $ after the AttributeError message are for the suggestions that
+ # will be added in Python 3.10
assert matches(sys.stderr.getvalue(), """\
From cffi callback <function$Zcb1 at 0x$>:
Trying to convert the result back to C:
@@ -1399,7 +1466,18 @@ During the call to 'onerror', another exception occurred:
Traceback (most recent call last):
File "$", line $, in oops
$
-AttributeError: 'str' object has no attribute 'append'
+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
@@ -1434,7 +1512,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):
@@ -1636,7 +1714,8 @@ def test_enum_in_struct():
assert ("an integer is required" in msg or # CPython
"unsupported operand type for int(): 'NoneType'" in msg or # old PyPys
"expected integer, got NoneType object" in msg) # newer PyPys
- py.test.raises(TypeError, 'p.a1 = "def"')
+ with pytest.raises(TypeError):
+ p.a1 = "def"
if sys.version_info < (3,):
BEnum2 = new_enum_type(unicode("foo"), (unicode('abc'),), (5,), BInt)
assert string(cast(BEnum2, 5)) == 'abc'
@@ -1766,14 +1845,17 @@ def test_bitfield_instance():
p.a1 = -1
assert p.a1 == -1
p.a1 = 0
- py.test.raises(OverflowError, "p.a1 = 2")
+ with pytest.raises(OverflowError):
+ p.a1 = 2
assert p.a1 == 0
#
p.a1 = -1
p.a2 = 3
p.a3 = -4
- py.test.raises(OverflowError, "p.a3 = 4")
- e = py.test.raises(OverflowError, "p.a3 = -5")
+ with pytest.raises(OverflowError):
+ p.a3 = 4
+ with pytest.raises(OverflowError) as e:
+ p.a3 = -5
assert str(e.value) == ("value -5 outside the range allowed by the "
"bit field width: -4 <= x <= 3")
assert p.a1 == -1 and p.a2 == 3 and p.a3 == -4
@@ -1782,7 +1864,8 @@ def test_bitfield_instance():
# allows also setting the value "1" (it still gets read back as -1)
p.a1 = 1
assert p.a1 == -1
- e = py.test.raises(OverflowError, "p.a1 = -2")
+ with pytest.raises(OverflowError) as e:
+ p.a1 = -2
assert str(e.value) == ("value -2 outside the range allowed by the "
"bit field width: -1 <= x <= 1")
@@ -1842,14 +1925,17 @@ def test_assign_string():
assert string(a[2]) == b"."
a[2] = b"12345"
assert string(a[2]) == b"12345"
- e = py.test.raises(IndexError, 'a[2] = b"123456"')
+ with pytest.raises(IndexError) as e:
+ a[2] = b"123456"
assert 'char[5]' in str(e.value)
assert 'got 6 characters' in str(e.value)
def test_add_error():
x = cast(new_primitive_type("int"), 42)
- py.test.raises(TypeError, "x + 1")
- py.test.raises(TypeError, "x - 1")
+ with pytest.raises(TypeError):
+ x + 1
+ with pytest.raises(TypeError):
+ x - 1
def test_void_errors():
py.test.raises(ValueError, alignof, new_void_type())
@@ -2181,8 +2267,10 @@ def _test_wchar_variant(typename):
s = newp(BStructPtr)
s.a1 = u+'\x00'
assert s.a1 == u+'\x00'
- py.test.raises(TypeError, "s.a1 = b'a'")
- py.test.raises(TypeError, "s.a1 = bytechr(0xFF)")
+ with pytest.raises(TypeError):
+ s.a1 = b'a'
+ with pytest.raises(TypeError):
+ s.a1 = bytechr(0xFF)
s.a1 = u+'\u1234'
assert s.a1 == u+'\u1234'
if pyuni4:
@@ -2196,7 +2284,8 @@ def _test_wchar_variant(typename):
s.a1 = u+'\ud807\udf44'
assert s.a1 == u+'\U00011f44'
else:
- py.test.raises(TypeError, "s.a1 = u+'\U00012345'")
+ with pytest.raises(TypeError):
+ s.a1 = u+'\U00012345'
#
BWCharArray = new_array_type(BWCharP, None)
a = newp(BWCharArray, u+'hello \u1234 world')
@@ -2220,7 +2309,8 @@ def _test_wchar_variant(typename):
assert list(a) == expected
got = [a[i] for i in range(4)]
assert got == expected
- py.test.raises(IndexError, 'a[4]')
+ with pytest.raises(IndexError):
+ a[4]
#
w = cast(BWChar, 'a')
assert repr(w) == "<cdata '%s' %s'a'>" % (typename, mandatory_u_prefix)
@@ -2352,9 +2442,11 @@ def test_owning_repr():
def test_cannot_dereference_void():
BVoidP = new_pointer_type(new_void_type())
p = cast(BVoidP, 123456)
- py.test.raises(TypeError, "p[0]")
+ with pytest.raises(TypeError):
+ p[0]
p = cast(BVoidP, 0)
- py.test.raises((TypeError, RuntimeError), "p[0]")
+ with pytest.raises((TypeError, RuntimeError)):
+ p[0]
def test_iter():
BInt = new_primitive_type("int")
@@ -2377,12 +2469,12 @@ def test_cmp():
assert (q == p) is False
assert (q != p) is True
if strict_compare:
- py.test.raises(TypeError, "p < q")
- py.test.raises(TypeError, "p <= q")
- py.test.raises(TypeError, "q < p")
- py.test.raises(TypeError, "q <= p")
- py.test.raises(TypeError, "p > q")
- py.test.raises(TypeError, "p >= q")
+ with pytest.raises(TypeError): p < q
+ with pytest.raises(TypeError): p <= q
+ with pytest.raises(TypeError): q < p
+ with pytest.raises(TypeError): q <= p
+ with pytest.raises(TypeError): p > q
+ with pytest.raises(TypeError): p >= q
r = cast(BVoidP, p)
assert (p < r) is False
assert (p <= r) is True
@@ -2428,7 +2520,8 @@ def test_buffer():
try:
expected = b"hi there\x00"[i]
except IndexError:
- py.test.raises(IndexError, "buf[i]")
+ with pytest.raises(IndexError):
+ buf[i]
else:
assert buf[i] == bitem2bchr(expected)
# --mb_slice--
@@ -2455,15 +2548,18 @@ def test_buffer():
try:
expected[i] = bytechr(i & 0xff)
except IndexError:
- py.test.raises(IndexError, "buf[i] = bytechr(i & 0xff)")
+ with pytest.raises(IndexError):
+ buf[i] = bytechr(i & 0xff)
else:
buf[i] = bytechr(i & 0xff)
assert list(buf) == expected
# --mb_ass_slice--
buf[:] = b"hi there\x00"
assert list(buf) == list(c) == list(map(bitem2bchr, b"hi there\x00"))
- py.test.raises(ValueError, 'buf[:] = b"shorter"')
- py.test.raises(ValueError, 'buf[:] = b"this is much too long!"')
+ with pytest.raises(ValueError):
+ buf[:] = b"shorter"
+ with pytest.raises(ValueError):
+ buf[:] = b"this is much too long!"
buf[4:2] = b"" # no effect, but should work
assert buf[:] == b"hi there\x00"
buf[:2] = b"HI"
@@ -2499,8 +2595,8 @@ def test_errno():
assert get_errno() == 95
def test_errno_callback():
- if globals().get('PY_DOT_PY') == '2.5':
- py.test.skip("cannot run this test on py.py with Python 2.5")
+ if globals().get('PY_DOT_PY'):
+ py.test.skip("cannot run this test on py.py (e.g. fails on Windows)")
set_errno(95)
def cb():
e = get_errno()
@@ -2537,14 +2633,16 @@ def test_bug_delitem():
BChar = new_primitive_type("char")
BCharP = new_pointer_type(BChar)
x = newp(BCharP)
- py.test.raises(TypeError, "del x[0]")
+ with pytest.raises(TypeError):
+ del x[0]
def test_bug_delattr():
BLong = new_primitive_type("long")
BStruct = new_struct_type("struct foo")
complete_struct_or_union(BStruct, [('a1', BLong, -1)])
x = newp(new_pointer_type(BStruct))
- py.test.raises(AttributeError, "del x.a1")
+ with pytest.raises(AttributeError):
+ del x.a1
def test_variable_length_struct():
py.test.skip("later")
@@ -2562,7 +2660,8 @@ def test_variable_length_struct():
assert sizeof(x) == 6 * size_of_long()
x[4] = 123
assert x[4] == 123
- py.test.raises(IndexError, "x[5]")
+ with pytest.raises(IndexError):
+ x[5]
assert len(x.a2) == 5
#
py.test.raises(TypeError, newp, BStructP, [123])
@@ -2814,7 +2913,8 @@ def test_bool_forbidden_cases():
BCharP = new_pointer_type(new_primitive_type("char"))
p = newp(BCharP, b'X')
q = cast(BBoolP, p)
- py.test.raises(ValueError, "q[0]")
+ with pytest.raises(ValueError):
+ q[0]
py.test.raises(TypeError, newp, BBoolP, b'\x00')
assert newp(BBoolP, 0)[0] is False
assert newp(BBoolP, 1)[0] is True
@@ -3114,8 +3214,10 @@ def test_slice():
assert c[1] == 123
assert c[3] == 456
assert d[2] == 456
- py.test.raises(IndexError, "d[3]")
- py.test.raises(IndexError, "d[-1]")
+ with pytest.raises(IndexError):
+ d[3]
+ with pytest.raises(IndexError):
+ d[-1]
def test_slice_ptr():
BIntP = new_pointer_type(new_primitive_type("int"))
@@ -3133,7 +3235,8 @@ def test_slice_array_checkbounds():
c = newp(BIntArray, 5)
c[0:5]
assert len(c[5:5]) == 0
- py.test.raises(IndexError, "c[-1:1]")
+ with pytest.raises(IndexError):
+ c[-1:1]
cp = c + 0
cp[-1:1]
@@ -3141,17 +3244,23 @@ def test_nonstandard_slice():
BIntP = new_pointer_type(new_primitive_type("int"))
BIntArray = new_array_type(BIntP, None)
c = newp(BIntArray, 5)
- e = py.test.raises(IndexError, "c[:5]")
+ with pytest.raises(IndexError) as e:
+ c[:5]
assert str(e.value) == "slice start must be specified"
- e = py.test.raises(IndexError, "c[4:]")
+ with pytest.raises(IndexError) as e:
+ c[4:]
assert str(e.value) == "slice stop must be specified"
- e = py.test.raises(IndexError, "c[1:2:3]")
+ with pytest.raises(IndexError) as e:
+ c[1:2:3]
assert str(e.value) == "slice with step not supported"
- e = py.test.raises(IndexError, "c[1:2:1]")
+ with pytest.raises(IndexError) as e:
+ c[1:2:1]
assert str(e.value) == "slice with step not supported"
- e = py.test.raises(IndexError, "c[4:2]")
+ with pytest.raises(IndexError) as e:
+ c[4:2]
assert str(e.value) == "slice start > stop"
- e = py.test.raises(IndexError, "c[6:6]")
+ with pytest.raises(IndexError) as e:
+ c[6:6]
assert str(e.value) == "index too large (expected 6 <= 5)"
def test_setslice():
@@ -3165,9 +3274,11 @@ def test_setslice():
assert list(c) == [0, 100, 300, 400, 0]
cp[-1:1] = iter([500, 600])
assert list(c) == [0, 100, 500, 600, 0]
- py.test.raises(ValueError, "cp[-1:1] = [1000]")
+ with pytest.raises(ValueError):
+ cp[-1:1] = [1000]
assert list(c) == [0, 100, 1000, 600, 0]
- py.test.raises(ValueError, "cp[-1:1] = (700, 800, 900)")
+ with pytest.raises(ValueError):
+ cp[-1:1] = (700, 800, 900)
assert list(c) == [0, 100, 700, 800, 0]
def test_setslice_array():
@@ -3427,10 +3538,14 @@ def test_struct_array_no_length():
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")
+ with pytest.raises(IndexError):
+ p.y[4]
+ with pytest.raises(TypeError):
+ p.y = cast(BIntP, 0)
+ with pytest.raises(TypeError):
+ p.y = 15
+ with pytest.raises(TypeError):
+ p.y = None
#
# accepting this may be specified by the C99 standard,
# or a GCC strangeness...
@@ -3452,6 +3567,15 @@ def test_struct_array_no_length():
assert p.a[1] == 20
assert p.a[2] == 30
assert p.a[3] == 0
+ #
+ # struct of struct of varsized array
+ BStruct2 = new_struct_type("bar")
+ complete_struct_or_union(BStruct2, [('head', BInt),
+ ('tail', BStruct)])
+ for i in range(2): # try to detect heap overwrites
+ p = newp(new_pointer_type(BStruct2), [100, [200, list(range(50))]])
+ assert p.tail.y[49] == 49
+
def test_struct_array_no_length_explicit_position():
BInt = new_primitive_type("int")
@@ -3526,8 +3650,10 @@ def test_ass_slice():
p[2:5] = [b"*", b"Z", b"T"]
p[1:3] = b"XY"
assert list(p) == [b"f", b"X", b"Y", b"Z", b"T", b"r", b"\x00"]
- py.test.raises(TypeError, "p[1:5] = u+'XYZT'")
- py.test.raises(TypeError, "p[1:5] = [1, 2, 3, 4]")
+ with pytest.raises(TypeError):
+ p[1:5] = u+'XYZT'
+ with pytest.raises(TypeError):
+ p[1:5] = [1, 2, 3, 4]
#
for typename in ["wchar_t", "char16_t", "char32_t"]:
BUniChar = new_primitive_type(typename)
@@ -3536,8 +3662,10 @@ def test_ass_slice():
p[2:5] = [u+"*", u+"Z", u+"T"]
p[1:3] = u+"XY"
assert list(p) == [u+"f", u+"X", u+"Y", u+"Z", u+"T", u+"r", u+"\x00"]
- py.test.raises(TypeError, "p[1:5] = b'XYZT'")
- py.test.raises(TypeError, "p[1:5] = [1, 2, 3, 4]")
+ with pytest.raises(TypeError):
+ p[1:5] = b'XYZT'
+ with pytest.raises(TypeError):
+ p[1:5] = [1, 2, 3, 4]
def test_void_p_arithmetic():
BVoid = new_void_type()
@@ -3548,10 +3676,14 @@ def test_void_p_arithmetic():
assert int(cast(BInt, p - (-42))) == 100042
assert (p + 42) - p == 42
q = cast(new_pointer_type(new_primitive_type("char")), 100000)
- py.test.raises(TypeError, "p - q")
- py.test.raises(TypeError, "q - p")
- py.test.raises(TypeError, "p + cast(new_primitive_type('int'), 42)")
- py.test.raises(TypeError, "p - cast(new_primitive_type('int'), 42)")
+ with pytest.raises(TypeError):
+ p - q
+ with pytest.raises(TypeError):
+ q - p
+ with pytest.raises(TypeError):
+ p + cast(new_primitive_type('int'), 42)
+ with pytest.raises(TypeError):
+ p - cast(new_primitive_type('int'), 42)
def test_sizeof_sliced_array():
BInt = new_primitive_type("int")
@@ -3758,7 +3890,9 @@ def test_from_buffer_types():
BIntP = new_pointer_type(BInt)
BIntA = new_array_type(BIntP, None)
lst = [-12345678, 87654321, 489148]
- bytestring = buffer(newp(BIntA, lst))[:] + b'XYZ'
+ bytestring = bytearray(buffer(newp(BIntA, lst))[:] + b'XYZ')
+ lst2 = lst + [42, -999999999]
+ bytestring2 = bytearray(buffer(newp(BIntA, lst2))[:] + b'XYZ')
#
p1 = from_buffer(BIntA, bytestring) # int[]
assert typeof(p1) is BIntA
@@ -3766,11 +3900,25 @@ def test_from_buffer_types():
assert p1[0] == lst[0]
assert p1[1] == lst[1]
assert p1[2] == lst[2]
- py.test.raises(IndexError, "p1[3]")
- py.test.raises(IndexError, "p1[-1]")
+ with pytest.raises(IndexError):
+ p1[3]
+ with pytest.raises(IndexError):
+ p1[-1]
#
py.test.raises(TypeError, from_buffer, BInt, bytestring)
- py.test.raises(TypeError, from_buffer, BIntP, bytestring)
+ #
+ p2 = from_buffer(BIntP, bytestring) # int *
+ assert p2 == p1 or 'PY_DOT_PY' in globals()
+ # note: on py.py ^^^, bytearray buffers are not emulated well enough
+ assert typeof(p2) is BIntP
+ assert p2[0] == lst[0]
+ assert p2[1] == lst[1]
+ assert p2[2] == lst[2]
+ # hopefully does not crash, but doesn't raise an exception:
+ p2[3]
+ p2[-1]
+ # not enough data even for one, but this is not enforced:
+ from_buffer(BIntP, b"")
#
BIntA2 = new_array_type(BIntP, 2)
p2 = from_buffer(BIntA2, bytestring) # int[2]
@@ -3778,9 +3926,11 @@ def test_from_buffer_types():
assert len(p2) == 2
assert p2[0] == lst[0]
assert p2[1] == lst[1]
- py.test.raises(IndexError, "p2[2]")
- py.test.raises(IndexError, "p2[-1]")
- assert p2 == p1
+ with pytest.raises(IndexError):
+ p2[2]
+ with pytest.raises(IndexError):
+ p2[-1]
+ assert p2 == p1 or 'PY_DOT_PY' in globals()
#
BIntA4 = new_array_type(BIntP, 4) # int[4]: too big
py.test.raises(ValueError, from_buffer, BIntA4, bytestring)
@@ -3790,12 +3940,37 @@ def test_from_buffer_types():
('a2', BInt, -1)])
BStructP = new_pointer_type(BStruct)
BStructA = new_array_type(BStructP, None)
- p1 = from_buffer(BStructA, bytestring) # struct[]
- assert len(p1) == 1
+ p1 = from_buffer(BStructA, bytestring2) # struct[]
+ assert len(p1) == 2
assert typeof(p1) is BStructA
- assert p1[0].a1 == lst[0]
- assert p1[0].a2 == lst[1]
- py.test.raises(IndexError, "p1[1]")
+ assert p1[0].a1 == lst2[0]
+ assert p1[0].a2 == lst2[1]
+ assert p1[1].a1 == lst2[2]
+ assert p1[1].a2 == lst2[3]
+ with pytest.raises(IndexError):
+ p1[2]
+ with pytest.raises(IndexError):
+ p1[-1]
+ assert repr(p1) == "<cdata 'foo[]' buffer len 2 from 'bytearray' object>"
+ #
+ p2 = from_buffer(BStructP, bytestring2) # 'struct *'
+ assert p2 == p1 or 'PY_DOT_PY' in globals()
+ assert typeof(p2) is BStructP
+ assert p2.a1 == lst2[0]
+ assert p2.a2 == lst2[1]
+ assert p2[0].a1 == lst2[0]
+ assert p2[0].a2 == lst2[1]
+ assert p2[1].a1 == lst2[2]
+ assert p2[1].a2 == lst2[3]
+ # does not crash:
+ p2[2]
+ p2[-1]
+ # not enough data even for one, but this is not enforced:
+ from_buffer(BStructP, b"")
+ from_buffer(BStructP, b"1234567")
+ #
+ release(p1)
+ assert repr(p1) == "<cdata 'foo[]' buffer RELEASED>"
#
BEmptyStruct = new_struct_type("empty")
complete_struct_or_union(BEmptyStruct, [], Ellipsis, 0)
@@ -3809,7 +3984,51 @@ def test_from_buffer_types():
p1 = from_buffer(BEmptyStructA5, bytestring) # struct empty[5]
assert typeof(p1) is BEmptyStructA5
assert len(p1) == 5
- assert cast(BIntP, p1) == from_buffer(BIntA, bytestring)
+ assert (cast(BIntP, p1) == from_buffer(BIntA, bytestring)
+ or 'PY_DOT_PY' in globals())
+ #
+ BVarStruct = new_struct_type("varfoo")
+ BVarStructP = new_pointer_type(BVarStruct)
+ complete_struct_or_union(BVarStruct, [('a1', BInt, -1),
+ ('va', BIntA, -1)])
+ with pytest.raises(TypeError):
+ from_buffer(BVarStruct, bytestring)
+ pv = from_buffer(BVarStructP, bytestring) # varfoo *
+ assert pv.a1 == lst[0]
+ assert pv.va[0] == lst[1]
+ assert pv.va[1] == lst[2]
+ assert sizeof(pv[0]) == 1 * size_of_int()
+ with pytest.raises(TypeError):
+ len(pv.va)
+ # hopefully does not crash, but doesn't raise an exception:
+ pv.va[2]
+ pv.va[-1]
+ # not enough data even for one, but this is not enforced:
+ from_buffer(BVarStructP, b"")
+ assert repr(pv) == "<cdata 'varfoo *' buffer from 'bytearray' object>"
+ assert repr(pv[0]).startswith("<cdata 'varfoo &' ")
+ #
+ release(pv)
+ assert repr(pv) == "<cdata 'varfoo *' buffer RELEASED>"
+ assert repr(pv[0]).startswith("<cdata 'varfoo &' ")
+ #
+ pv = from_buffer(BVarStructP, bytestring) # make a fresh one
+ with pytest.raises(ValueError):
+ release(pv[0])
+
+def test_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")
@@ -3887,10 +4106,14 @@ def test_dereference_null_ptr():
BInt = new_primitive_type("int")
BIntPtr = new_pointer_type(BInt)
p = cast(BIntPtr, 0)
- py.test.raises(RuntimeError, "p[0]")
- py.test.raises(RuntimeError, "p[0] = 42")
- py.test.raises(RuntimeError, "p[42]")
- py.test.raises(RuntimeError, "p[42] = -1")
+ with pytest.raises(RuntimeError):
+ p[0]
+ with pytest.raises(RuntimeError):
+ p[0] = 42
+ with pytest.raises(RuntimeError):
+ p[42]
+ with pytest.raises(RuntimeError):
+ p[42] = -1
def test_mixup():
BStruct1 = new_struct_type("foo")
@@ -3906,10 +4129,12 @@ def test_mixup():
pp2 = newp(BStruct2PtrPtr)
pp3 = newp(BStruct3PtrPtr)
pp1[0] = pp1[0]
- e = py.test.raises(TypeError, "pp3[0] = pp1[0]")
+ with pytest.raises(TypeError) as e:
+ pp3[0] = pp1[0]
assert str(e.value).startswith("initializer for ctype 'bar *' must be a ")
assert str(e.value).endswith(", not cdata 'foo *'")
- e = py.test.raises(TypeError, "pp2[0] = pp1[0]")
+ with pytest.raises(TypeError) as e:
+ pp2[0] = pp1[0]
assert str(e.value) == ("initializer for ctype 'foo *' appears indeed to "
"be 'foo *', but the types are different (check "
"that you are not e.g. mixing up different ffi "
@@ -4098,14 +4323,14 @@ def test_primitive_comparison():
assert (a != b) is True
assert (b != a) is True
if strict_compare:
- py.test.raises(TypeError, "a < b")
- py.test.raises(TypeError, "a <= b")
- py.test.raises(TypeError, "a > b")
- py.test.raises(TypeError, "a >= b")
- py.test.raises(TypeError, "b < a")
- py.test.raises(TypeError, "b <= a")
- py.test.raises(TypeError, "b > a")
- py.test.raises(TypeError, "b >= a")
+ with pytest.raises(TypeError): a < b
+ with pytest.raises(TypeError): a <= b
+ with pytest.raises(TypeError): a > b
+ with pytest.raises(TypeError): a >= b
+ with pytest.raises(TypeError): b < a
+ with pytest.raises(TypeError): b <= a
+ with pytest.raises(TypeError): b > a
+ with pytest.raises(TypeError): b >= a
elif a < b:
assert_lt(a, b)
else:
@@ -4151,7 +4376,8 @@ def test_explicit_release_new():
BIntP = new_pointer_type(new_primitive_type("int"))
p = newp(BIntP)
p[0] = 42
- py.test.raises(IndexError, "p[1]")
+ with pytest.raises(IndexError):
+ p[1]
release(p)
# here, reading p[0] might give garbage or segfault...
release(p) # no effect
@@ -4187,8 +4413,12 @@ def test_explicit_release_badtype():
def test_explicit_release_badtype_contextmgr():
BIntP = new_pointer_type(new_primitive_type("int"))
p = cast(BIntP, 12345)
- py.test.raises(ValueError, "with p: pass")
- py.test.raises(ValueError, "with p: pass")
+ with pytest.raises(ValueError):
+ with p:
+ pass
+ with pytest.raises(ValueError):
+ with p:
+ pass
def test_explicit_release_gc():
BIntP = new_pointer_type(new_primitive_type("int"))
@@ -4224,8 +4454,10 @@ def test_explicit_release_from_buffer():
BCharA = new_array_type(BCharP, None)
p = from_buffer(BCharA, a)
assert p[2] == b"z"
+ assert repr(p) == "<cdata 'char[]' buffer len 3 from 'bytearray' object>"
release(p)
assert p[2] == b"z" # true so far, but might change to raise RuntimeError
+ assert repr(p) == "<cdata 'char[]' buffer RELEASED>"
release(p) # no effect
def test_explicit_release_from_buffer_contextmgr():
@@ -4237,6 +4469,7 @@ def test_explicit_release_from_buffer_contextmgr():
with p:
assert p[2] == b"z"
assert p[2] == b"z" # true so far, but might change to raise RuntimeError
+ assert repr(p) == "<cdata 'char[]' buffer RELEASED>"
release(p) # no effect
def test_explicit_release_bytearray_on_cpython():
@@ -4248,9 +4481,95 @@ def test_explicit_release_bytearray_on_cpython():
BCharA = new_array_type(BCharP, None)
a += b't' * 10
p = from_buffer(BCharA, a)
- py.test.raises(BufferError, "a += b'u' * 100")
+ with pytest.raises(BufferError):
+ a += b'u' * 100
release(p)
a += b'v' * 100
release(p) # no effect
a += b'w' * 1000
assert a == bytearray(b"xyz" + b't' * 10 + b'v' * 100 + b'w' * 1000)
+
+def test_int_doesnt_give_bool():
+ BBool = new_primitive_type("_Bool")
+ x = int(cast(BBool, 42))
+ assert type(x) is int and x == 1
+ x = long(cast(BBool, 42))
+ assert type(x) is long and x == 1
+ with pytest.raises(TypeError):
+ float(cast(BBool, 42))
+ with pytest.raises(TypeError):
+ complex(cast(BBool, 42))
+
+def test_cannot_call_null_function_pointer():
+ BInt = new_primitive_type("int")
+ BFunc = new_function_type((BInt, BInt), BInt, False)
+ f = cast(BFunc, 0)
+ with pytest.raises(RuntimeError):
+ f(40, 2)
+
+def test_huge_structure():
+ BChar = new_primitive_type("char")
+ BArray = new_array_type(new_pointer_type(BChar), sys.maxsize)
+ assert sizeof(BArray) == sys.maxsize
+ BStruct = new_struct_type("struct foo")
+ complete_struct_or_union(BStruct, [('a1', BArray, -1)])
+ assert sizeof(BStruct) == sys.maxsize
+
+def test_get_types():
+ import _cffi_backend
+ CData, CType = _get_types()
+ assert CData is _cffi_backend._CDataBase
+ assert CType is _cffi_backend.CType
+
+def test_type_available_with_correct_names():
+ import _cffi_backend
+ check_names = [
+ 'CType',
+ 'CField',
+ 'CLibrary',
+ '_CDataBase',
+ 'FFI',
+ 'Lib',
+ 'buffer',
+ ]
+ if '__pypy__' in sys.builtin_module_names:
+ check_names += [
+ '__CData_iterator',
+ '__FFIGlobSupport',
+ '__FFIAllocator',
+ '__FFIFunctionWrapper',
+ ]
+ else:
+ check_names += [
+ '__CDataOwn',
+ '__CDataOwnGC',
+ '__CDataFromBuf',
+ '__CDataGCP',
+ '__CData_iterator',
+ '__FFIGlobSupport',
+ ]
+ for name in check_names:
+ tp = getattr(_cffi_backend, name)
+ assert isinstance(tp, type)
+ assert (tp.__module__, tp.__name__) == ('_cffi_backend', name)
+
+def test_unaligned_types():
+ BByteArray = new_array_type(
+ new_pointer_type(new_primitive_type("unsigned char")), None)
+ pbuf = newp(BByteArray, 40)
+ buf = buffer(pbuf)
+ #
+ for name in ['short', 'int', 'long', 'long long', 'float', 'double',
+ 'float _Complex', 'double _Complex']:
+ p = new_primitive_type(name)
+ if name.endswith(' _Complex'):
+ num = cast(p, 1.23 - 4.56j)
+ else:
+ num = cast(p, 0x0123456789abcdef)
+ size = sizeof(p)
+ buf[0:40] = b"\x00" * 40
+ pbuf1 = cast(new_pointer_type(p), pbuf + 1)
+ pbuf1[0] = num
+ assert pbuf1[0] == num
+ assert buf[0] == b'\x00'
+ assert buf[1 + size] == b'\x00'