diff options
Diffstat (limited to 'c')
42 files changed, 0 insertions, 22276 deletions
diff --git a/c/.libs_cffi_backend/libffi-9c61262e.so.8.1.0 b/c/.libs_cffi_backend/libffi-9c61262e.so.8.1.0 Binary files differdeleted file mode 100755 index 82b4232..0000000 --- a/c/.libs_cffi_backend/libffi-9c61262e.so.8.1.0 +++ /dev/null diff --git a/c/Android.bp b/c/Android.bp deleted file mode 100644 index 96565df..0000000 --- a/c/Android.bp +++ /dev/null @@ -1,44 +0,0 @@ -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "external_python_cffi_license" - // to get the below license kinds: - // SPDX-license-identifier-MIT - default_applicable_licenses: ["external_python_cffi_license"], -} - -python_library { - name: "py-cffi-backend", - host_supported: true, - srcs: [ - "_dummy_file_cffi_backend.py", - ], - data: [ - ":py-cffi-backend-files" - ], -} - -filegroup { - name: "py-cffi-backend-files", - srcs: [ - "_cffi_backend.so", - ], -} - -python_library { - name: "py-cffi-backend-libffi", - host_supported: true, - srcs: [ - "_dummy_file_libffi.py", - ], - data: [ - ":py-cffi-backend-libffi-files" - ], -} - -filegroup { - name: "py-cffi-backend-libffi-files", - srcs: [ - ".libs_cffi_backend/libffi-9c61262e.so.8.1.0", - ], -} diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c deleted file mode 100644 index ffecbf9..0000000 --- a/c/_cffi_backend.c +++ /dev/null @@ -1,8083 +0,0 @@ -#define PY_SSIZE_T_CLEAN -#include <Python.h> -#include "structmember.h" - -#define CFFI_VERSION "1.15.0" - -#ifdef MS_WIN32 -#include <windows.h> -#include "misc_win32.h" -#else -#include <stddef.h> -#include <stdint.h> -#include <dlfcn.h> -#include <errno.h> -#include <ffi.h> -#include <sys/mman.h> -#endif - -/* this block of #ifs should be kept exactly identical between - c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py */ -#if defined(_MSC_VER) -# include <malloc.h> /* for alloca() */ -# if _MSC_VER < 1600 /* MSVC < 2010 */ - typedef __int8 int8_t; - typedef __int16 int16_t; - typedef __int32 int32_t; - typedef __int64 int64_t; - typedef unsigned __int8 uint8_t; - typedef unsigned __int16 uint16_t; - typedef unsigned __int32 uint32_t; - typedef unsigned __int64 uint64_t; - typedef __int8 int_least8_t; - typedef __int16 int_least16_t; - typedef __int32 int_least32_t; - typedef __int64 int_least64_t; - typedef unsigned __int8 uint_least8_t; - typedef unsigned __int16 uint_least16_t; - typedef unsigned __int32 uint_least32_t; - typedef unsigned __int64 uint_least64_t; - typedef __int8 int_fast8_t; - typedef __int16 int_fast16_t; - typedef __int32 int_fast32_t; - typedef __int64 int_fast64_t; - typedef unsigned __int8 uint_fast8_t; - typedef unsigned __int16 uint_fast16_t; - typedef unsigned __int32 uint_fast32_t; - typedef unsigned __int64 uint_fast64_t; - typedef __int64 intmax_t; - typedef unsigned __int64 uintmax_t; -# else -# include <stdint.h> -# endif -# if _MSC_VER < 1800 /* MSVC < 2013 */ - typedef unsigned char _Bool; -# endif -#else -# include <stdint.h> -# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux) -# include <alloca.h> -# endif -#endif - - -/* Define the following macro ONLY if you trust libffi's version of - * ffi_closure_alloc() more than the code in malloc_closure.h. - * IMPORTANT: DO NOT ENABLE THIS ON LINUX, unless you understand exactly - * why I recommend against it and decide that you trust it more than my - * analysis below. - * - * There are two versions of this code: one inside libffi itself, and - * one inside malloc_closure.h here. Both should be fine as long as the - * Linux distribution does _not_ enable extra security features. If it - * does, then the code in malloc_closure.h will cleanly crash because - * there is no reasonable way to obtain a read-write-execute memory - * page. On the other hand, the code in libffi will appear to - * work---but will actually randomly crash after a fork() if the child - * does not immediately call exec(). This second crash is of the kind - * that can be turned into an attack vector by a motivated attacker. - * So, _enabling_ extra security features _opens_ an attack vector. - * 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() 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_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" -# define PyText_Type PyUnicode_Type -# define PyText_Check PyUnicode_Check -# define PyTextAny_Check PyUnicode_Check -# define PyText_FromFormat PyUnicode_FromFormat -# define PyText_AsUTF8 _PyUnicode_AsString /* PyUnicode_AsUTF8 in Py3.3 */ -# define PyText_AS_UTF8 _PyUnicode_AsString -# if PY_VERSION_HEX >= 0x03030000 -# define PyText_GetSize PyUnicode_GetLength -# else -# define PyText_GetSize PyUnicode_GetSize -# endif -# define PyText_FromString PyUnicode_FromString -# define PyText_FromStringAndSize PyUnicode_FromStringAndSize -# define PyText_InternInPlace PyUnicode_InternInPlace -# define PyText_InternFromString PyUnicode_InternFromString -# define PyIntOrLong_Check PyLong_Check -#else -# define STR_OR_BYTES "str" -# define PyText_Type PyString_Type -# define PyText_Check PyString_Check -# define PyTextAny_Check(op) (PyString_Check(op) || PyUnicode_Check(op)) -# define PyText_FromFormat PyString_FromFormat -# define PyText_AsUTF8 PyString_AsString -# define PyText_AS_UTF8 PyString_AS_STRING -# define PyText_GetSize PyString_Size -# define PyText_FromString PyString_FromString -# define PyText_FromStringAndSize PyString_FromStringAndSize -# define PyText_InternInPlace PyString_InternInPlace -# define PyText_InternFromString PyString_InternFromString -# define PyIntOrLong_Check(op) (PyInt_Check(op) || PyLong_Check(op)) -#endif - -#if PY_MAJOR_VERSION >= 3 -# define PyInt_FromLong PyLong_FromLong -# define PyInt_FromSsize_t PyLong_FromSsize_t -# define PyInt_AsSsize_t PyLong_AsSsize_t -# define PyInt_AsLong PyLong_AsLong -#endif - -#if PY_MAJOR_VERSION >= 3 -/* This is the default on Python3 and constant has been removed. */ -# define Py_TPFLAGS_CHECKTYPES 0 -#endif - -#if PY_MAJOR_VERSION < 3 -# undef PyCapsule_GetPointer -# undef PyCapsule_New -# define PyCapsule_GetPointer(capsule, name) \ - (PyCObject_AsVoidPtr(capsule)) -# define PyCapsule_New(pointer, name, destructor) \ - (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: */ -#define CT_PRIMITIVE_SIGNED 0x001 /* signed integer */ -#define CT_PRIMITIVE_UNSIGNED 0x002 /* unsigned integer */ -#define CT_PRIMITIVE_CHAR 0x004 /* char, wchar_t, charN_t */ -#define CT_PRIMITIVE_FLOAT 0x008 /* float, double, long double */ -#define CT_POINTER 0x010 /* pointer, excluding ptr-to-func */ -#define CT_ARRAY 0x020 /* array */ -#define CT_STRUCT 0x040 /* struct */ -#define CT_UNION 0x080 /* union */ -#define CT_FUNCTIONPTR 0x100 /* pointer to function */ -#define CT_VOID 0x200 /* void */ -#define CT_PRIMITIVE_COMPLEX 0x400 /* float _Complex, double _Complex */ - -/* other flags that may also be set in addition to the base flag: */ -#define CT_IS_VOIDCHAR_PTR 0x00001000 -#define CT_PRIMITIVE_FITS_LONG 0x00002000 -#define CT_IS_OPAQUE 0x00004000 -#define CT_IS_ENUM 0x00008000 -#define CT_IS_PTR_TO_OWNED 0x00010000 /* only owned if CDataOwning_Type */ -#define CT_CUSTOM_FIELD_POS 0x00020000 -#define CT_IS_LONGDOUBLE 0x00040000 -#define CT_IS_BOOL 0x00080000 -#define CT_IS_FILE 0x00100000 -#define CT_IS_VOID_PTR 0x00200000 -#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 -#define CT_IS_SIGNED_WCHAR 0x04000000 -#define CT_PRIMITIVE_ANY (CT_PRIMITIVE_SIGNED | \ - CT_PRIMITIVE_UNSIGNED | \ - CT_PRIMITIVE_CHAR | \ - CT_PRIMITIVE_FLOAT | \ - CT_PRIMITIVE_COMPLEX) - -typedef struct _ctypedescr { - PyObject_VAR_HEAD - - struct _ctypedescr *ct_itemdescr; /* ptrs and arrays: the item type */ - PyObject *ct_stuff; /* structs: dict of the fields - arrays: ctypedescr of the ptr type - function: tuple(abi, ctres, ctargs..) - enum: pair {"name":x},{x:"name"} - ptrs: lazily, ctypedescr of array */ - void *ct_extra; /* structs: first field (not a ref!) - function types: cif_description - primitives: prebuilt "cif" object */ - - PyObject *ct_weakreflist; /* weakref support */ - - PyObject *ct_unique_key; /* key in unique_cache (a string, but not - human-readable) */ - - Py_ssize_t ct_size; /* size of instances, or -1 if unknown */ - Py_ssize_t ct_length; /* length of arrays, or -1 if unknown; - or alignment of primitive and struct types; - always -1 for pointers */ - int ct_flags; /* CT_xxx flags */ - - int ct_name_position; /* index in ct_name of where to put a var name */ - char ct_name[1]; /* string, e.g. "int *" for pointers to ints */ -} CTypeDescrObject; - -typedef struct { - PyObject_HEAD - CTypeDescrObject *c_type; - char *c_data; - PyObject *c_weakreflist; -} CDataObject; - -typedef struct cfieldobject_s { - PyObject_HEAD - CTypeDescrObject *cf_type; - Py_ssize_t cf_offset; - short cf_bitshift; /* >= 0: bitshift; or BS_REGULAR or BS_EMPTY_ARRAY */ - short cf_bitsize; - unsigned char cf_flags; /* BF_... */ - struct cfieldobject_s *cf_next; -} CFieldObject; -#define BS_REGULAR (-1) /* a regular field, not with bitshift */ -#define BS_EMPTY_ARRAY (-2) /* a field declared 'type[0]' or 'type[]' */ -#define BF_IGNORE_IN_CTOR 0x01 /* union field not in the first place */ - -static PyTypeObject CTypeDescr_Type; -static PyTypeObject CField_Type; -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) - -typedef union { - unsigned char m_char; - unsigned short m_short; - unsigned int m_int; - unsigned long m_long; - unsigned long long m_longlong; - float m_float; - double m_double; - long double m_longdouble; -} union_alignment; - -typedef struct { - CDataObject head; - union_alignment alignment; -} CDataObject_casted_primitive; - -typedef struct { - CDataObject head; - union_alignment alignment; -} CDataObject_own_nolength; - -typedef struct { - CDataObject head; - Py_ssize_t length; - union_alignment alignment; -} CDataObject_own_length; - -typedef struct { - CDataObject head; - 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_frombuf; - -typedef struct { - CDataObject head; - Py_ssize_t length; /* same as CDataObject_own_length up to here */ - PyObject *origobj; - PyObject *destructor; -} CDataObject_gcp; - -typedef struct { - CDataObject head; - ffi_closure *closure; -} CDataObject_closure; - -typedef struct { - ffi_cif cif; - /* the following information is used when doing the call: - - a buffer of size 'exchange_size' is malloced - - the arguments are converted from Python objects to raw data - - the i'th raw data is stored at 'buffer + exchange_offset_arg[1+i]' - - the call is done - - the result is read back from 'buffer + exchange_offset_arg[0]' */ - Py_ssize_t exchange_size; - Py_ssize_t exchange_offset_arg[1]; -} cif_description_t; - -#define ADD_WRAPAROUND(x, y) ((Py_ssize_t)(((size_t)(x)) + ((size_t)(y)))) -#define MUL_WRAPAROUND(x, y) ((Py_ssize_t)(((size_t)(x)) * ((size_t)(y)))) - - -/* whenever running Python code, the errno is saved in this thread-local - variable */ -#ifndef MS_WIN32 -# include "misc_thread_posix.h" -#endif - -#include "minibuffer.h" - -#if PY_MAJOR_VERSION >= 3 -# include "file_emulator.h" -#endif - -#ifdef PyUnicode_KIND /* Python >= 3.3 */ -# include "wchar_helper_3.h" -#else -# include "wchar_helper.h" -#endif - -#include "../cffi/_cffi_errors.h" - -typedef struct _cffi_allocator_s { - PyObject *ca_alloc, *ca_free; - int ca_dont_clear; -} cffi_allocator_t; -static const cffi_allocator_t default_allocator = { NULL, NULL, 0 }; -static PyObject *FFIError; -static PyObject *unique_cache; - -/************************************************************/ - -static CTypeDescrObject * -ctypedescr_new(int name_size) -{ - CTypeDescrObject *ct = PyObject_GC_NewVar(CTypeDescrObject, - &CTypeDescr_Type, - name_size); - if (ct == NULL) - return NULL; - - ct->ct_itemdescr = NULL; - ct->ct_stuff = NULL; - ct->ct_weakreflist = NULL; - ct->ct_unique_key = NULL; - PyObject_GC_Track(ct); - return ct; -} - -static CTypeDescrObject * -ctypedescr_new_on_top(CTypeDescrObject *ct_base, const char *extra_text, - int extra_position) -{ - int base_name_len = strlen(ct_base->ct_name); - int extra_name_len = strlen(extra_text); - CTypeDescrObject *ct = ctypedescr_new(base_name_len + extra_name_len + 1); - char *p; - if (ct == NULL) - return NULL; - - Py_INCREF(ct_base); - ct->ct_itemdescr = ct_base; - ct->ct_name_position = ct_base->ct_name_position + extra_position; - - p = ct->ct_name; - memcpy(p, ct_base->ct_name, ct_base->ct_name_position); - p += ct_base->ct_name_position; - memcpy(p, extra_text, extra_name_len); - p += extra_name_len; - memcpy(p, ct_base->ct_name + ct_base->ct_name_position, - base_name_len - ct_base->ct_name_position + 1); - - return ct; -} - -static PyObject * -ctypedescr_repr(CTypeDescrObject *ct) -{ - return PyText_FromFormat("<ctype '%s'>", ct->ct_name); -} - -static void -ctypedescr_dealloc(CTypeDescrObject *ct) -{ - PyObject_GC_UnTrack(ct); - if (ct->ct_weakreflist != NULL) - PyObject_ClearWeakRefs((PyObject *) ct); - - if (ct->ct_unique_key != NULL) { - /* revive dead object temporarily for DelItem */ - Py_SET_REFCNT(ct, 43); - PyDict_DelItem(unique_cache, ct->ct_unique_key); - assert(Py_REFCNT(ct) == 42); - Py_SET_REFCNT(ct, 0); - Py_DECREF(ct->ct_unique_key); - } - Py_XDECREF(ct->ct_itemdescr); - Py_XDECREF(ct->ct_stuff); - if (ct->ct_flags & CT_FUNCTIONPTR) - PyObject_Free(ct->ct_extra); - Py_TYPE(ct)->tp_free((PyObject *)ct); -} - -static int -ctypedescr_traverse(CTypeDescrObject *ct, visitproc visit, void *arg) -{ - Py_VISIT(ct->ct_itemdescr); - Py_VISIT(ct->ct_stuff); - return 0; -} - -static int -ctypedescr_clear(CTypeDescrObject *ct) -{ - Py_CLEAR(ct->ct_itemdescr); - Py_CLEAR(ct->ct_stuff); - return 0; -} - - -static PyObject *nosuchattr(const char *attr) -{ - PyErr_SetString(PyExc_AttributeError, attr); - return NULL; -} - -static PyObject *ctypeget_kind(CTypeDescrObject *ct, void *context) -{ - char *result; - if (ct->ct_flags & CT_PRIMITIVE_ANY) { - if (ct->ct_flags & CT_IS_ENUM) - result = "enum"; - else - result = "primitive"; - } - else if (ct->ct_flags & CT_POINTER) { - result = "pointer"; - } - else if (ct->ct_flags & CT_ARRAY) { - result = "array"; - } - else if (ct->ct_flags & CT_VOID) { - result = "void"; - } - else if (ct->ct_flags & CT_STRUCT) { - result = "struct"; - } - else if (ct->ct_flags & CT_UNION) { - result = "union"; - } - else if (ct->ct_flags & CT_FUNCTIONPTR) { - result = "function"; - } - else - result = "?"; - - return PyText_FromString(result); -} - -static PyObject *ctypeget_cname(CTypeDescrObject *ct, void *context) -{ - return PyText_FromString(ct->ct_name); -} - -static PyObject *ctypeget_item(CTypeDescrObject *ct, void *context) -{ - if (ct->ct_flags & (CT_POINTER | CT_ARRAY)) { - Py_INCREF(ct->ct_itemdescr); - return (PyObject *)ct->ct_itemdescr; - } - return nosuchattr("item"); -} - -static PyObject *ctypeget_length(CTypeDescrObject *ct, void *context) -{ - if (ct->ct_flags & CT_ARRAY) { - if (ct->ct_length >= 0) { - return PyInt_FromSsize_t(ct->ct_length); - } - else { - Py_INCREF(Py_None); - return Py_None; - } - } - return nosuchattr("length"); -} - -static PyObject * -get_field_name(CTypeDescrObject *ct, CFieldObject *cf); /* forward */ - -/* returns 0 if the struct ctype is opaque, 1 if it is not, or -1 if - an exception occurs */ -#define force_lazy_struct(ct) \ - ((ct)->ct_stuff != NULL ? 1 : do_realize_lazy_struct(ct)) - -static int do_realize_lazy_struct(CTypeDescrObject *ct); -/* forward, implemented in realize_c_type.c */ - -static PyObject *ctypeget_fields(CTypeDescrObject *ct, void *context) -{ - if (ct->ct_flags & (CT_STRUCT | CT_UNION)) { - if (!(ct->ct_flags & CT_IS_OPAQUE)) { - CFieldObject *cf; - PyObject *res; - if (force_lazy_struct(ct) < 0) - return NULL; - res = PyList_New(0); - if (res == NULL) - return NULL; - for (cf = (CFieldObject *)ct->ct_extra; - cf != NULL; cf = cf->cf_next) { - PyObject *o = PyTuple_Pack(2, get_field_name(ct, cf), - (PyObject *)cf); - int err = (o != NULL) ? PyList_Append(res, o) : -1; - Py_XDECREF(o); - if (err < 0) { - Py_DECREF(res); - return NULL; - } - } - return res; - } - else { - Py_INCREF(Py_None); - return Py_None; - } - } - return nosuchattr("fields"); -} - -static PyObject *ctypeget_args(CTypeDescrObject *ct, void *context) -{ - if (ct->ct_flags & CT_FUNCTIONPTR) { - PyObject *t = ct->ct_stuff; - return PyTuple_GetSlice(t, 2, PyTuple_GET_SIZE(t)); - } - return nosuchattr("args"); -} - -static PyObject *ctypeget_result(CTypeDescrObject *ct, void *context) -{ - if (ct->ct_flags & CT_FUNCTIONPTR) { - PyObject *res = PyTuple_GetItem(ct->ct_stuff, 1); - Py_XINCREF(res); - return res; - } - return nosuchattr("result"); -} - -static PyObject *ctypeget_ellipsis(CTypeDescrObject *ct, void *context) -{ - if (ct->ct_flags & CT_FUNCTIONPTR) { - PyObject *res = ct->ct_extra ? Py_False : Py_True; - Py_INCREF(res); - return res; - } - return nosuchattr("ellipsis"); -} - -static PyObject *ctypeget_abi(CTypeDescrObject *ct, void *context) -{ - if (ct->ct_flags & CT_FUNCTIONPTR) { - PyObject *res = PyTuple_GetItem(ct->ct_stuff, 0); - Py_XINCREF(res); - return res; - } - return nosuchattr("abi"); -} - -static PyObject *ctypeget_elements(CTypeDescrObject *ct, void *context) -{ - if (ct->ct_flags & CT_IS_ENUM) { - PyObject *res = PyTuple_GetItem(ct->ct_stuff, 1); - if (res) res = PyDict_Copy(res); - return res; - } - return nosuchattr("elements"); -} - -static PyObject *ctypeget_relements(CTypeDescrObject *ct, void *context) -{ - if (ct->ct_flags & CT_IS_ENUM) { - PyObject *res = PyTuple_GetItem(ct->ct_stuff, 0); - if (res) res = PyDict_Copy(res); - return res; - } - return nosuchattr("relements"); -} - -static PyGetSetDef ctypedescr_getsets[] = { - {"kind", (getter)ctypeget_kind, NULL, "kind"}, - {"cname", (getter)ctypeget_cname, NULL, "C name"}, - {"item", (getter)ctypeget_item, NULL, "pointer to, or array of"}, - {"length", (getter)ctypeget_length, NULL, "array length or None"}, - {"fields", (getter)ctypeget_fields, NULL, "struct or union fields"}, - {"args", (getter)ctypeget_args, NULL, "function argument types"}, - {"result", (getter)ctypeget_result, NULL, "function result type"}, - {"ellipsis", (getter)ctypeget_ellipsis, NULL, "function has '...'"}, - {"abi", (getter)ctypeget_abi, NULL, "function ABI"}, - {"elements", (getter)ctypeget_elements, NULL, "enum elements"}, - {"relements", (getter)ctypeget_relements, NULL, "enum elements, reverse"}, - {NULL} /* sentinel */ -}; - -static PyObject * -ctypedescr_dir(PyObject *ct, PyObject *noarg) -{ - int err; - struct PyGetSetDef *gsdef; - PyObject *res = PyList_New(0); - if (res == NULL) - return NULL; - - for (gsdef = ctypedescr_getsets; gsdef->name; gsdef++) { - PyObject *x = PyObject_GetAttrString(ct, gsdef->name); - if (x == NULL) { - PyErr_Clear(); - } - else { - Py_DECREF(x); - x = PyText_FromString(gsdef->name); - err = (x != NULL) ? PyList_Append(res, x) : -1; - Py_XDECREF(x); - if (err < 0) { - Py_DECREF(res); - return NULL; - } - } - } - return res; -} - -static PyMethodDef ctypedescr_methods[] = { - {"__dir__", ctypedescr_dir, METH_NOARGS}, - {NULL, NULL} /* sentinel */ -}; - -static PyTypeObject CTypeDescr_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_cffi_backend.CType", - offsetof(CTypeDescrObject, ct_name), - sizeof(char), - (destructor)ctypedescr_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - (reprfunc)ctypedescr_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - 0, /* tp_doc */ - (traverseproc)ctypedescr_traverse, /* tp_traverse */ - (inquiry)ctypedescr_clear, /* tp_clear */ - 0, /* tp_richcompare */ - offsetof(CTypeDescrObject, ct_weakreflist), /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - ctypedescr_methods, /* tp_methods */ - 0, /* tp_members */ - ctypedescr_getsets, /* tp_getset */ -}; - -/************************************************************/ - -static PyObject * -get_field_name(CTypeDescrObject *ct, CFieldObject *cf) -{ - Py_ssize_t i = 0; - PyObject *d_key, *d_value; - while (PyDict_Next(ct->ct_stuff, &i, &d_key, &d_value)) { - if (d_value == (PyObject *)cf) - return d_key; - } - Py_FatalError("_cffi_backend: get_field_name()"); - return NULL; -} - -static void -cfield_dealloc(CFieldObject *cf) -{ - Py_DECREF(cf->cf_type); - PyObject_Del(cf); -} - -#undef OFF -#define OFF(x) offsetof(CFieldObject, x) - -static PyMemberDef cfield_members[] = { - {"type", T_OBJECT, OFF(cf_type), READONLY}, - {"offset", T_PYSSIZET, OFF(cf_offset), READONLY}, - {"bitshift", T_SHORT, OFF(cf_bitshift), READONLY}, - {"bitsize", T_SHORT, OFF(cf_bitsize), READONLY}, - {"flags", T_UBYTE, OFF(cf_flags), READONLY}, - {NULL} /* Sentinel */ -}; -#undef OFF - -static PyTypeObject CField_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_cffi_backend.CField", - sizeof(CFieldObject), - 0, - (destructor)cfield_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - cfield_members, /* tp_members */ -}; - -/************************************************************/ - -static int -CDataObject_Or_PyFloat_Check(PyObject *ob) -{ - return (PyFloat_Check(ob) || - (CData_Check(ob) && - (((CDataObject *)ob)->c_type->ct_flags & CT_PRIMITIVE_FLOAT))); -} - -static PY_LONG_LONG -_my_PyLong_AsLongLong(PyObject *ob) -{ - /* (possibly) convert and cast a Python object to a long long. - Like PyLong_AsLongLong(), this version accepts a Python int too, and - does convertions from other types of objects. The difference is that - this version refuses floats. */ -#if PY_MAJOR_VERSION < 3 - if (PyInt_Check(ob)) { - return PyInt_AS_LONG(ob); - } - else -#endif - if (PyLong_Check(ob)) { - return PyLong_AsLongLong(ob); - } - else { - PyObject *io; - PY_LONG_LONG res; - PyNumberMethods *nb = ob->ob_type->tp_as_number; - - if (CDataObject_Or_PyFloat_Check(ob) || - nb == NULL || nb->nb_int == NULL) { - PyErr_SetString(PyExc_TypeError, "an integer is required"); - return -1; - } - io = (*nb->nb_int) (ob); - if (io == NULL) - return -1; - - if (PyIntOrLong_Check(io)) { - res = _my_PyLong_AsLongLong(io); - } - else { - PyErr_SetString(PyExc_TypeError, "integer conversion failed"); - res = -1; - } - Py_DECREF(io); - return res; - } -} - -static unsigned PY_LONG_LONG -_my_PyLong_AsUnsignedLongLong(PyObject *ob, int strict) -{ - /* (possibly) convert and cast a Python object to an unsigned long long. - Like PyLong_AsLongLong(), this version accepts a Python int too, and - does convertions from other types of objects. If 'strict', complains - with OverflowError and refuses floats. If '!strict', rounds floats - and masks the result. */ -#if PY_MAJOR_VERSION < 3 - if (PyInt_Check(ob)) { - long value1 = PyInt_AS_LONG(ob); - if (strict && value1 < 0) - goto negative; - return (unsigned PY_LONG_LONG)(PY_LONG_LONG)value1; - } - else -#endif - if (PyLong_Check(ob)) { - if (strict) { - if (_PyLong_Sign(ob) < 0) - goto negative; - return PyLong_AsUnsignedLongLong(ob); - } - else { - return PyLong_AsUnsignedLongLongMask(ob); - } - } - else { - PyObject *io; - unsigned PY_LONG_LONG res; - PyNumberMethods *nb = ob->ob_type->tp_as_number; - - if ((strict && CDataObject_Or_PyFloat_Check(ob)) || - nb == NULL || nb->nb_int == NULL) { - PyErr_SetString(PyExc_TypeError, "an integer is required"); - return (unsigned PY_LONG_LONG)-1; - } - io = (*nb->nb_int) (ob); - if (io == NULL) - return (unsigned PY_LONG_LONG)-1; - - if (PyIntOrLong_Check(io)) { - res = _my_PyLong_AsUnsignedLongLong(io, strict); - } - else { - PyErr_SetString(PyExc_TypeError, "integer conversion failed"); - res = (unsigned PY_LONG_LONG)-1; - } - Py_DECREF(io); - return res; - } - - negative: - PyErr_SetString(PyExc_OverflowError, - "can't convert negative number to unsigned"); - return (unsigned PY_LONG_LONG)-1; -} - -#define _read_raw_data(type) \ - do { \ - if (size == sizeof(type)) { \ - type r; \ - memcpy(&r, target, sizeof(type)); \ - return r; \ - } \ - } while(0) - -static PY_LONG_LONG -read_raw_signed_data(char *target, int size) -{ - _read_raw_data(signed char); - _read_raw_data(short); - _read_raw_data(int); - _read_raw_data(long); - _read_raw_data(PY_LONG_LONG); - Py_FatalError("read_raw_signed_data: bad integer size"); - return 0; -} - -static unsigned PY_LONG_LONG -read_raw_unsigned_data(char *target, int size) -{ - _read_raw_data(unsigned char); - _read_raw_data(unsigned short); - _read_raw_data(unsigned int); - _read_raw_data(unsigned long); - _read_raw_data(unsigned PY_LONG_LONG); - Py_FatalError("read_raw_unsigned_data: bad integer size"); - return 0; -} - -#ifdef __GNUC__ -/* This is a workaround for what I think is a GCC bug on several - platforms. See issue #378. */ -__attribute__((noinline)) -#endif -void _cffi_memcpy(char *target, const void *src, size_t size) -{ - memcpy(target, src, size); -} - -#define _write_raw_data(type) \ - do { \ - if (size == sizeof(type)) { \ - type r = (type)source; \ - _cffi_memcpy(target, &r, sizeof(type)); \ - return; \ - } \ - } while(0) - -static void -write_raw_integer_data(char *target, unsigned PY_LONG_LONG source, int size) -{ - _write_raw_data(unsigned char); - _write_raw_data(unsigned short); - _write_raw_data(unsigned int); - _write_raw_data(unsigned long); - _write_raw_data(unsigned PY_LONG_LONG); - Py_FatalError("write_raw_integer_data: bad integer size"); -} - -static double -read_raw_float_data(char *target, int size) -{ - _read_raw_data(float); - _read_raw_data(double); - Py_FatalError("read_raw_float_data: bad float size"); - return 0; -} - -static long double -read_raw_longdouble_data(char *target) -{ - int size = sizeof(long double); - _read_raw_data(long double); - Py_FatalError("read_raw_longdouble_data: bad long double size"); - return 0; -} - -static Py_complex -read_raw_complex_data(char *target, int size) -{ - Py_complex r = {0.0, 0.0}; - if (size == 2*sizeof(float)) { - float real_part, imag_part; - memcpy(&real_part, target + 0, sizeof(float)); - memcpy(&imag_part, target + sizeof(float), sizeof(float)); - r.real = real_part; - r.imag = imag_part; - return r; - } - if (size == 2*sizeof(double)) { - memcpy(&r, target, 2*sizeof(double)); - return r; - } - Py_FatalError("read_raw_complex_data: bad complex size"); - return r; -} - -static void -write_raw_float_data(char *target, double source, int size) -{ - _write_raw_data(float); - _write_raw_data(double); - Py_FatalError("write_raw_float_data: bad float size"); -} - -static void -write_raw_longdouble_data(char *target, long double source) -{ - int size = sizeof(long double); - _write_raw_data(long double); -} - -#define _write_raw_complex_data(type) \ - do { \ - if (size == 2*sizeof(type)) { \ - type r = (type)source.real; \ - type i = (type)source.imag; \ - _cffi_memcpy(target, &r, sizeof(type)); \ - _cffi_memcpy(target+sizeof(type), &i, sizeof(type)); \ - return; \ - } \ - } while(0) - -static void -write_raw_complex_data(char *target, Py_complex source, int size) -{ - _write_raw_complex_data(float); - _write_raw_complex_data(double); - Py_FatalError("write_raw_complex_data: bad complex size"); -} - -static PyObject * -new_simple_cdata(char *data, CTypeDescrObject *ct) -{ - CDataObject *cd = PyObject_New(CDataObject, &CData_Type); - if (cd == NULL) - return NULL; - Py_INCREF(ct); - cd->c_data = data; - cd->c_type = ct; - cd->c_weakreflist = NULL; - return (PyObject *)cd; -} - -static PyObject * -new_sized_cdata(char *data, CTypeDescrObject *ct, Py_ssize_t length) -{ - CDataObject_own_length *scd; - - scd = (CDataObject_own_length *)PyObject_Malloc( - offsetof(CDataObject_own_length, alignment)); - if (PyObject_Init((PyObject *)scd, &CData_Type) == NULL) - return NULL; - Py_INCREF(ct); - scd->head.c_type = ct; - scd->head.c_data = data; - scd->head.c_weakreflist = NULL; - scd->length = length; - return (PyObject *)scd; -} - -static CDataObject *_new_casted_primitive(CTypeDescrObject *ct); /*forward*/ - -static PyObject * -convert_to_object(char *data, CTypeDescrObject *ct) -{ - if (!(ct->ct_flags & CT_PRIMITIVE_ANY)) { - /* non-primitive types (check done just for performance) */ - if (ct->ct_flags & (CT_POINTER|CT_FUNCTIONPTR)) { - char *ptrdata = *(char **)data; - /*READ(data, sizeof(char *))*/ - return new_simple_cdata(ptrdata, ct); - } - else if (ct->ct_flags & CT_IS_OPAQUE) { - PyErr_Format(PyExc_TypeError, "cdata '%s' is opaque", - ct->ct_name); - return NULL; - } - else if (ct->ct_flags & (CT_STRUCT|CT_UNION)) { - return new_simple_cdata(data, ct); - } - else if (ct->ct_flags & CT_ARRAY) { - if (ct->ct_length < 0) { - /* we can't return a <cdata 'int[]'> here, because we don't - know the length to give it. As a compromize, returns - <cdata 'int *'> in this case. */ - ct = (CTypeDescrObject *)ct->ct_stuff; - } - return new_simple_cdata(data, ct); - } - } - else if (ct->ct_flags & CT_PRIMITIVE_SIGNED) { - PY_LONG_LONG value; - /*READ(data, ct->ct_size)*/ - value = read_raw_signed_data(data, ct->ct_size); - if (ct->ct_flags & CT_PRIMITIVE_FITS_LONG) - return PyInt_FromLong((long)value); - else - return PyLong_FromLongLong(value); - } - else if (ct->ct_flags & CT_PRIMITIVE_UNSIGNED) { - unsigned PY_LONG_LONG value; - /*READ(data, ct->ct_size)*/ - value = read_raw_unsigned_data(data, ct->ct_size); - - if (ct->ct_flags & CT_PRIMITIVE_FITS_LONG) { - if (ct->ct_flags & CT_IS_BOOL) { - PyObject *x; - switch ((int)value) { - case 0: x = Py_False; break; - case 1: x = Py_True; break; - default: - PyErr_Format(PyExc_ValueError, - "got a _Bool of value %d, expected 0 or 1", - (int)value); - return NULL; - } - Py_INCREF(x); - return x; - } - return PyInt_FromLong((long)value); - } - else - return PyLong_FromUnsignedLongLong(value); - } - else if (ct->ct_flags & CT_PRIMITIVE_FLOAT) { - /*READ(data, ct->ct_size)*/ - if (!(ct->ct_flags & CT_IS_LONGDOUBLE)) { - double value = read_raw_float_data(data, ct->ct_size); - return PyFloat_FromDouble(value); - } - else { - long double value = read_raw_longdouble_data(data); - CDataObject *cd = _new_casted_primitive(ct); - if (cd != NULL) - write_raw_longdouble_data(cd->c_data, value); - return (PyObject *)cd; - } - } - else if (ct->ct_flags & CT_PRIMITIVE_CHAR) { - /*READ(data, ct->ct_size)*/ - switch (ct->ct_size) { - case sizeof(char): - return PyBytes_FromStringAndSize(data, 1); - case 2: - return _my_PyUnicode_FromChar16((cffi_char16_t *)data, 1); - case 4: - return _my_PyUnicode_FromChar32((cffi_char32_t *)data, 1); - } - } - else if (ct->ct_flags & CT_PRIMITIVE_COMPLEX) { - Py_complex value = read_raw_complex_data(data, ct->ct_size); - return PyComplex_FromCComplex(value); - } - - PyErr_Format(PyExc_SystemError, - "convert_to_object: '%s'", ct->ct_name); - return NULL; -} - -static PyObject * -convert_to_object_bitfield(char *data, CFieldObject *cf) -{ - CTypeDescrObject *ct = cf->cf_type; - /*READ(data, ct->ct_size)*/ - - if (ct->ct_flags & CT_PRIMITIVE_SIGNED) { - unsigned PY_LONG_LONG value, valuemask, shiftforsign; - PY_LONG_LONG result; - - value = (unsigned PY_LONG_LONG)read_raw_signed_data(data, ct->ct_size); - valuemask = (1ULL << cf->cf_bitsize) - 1ULL; - shiftforsign = 1ULL << (cf->cf_bitsize - 1); - value = ((value >> cf->cf_bitshift) + shiftforsign) & valuemask; - result = ((PY_LONG_LONG)value) - (PY_LONG_LONG)shiftforsign; - - if (ct->ct_flags & CT_PRIMITIVE_FITS_LONG) - return PyInt_FromLong((long)result); - else - return PyLong_FromLongLong(result); - } - else { - unsigned PY_LONG_LONG value, valuemask; - - value = read_raw_unsigned_data(data, ct->ct_size); - valuemask = (1ULL << cf->cf_bitsize) - 1ULL; - value = (value >> cf->cf_bitshift) & valuemask; - - if (ct->ct_flags & CT_PRIMITIVE_FITS_LONG) - return PyInt_FromLong((long)value); - else - return PyLong_FromUnsignedLongLong(value); - } -} - -static int _convert_overflow(PyObject *init, const char *ct_name) -{ - PyObject *s; - if (PyErr_Occurred()) /* already an exception pending */ - return -1; - s = PyObject_Str(init); - if (s == NULL) - return -1; - PyErr_Format(PyExc_OverflowError, "integer %s does not fit '%s'", - PyText_AS_UTF8(s), ct_name); - Py_DECREF(s); - return -1; -} - -static int _convert_to_char(PyObject *init) -{ - if (PyBytes_Check(init) && PyBytes_GET_SIZE(init) == 1) { - return (unsigned char)(PyBytes_AS_STRING(init)[0]); - } - if (CData_Check(init) && - (((CDataObject *)init)->c_type->ct_flags & CT_PRIMITIVE_CHAR) && - (((CDataObject *)init)->c_type->ct_size == sizeof(char))) { - char *data = ((CDataObject *)init)->c_data; - /*READ(data, 1)*/ - return *(unsigned char *)data; - } - PyErr_Format(PyExc_TypeError, - "initializer for ctype 'char' must be a "STR_OR_BYTES - " of length 1, not %.200s", Py_TYPE(init)->tp_name); - return -1; -} - -static cffi_char16_t _convert_to_char16_t(PyObject *init) -{ - char err_got[80]; - err_got[0] = 0; - - if (PyUnicode_Check(init)) { - cffi_char16_t ordinal; - if (_my_PyUnicode_AsSingleChar16(init, &ordinal, err_got) == 0) - return ordinal; - } - if (CData_Check(init) && - (((CDataObject *)init)->c_type->ct_flags & CT_PRIMITIVE_CHAR) && - (((CDataObject *)init)->c_type->ct_size == 2)) { - char *data = ((CDataObject *)init)->c_data; - /*READ(data, 2)*/ - return *(cffi_char16_t *)data; - } - PyErr_Format(PyExc_TypeError, - "initializer for ctype 'char16_t' must be a unicode string " - "of length 1, not %.200s", - err_got[0] == 0 ? Py_TYPE(init)->tp_name : err_got); - return (cffi_char16_t)-1; -} - -static cffi_char32_t _convert_to_char32_t(PyObject *init) -{ - char err_got[80]; - err_got[0] = 0; - - if (PyUnicode_Check(init)) { - cffi_char32_t ordinal; - if (_my_PyUnicode_AsSingleChar32(init, &ordinal, err_got) == 0) - return ordinal; - } - if (CData_Check(init) && - (((CDataObject *)init)->c_type->ct_flags & CT_PRIMITIVE_CHAR) && - (((CDataObject *)init)->c_type->ct_size == 4)) { - char *data = ((CDataObject *)init)->c_data; - /*READ(data, 4)*/ - return *(cffi_char32_t *)data; - } - PyErr_Format(PyExc_TypeError, - "initializer for ctype 'char32_t' must be a unicode string " - "of length 1, not %.200s", - err_got[0] == 0 ? Py_TYPE(init)->tp_name : err_got); - return (cffi_char32_t)-1; -} - -static int _convert_error(PyObject *init, CTypeDescrObject *ct, - const char *expected) -{ - if (CData_Check(init)) { - CTypeDescrObject *ct2 = ((CDataObject *)init)->c_type; - if (strcmp(ct->ct_name, ct2->ct_name) != 0) - PyErr_Format(PyExc_TypeError, - "initializer for ctype '%s' must be a %s, " - "not cdata '%s'", - ct->ct_name, expected, ct2->ct_name); - else if (ct != ct2) { - /* in case we'd give the error message "initializer for - ctype 'A' must be a pointer to same type, not cdata - 'B'", but with A=B, then give instead a different error - message to try to clear up the confusion */ - PyErr_Format(PyExc_TypeError, - "initializer for ctype '%s' appears indeed to be '%s'," - " but the types are different (check that you are not" - " e.g. mixing up different ffi instances)", - ct->ct_name, ct2->ct_name); - } - else - { - PyErr_Format(PyExc_SystemError, - "initializer for ctype '%s' is correct, but we get " - "an internal mismatch--please report a bug", - ct->ct_name); - } - } - else - PyErr_Format(PyExc_TypeError, - "initializer for ctype '%s' must be a %s, " - "not %.200s", - ct->ct_name, expected, Py_TYPE(init)->tp_name); - return -1; -} - -static int /* forward */ -convert_from_object(char *data, CTypeDescrObject *ct, PyObject *init); -static int /* forward */ -convert_from_object_bitfield(char *data, CFieldObject *cf, PyObject *init); - -static Py_ssize_t -get_new_array_length(CTypeDescrObject *ctitem, PyObject **pvalue) -{ - PyObject *value = *pvalue; - - if (PyList_Check(value) || PyTuple_Check(value)) { - return PySequence_Fast_GET_SIZE(value); - } - else if (PyBytes_Check(value)) { - /* from a string, we add the null terminator */ - return PyBytes_GET_SIZE(value) + 1; - } - else if (PyUnicode_Check(value)) { - /* from a unicode, we add the null terminator */ - int length; - if (ctitem->ct_size == 2) - length = _my_PyUnicode_SizeAsChar16(value); - else - length = _my_PyUnicode_SizeAsChar32(value); - return length + 1; - } - else { - Py_ssize_t explicitlength; - explicitlength = PyNumber_AsSsize_t(value, PyExc_OverflowError); - if (explicitlength < 0) { - if (PyErr_Occurred()) { - if (PyErr_ExceptionMatches(PyExc_TypeError)) - PyErr_Format(PyExc_TypeError, - "expected new array length or list/tuple/str, " - "not %.200s", Py_TYPE(value)->tp_name); - } - else - PyErr_SetString(PyExc_ValueError, "negative array length"); - return -1; - } - *pvalue = Py_None; - return explicitlength; - } -} - -static int -convert_field_from_object(char *data, CFieldObject *cf, PyObject *value) -{ - data += cf->cf_offset; - if (cf->cf_bitshift >= 0) - return convert_from_object_bitfield(data, cf, value); - else - return convert_from_object(data, cf->cf_type, 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) -{ - /* a special case for var-sized C99 arrays */ - if ((cf->cf_type->ct_flags & CT_ARRAY) && cf->cf_type->ct_size < 0) { - Py_ssize_t varsizelength = get_new_array_length( - cf->cf_type->ct_itemdescr, &value); - if (varsizelength < 0) - return -1; - 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 */ - assert(data == NULL); - 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, - and if so, stop here, leaving the content uninitialized - (it should be zero-initialized from somewhere else). */ - if (value == Py_None) - return 0; - } - 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; -} - -static int -must_be_array_of_zero_or_one(const char *data, Py_ssize_t n) -{ - Py_ssize_t i; - for (i = 0; i < n; i++) { - if (((unsigned char)data[i]) > 1) { - PyErr_SetString(PyExc_ValueError, - "an array of _Bool can only contain \\x00 or \\x01"); - return -1; - } - } - return 0; -} - -static Py_ssize_t -get_array_length(CDataObject *cd) -{ - if (cd->c_type->ct_length < 0) - return ((CDataObject_own_length *)cd)->length; - else - return cd->c_type->ct_length; -} - -static int -convert_array_from_object(char *data, CTypeDescrObject *ct, PyObject *init) -{ - /* used by convert_from_object(), and also to decode lists/tuples/unicodes - passed as function arguments. 'ct' is an CT_ARRAY in the first case - and a CT_POINTER in the second case. */ - const char *expected; - CTypeDescrObject *ctitem = ct->ct_itemdescr; - - if (PyList_Check(init) || PyTuple_Check(init)) { - PyObject **items; - Py_ssize_t i, n; - n = PySequence_Fast_GET_SIZE(init); - if (ct->ct_length >= 0 && n > ct->ct_length) { - PyErr_Format(PyExc_IndexError, - "too many initializers for '%s' (got %zd)", - ct->ct_name, n); - return -1; - } - items = PySequence_Fast_ITEMS(init); - for (i=0; i<n; i++) { - if (convert_from_object(data, ctitem, items[i]) < 0) - return -1; - data += ctitem->ct_size; - } - return 0; - } - else if ((ctitem->ct_flags & CT_PRIMITIVE_CHAR) || - ((ctitem->ct_flags & (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_UNSIGNED)) - && (ctitem->ct_size == sizeof(char)))) { - if (ctitem->ct_size == sizeof(char)) { - char *srcdata; - Py_ssize_t n; - if (!PyBytes_Check(init)) { - expected = STR_OR_BYTES" or list or tuple"; - goto cannot_convert; - } - n = PyBytes_GET_SIZE(init); - if (ct->ct_length >= 0 && n > ct->ct_length) { - PyErr_Format(PyExc_IndexError, - "initializer "STR_OR_BYTES" is too long for '%s' " - "(got %zd characters)", ct->ct_name, n); - return -1; - } - if (n != ct->ct_length) - n++; - srcdata = PyBytes_AS_STRING(init); - if (ctitem->ct_flags & CT_IS_BOOL) - if (must_be_array_of_zero_or_one(srcdata, n) < 0) - return -1; - memcpy(data, srcdata, n); - return 0; - } - else { - Py_ssize_t n; - if (!PyUnicode_Check(init)) { - expected = "unicode or list or tuple"; - goto cannot_convert; - } - - if (ctitem->ct_size == 4) - n = _my_PyUnicode_SizeAsChar32(init); - else - n = _my_PyUnicode_SizeAsChar16(init); - - if (ct->ct_length >= 0 && n > ct->ct_length) { - PyErr_Format(PyExc_IndexError, - "initializer unicode is too long for '%s' " - "(got %zd characters)", ct->ct_name, n); - return -1; - } - if (n != ct->ct_length) - n++; - if (ctitem->ct_size == 4) - return _my_PyUnicode_AsChar32(init, (cffi_char32_t *)data, n); - else - return _my_PyUnicode_AsChar16(init, (cffi_char16_t *)data, n); - } - } - else { - expected = "list or tuple"; - goto cannot_convert; - } - - cannot_convert: - if ((ct->ct_flags & CT_ARRAY) && CData_Check(init)) - { - CDataObject *cd = (CDataObject *)init; - if (cd->c_type == ct) - { - Py_ssize_t n = get_array_length(cd); - memcpy(data, cd->c_data, n * ctitem->ct_size); - return 0; - } - } - return _convert_error(init, ct, expected); -} - -static int -convert_struct_from_object(char *data, CTypeDescrObject *ct, PyObject *init, - Py_ssize_t *optvarsize) -{ - /* does not accept 'init' being already a CData */ - const char *expected; - - if (force_lazy_struct(ct) <= 0) { - if (!PyErr_Occurred()) - PyErr_Format(PyExc_TypeError, "'%s' is opaque", ct->ct_name); - return -1; - } - - if (PyList_Check(init) || PyTuple_Check(init)) { - PyObject **items = PySequence_Fast_ITEMS(init); - Py_ssize_t i, n = PySequence_Fast_GET_SIZE(init); - CFieldObject *cf = (CFieldObject *)ct->ct_extra; - - for (i=0; i<n; i++) { - while (cf != NULL && (cf->cf_flags & BF_IGNORE_IN_CTOR)) - cf = cf->cf_next; - if (cf == NULL) { - PyErr_Format(PyExc_ValueError, - "too many initializers for '%s' (got %zd)", - ct->ct_name, n); - return -1; - } - if (convert_vfield_from_object(data, cf, items[i], optvarsize) < 0) - return -1; - cf = cf->cf_next; - } - return 0; - } - if (PyDict_Check(init)) { - PyObject *d_key, *d_value; - Py_ssize_t i = 0; - CFieldObject *cf; - - while (PyDict_Next(init, &i, &d_key, &d_value)) { - cf = (CFieldObject *)PyDict_GetItem(ct->ct_stuff, d_key); - if (cf == NULL) { - PyErr_SetObject(PyExc_KeyError, d_key); - return -1; - } - if (convert_vfield_from_object(data, cf, d_value, optvarsize) < 0) - return -1; - } - return 0; - } - expected = optvarsize == NULL ? "list or tuple or dict or struct-cdata" - : "list or tuple or dict"; - return _convert_error(init, ct, expected); -} - -#ifdef __GNUC__ -# if __GNUC__ >= 4 -/* Don't go inlining this huge function. Needed because occasionally - it gets inlined in places where is causes a warning: call to - __builtin___memcpy_chk will always overflow destination buffer - (which is places where the 'ct' should never represent such a large - primitive type anyway). */ -__attribute__((noinline)) -# endif -#endif -static int -convert_from_object(char *data, CTypeDescrObject *ct, PyObject *init) -{ - const char *expected; - char buf[sizeof(PY_LONG_LONG)]; - - /*if (ct->ct_size > 0)*/ - /*WRITE(data, ct->ct_size)*/ - - if (ct->ct_flags & CT_ARRAY) { - return convert_array_from_object(data, ct, init); - } - if (ct->ct_flags & (CT_POINTER|CT_FUNCTIONPTR)) { - char *ptrdata; - CTypeDescrObject *ctinit; - - if (!CData_Check(init)) { - expected = "cdata pointer"; - goto cannot_convert; - } - ctinit = ((CDataObject *)init)->c_type; - if (!(ctinit->ct_flags & (CT_POINTER|CT_FUNCTIONPTR))) { - if (ctinit->ct_flags & CT_ARRAY) - ctinit = (CTypeDescrObject *)ctinit->ct_stuff; - else { - expected = "pointer or array"; - goto cannot_convert; - } - } - if (ctinit != ct) { - int combined_flags = ct->ct_flags | ctinit->ct_flags; - if (combined_flags & CT_IS_VOID_PTR) - ; /* accept "void *" as either source or target */ - else if (combined_flags & CT_IS_VOIDCHAR_PTR) { - /* for backward compatibility, accept "char *" as either - source of target. This is not what C does, though, - so emit a warning that will eventually turn into an - error. The warning is turned off if both types are - pointers to single bytes. */ - char *msg = (ct->ct_flags & CT_IS_VOIDCHAR_PTR ? - "implicit cast to 'char *' from a different pointer type: " - "will be forbidden in the future (check that the types " - "are as you expect; use an explicit ffi.cast() if they " - "are correct)" : - "implicit cast from 'char *' to a different pointer type: " - "will be forbidden in the future (check that the types " - "are as you expect; use an explicit ffi.cast() if they " - "are correct)"); - if ((ct->ct_flags & ctinit->ct_flags & CT_POINTER) && - ct->ct_itemdescr->ct_size == 1 && - ctinit->ct_itemdescr->ct_size == 1) { - /* no warning */ - } - else if (PyErr_WarnEx(PyExc_UserWarning, msg, 1)) - return -1; - } - else { - expected = "pointer to same type"; - goto cannot_convert; - } - } - ptrdata = ((CDataObject *)init)->c_data; - - *(char **)data = ptrdata; - return 0; - } - if (ct->ct_flags & CT_PRIMITIVE_SIGNED) { - PY_LONG_LONG value = _my_PyLong_AsLongLong(init); - if (value == -1 && PyErr_Occurred()) - return -1; - write_raw_integer_data(buf, value, ct->ct_size); - if (value != read_raw_signed_data(buf, ct->ct_size)) - goto overflow; - write_raw_integer_data(data, value, ct->ct_size); - return 0; - } - if (ct->ct_flags & CT_PRIMITIVE_UNSIGNED) { - unsigned PY_LONG_LONG value = _my_PyLong_AsUnsignedLongLong(init, 1); - if (value == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred()) - return -1; - if (ct->ct_flags & CT_IS_BOOL) { - if (value > 1ULL) /* value != 0 && value != 1 */ - goto overflow; - } - else { - write_raw_integer_data(buf, value, ct->ct_size); - if (value != read_raw_unsigned_data(buf, ct->ct_size)) - goto overflow; - } - write_raw_integer_data(data, value, ct->ct_size); - return 0; - } - if (ct->ct_flags & CT_PRIMITIVE_FLOAT) { - double value; - if ((ct->ct_flags & CT_IS_LONGDOUBLE) && - CData_Check(init) && - (((CDataObject *)init)->c_type->ct_flags & CT_IS_LONGDOUBLE)) { - long double lvalue; - char *initdata = ((CDataObject *)init)->c_data; - /*READ(initdata, sizeof(long double))*/ - lvalue = read_raw_longdouble_data(initdata); - write_raw_longdouble_data(data, lvalue); - return 0; - } - value = PyFloat_AsDouble(init); - if (value == -1.0 && PyErr_Occurred()) - return -1; - if (!(ct->ct_flags & CT_IS_LONGDOUBLE)) - write_raw_float_data(data, value, ct->ct_size); - else - write_raw_longdouble_data(data, (long double)value); - return 0; - } - if (ct->ct_flags & CT_PRIMITIVE_CHAR) { - switch (ct->ct_size) { - case sizeof(char): { - int res = _convert_to_char(init); - if (res < 0) - return -1; - data[0] = res; - return 0; - } - case 2: { - cffi_char16_t res = _convert_to_char16_t(init); - if (res == (cffi_char16_t)-1 && PyErr_Occurred()) - return -1; - *(cffi_char16_t *)data = res; - return 0; - } - case 4: { - cffi_char32_t res = _convert_to_char32_t(init); - if (res == (cffi_char32_t)-1 && PyErr_Occurred()) - return -1; - *(cffi_char32_t *)data = res; - return 0; - } - } - } - if (ct->ct_flags & (CT_STRUCT|CT_UNION)) { - - if (CData_Check(init)) { - if (((CDataObject *)init)->c_type == ct && ct->ct_size >= 0) { - memcpy(data, ((CDataObject *)init)->c_data, ct->ct_size); - return 0; - } - } - return convert_struct_from_object(data, ct, init, NULL); - } - if (ct->ct_flags & CT_PRIMITIVE_COMPLEX) { - Py_complex value = PyComplex_AsCComplex(init); - if (PyErr_Occurred()) - return -1; - write_raw_complex_data(data, value, ct->ct_size); - return 0; - } - PyErr_Format(PyExc_SystemError, - "convert_from_object: '%s'", ct->ct_name); - return -1; - - overflow: - return _convert_overflow(init, ct->ct_name); - - cannot_convert: - return _convert_error(init, ct, expected); -} - -static int -convert_from_object_bitfield(char *data, CFieldObject *cf, PyObject *init) -{ - CTypeDescrObject *ct = cf->cf_type; - PY_LONG_LONG fmin, fmax, value = PyLong_AsLongLong(init); - unsigned PY_LONG_LONG rawfielddata, rawvalue, rawmask; - if (value == -1 && PyErr_Occurred()) - return -1; - - if (ct->ct_flags & CT_PRIMITIVE_SIGNED) { - fmin = -(1LL << (cf->cf_bitsize-1)); - fmax = (1LL << (cf->cf_bitsize-1)) - 1LL; - if (fmax == 0) - fmax = 1; /* special case to let "int x:1" receive "1" */ - } - else { - fmin = 0LL; - fmax = (PY_LONG_LONG)((1ULL << cf->cf_bitsize) - 1ULL); - } - if (value < fmin || value > fmax) { - /* phew, PyErr_Format does not support "%lld" in Python 2.6 */ - PyObject *svalue = NULL, *sfmin = NULL, *sfmax = NULL; - PyObject *lfmin = NULL, *lfmax = NULL; - svalue = PyObject_Str(init); - if (svalue == NULL) goto skip; - lfmin = PyLong_FromLongLong(fmin); - if (lfmin == NULL) goto skip; - sfmin = PyObject_Str(lfmin); - if (sfmin == NULL) goto skip; - lfmax = PyLong_FromLongLong(fmax); - if (lfmax == NULL) goto skip; - sfmax = PyObject_Str(lfmax); - if (sfmax == NULL) goto skip; - PyErr_Format(PyExc_OverflowError, - "value %s outside the range allowed by the " - "bit field width: %s <= x <= %s", - PyText_AS_UTF8(svalue), - PyText_AS_UTF8(sfmin), - PyText_AS_UTF8(sfmax)); - skip: - Py_XDECREF(svalue); - Py_XDECREF(sfmin); - Py_XDECREF(sfmax); - Py_XDECREF(lfmin); - Py_XDECREF(lfmax); - return -1; - } - - rawmask = ((1ULL << cf->cf_bitsize) - 1ULL) << cf->cf_bitshift; - rawvalue = ((unsigned PY_LONG_LONG)value) << cf->cf_bitshift; - /*WRITE(data, ct->ct_size)*/ - rawfielddata = read_raw_unsigned_data(data, ct->ct_size); - rawfielddata = (rawfielddata & ~rawmask) | (rawvalue & rawmask); - write_raw_integer_data(data, rawfielddata, ct->ct_size); - return 0; -} - -static int -get_alignment(CTypeDescrObject *ct) -{ - int align; - retry: - if ((ct->ct_flags & (CT_PRIMITIVE_ANY|CT_STRUCT|CT_UNION)) && - !(ct->ct_flags & CT_IS_OPAQUE)) { - align = ct->ct_length; - if (align == -1 && (ct->ct_flags & CT_LAZY_FIELD_LIST)) { - force_lazy_struct(ct); - align = ct->ct_length; - } - } - else if (ct->ct_flags & (CT_POINTER|CT_FUNCTIONPTR)) { - struct aligncheck_ptr { char x; char *y; }; - align = offsetof(struct aligncheck_ptr, y); - } - else if (ct->ct_flags & CT_ARRAY) { - ct = ct->ct_itemdescr; - goto retry; - } - else { - PyErr_Format(PyExc_ValueError, "ctype '%s' is of unknown alignment", - ct->ct_name); - return -1; - } - - if ((align < 1) || (align & (align-1))) { - PyErr_Format(PyExc_SystemError, - "found for ctype '%s' bogus alignment '%d'", - ct->ct_name, align); - return -1; - } - return align; -} - -static void cdata_dealloc(CDataObject *cd) -{ - if (cd->c_weakreflist != NULL) - PyObject_ClearWeakRefs((PyObject *) cd); - - Py_DECREF(cd->c_type); -#ifndef CFFI_MEM_LEAK /* never release anything, tests only */ - Py_TYPE(cd)->tp_free((PyObject *)cd); -#endif -} - -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) - if (cd->c_type->ct_flags & (CT_PRIMITIVE_ANY | CT_STRUCT | CT_UNION)) { - assert(cd->c_type->ct_size >= 0); - memset(cd->c_data, 0xDD, cd->c_type->ct_size); - } - else if (cd->c_type->ct_flags & CT_ARRAY) { - Py_ssize_t x = get_array_length(cd); - assert(x >= 0); - x *= cd->c_type->ct_itemdescr->ct_size; - assert(x >= 0); - memset(cd->c_data, 0xDD, x); - } -#endif - cdata_dealloc(cd); -} - -static void cdataowninggc_dealloc(CDataObject *cd) -{ - PyObject_GC_UnTrack(cd); - - if (cd->c_type->ct_flags & CT_IS_VOID_PTR) { /* a handle */ - PyObject *x = ((CDataObject_own_structptr *)cd)->structobj; - Py_DECREF(x); - } - else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) { /* a callback */ - ffi_closure *closure = ((CDataObject_closure *)cd)->closure; - PyObject *args = (PyObject *)(closure->user_data); - Py_XDECREF(args); -#if CFFI_CHECK_FFI_CLOSURE_ALLOC_MAYBE - if (CFFI_CHECK_FFI_CLOSURE_ALLOC) { - ffi_closure_free(closure); - } else -#endif - cffi_closure_free(closure); - } - 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 */ - PyObject *x = ((CDataObject_own_structptr *)cd)->structobj; - Py_VISIT(x); - } - else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) { /* a callback */ - ffi_closure *closure = ((CDataObject_closure *)cd)->closure; - PyObject *args = (PyObject *)(closure->user_data); - Py_VISIT(args); - } - 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; -} - -static int cdataowninggc_clear(CDataObject *cd) -{ - if (cd->c_type->ct_flags & CT_IS_VOID_PTR) { /* a handle */ - CDataObject_own_structptr *cd1 = (CDataObject_own_structptr *)cd; - PyObject *x = cd1->structobj; - Py_INCREF(Py_None); - cd1->structobj = Py_None; - Py_DECREF(x); - } - else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) { /* a callback */ - ffi_closure *closure = ((CDataObject_closure *)cd)->closure; - PyObject *args = (PyObject *)(closure->user_data); - closure->user_data = NULL; - Py_XDECREF(args); - } - return 0; -} - -static int cdatafrombuf_clear(CDataObject *cd) -{ - Py_buffer *view = ((CDataObject_frombuf *)cd)->bufferview; - PyBuffer_Release(view); - return 0; -} - -/* forward */ -static void _my_PyErr_WriteUnraisable(PyObject *t, PyObject *v, PyObject *tb, - char *objdescr, PyObject *obj, - char *extra_error_line); - - -static void gcp_finalize(PyObject *destructor, PyObject *origobj) -{ - /* NOTE: this decrements the reference count of the two arguments */ - - if (destructor != NULL) { - PyObject *result; - PyObject *error_type, *error_value, *error_traceback; - - /* Save the current exception */ - PyErr_Fetch(&error_type, &error_value, &error_traceback); - - result = PyObject_CallFunctionObjArgs(destructor, origobj, NULL); - if (result != NULL) { - Py_DECREF(result); - } - else { - PyObject *t, *v, *tb; - PyErr_Fetch(&t, &v, &tb); - /* Don't use error capture here, because it is very much - * like errors at __del__(), and these ones are not captured - * either */ - /* ecap = _cffi_start_error_capture(); */ - _my_PyErr_WriteUnraisable(t, v, tb, "From callback for ffi.gc ", - origobj, NULL); - /* _cffi_stop_error_capture(ecap); */ - } - Py_DECREF(destructor); - - /* Restore the saved exception */ - PyErr_Restore(error_type, error_value, error_traceback); - } - Py_XDECREF(origobj); -} - -static void cdatagcp_finalize(CDataObject_gcp *cd) -{ - PyObject *destructor = cd->destructor; - PyObject *origobj = cd->origobj; - cd->destructor = NULL; - cd->origobj = NULL; - gcp_finalize(destructor, origobj); -} - -static void cdatagcp_dealloc(CDataObject_gcp *cd) -{ - PyObject *destructor = cd->destructor; - PyObject *origobj = cd->origobj; - cdata_dealloc((CDataObject *)cd); - - gcp_finalize(destructor, origobj); -} - -static int cdatagcp_traverse(CDataObject_gcp *cd, visitproc visit, void *arg) -{ - Py_VISIT(cd->destructor); - Py_VISIT(cd->origobj); - return 0; -} - -static PyObject *cdata_float(CDataObject *cd); /*forward*/ - -static PyObject *convert_cdata_to_enum_string(CDataObject *cd, int both) -{ - PyObject *d_key, *d_value; - CTypeDescrObject *ct = cd->c_type; - - assert(ct->ct_flags & CT_IS_ENUM); - d_key = convert_to_object(cd->c_data, ct); - if (d_key == NULL) - return NULL; - - d_value = PyDict_GetItem(PyTuple_GET_ITEM(ct->ct_stuff, 1), d_key); - if (d_value != NULL) { - if (both) { - PyObject *o = PyObject_Str(d_key); - if (o == NULL) - d_value = NULL; - else { - d_value = PyText_FromFormat("%s: %s", - PyText_AS_UTF8(o), - PyText_AS_UTF8(d_value)); - Py_DECREF(o); - } - } - else - Py_INCREF(d_value); - } - else - d_value = PyObject_Str(d_key); - Py_DECREF(d_key); - return d_value; -} - -static PyObject *cdata_repr(CDataObject *cd) -{ - char *extra; - PyObject *result, *s; - - if (cd->c_type->ct_flags & CT_PRIMITIVE_ANY) { - if (cd->c_type->ct_flags & CT_IS_ENUM) { - s = convert_cdata_to_enum_string(cd, 1); - } - else if (cd->c_type->ct_flags & CT_IS_LONGDOUBLE) { - long double lvalue; - char buffer[128]; /* big enough */ - /*READ(cd->c_data, sizeof(long double)*/ - lvalue = read_raw_longdouble_data(cd->c_data); - sprintf(buffer, "%LE", lvalue); - s = PyText_FromString(buffer); - } - else { - PyObject *o = convert_to_object(cd->c_data, cd->c_type); - if (o == NULL) - return NULL; - s = PyObject_Repr(o); - Py_DECREF(o); - } - } - else if ((cd->c_type->ct_flags & CT_ARRAY) && cd->c_type->ct_length < 0) { - s = PyText_FromFormat("sliced length %zd", get_array_length(cd)); - } - else { - if (cd->c_data != NULL) { - s = PyText_FromFormat("%p", cd->c_data); - } - else - s = PyText_FromString("NULL"); - } - if (s == NULL) - return NULL; - /* it's slightly confusing to get "<cdata 'struct foo' 0x...>" because the - struct foo is not owned. Trying to make it clearer, write in this - case "<cdata 'struct foo &' 0x...>". */ - if (cd->c_type->ct_flags & (CT_STRUCT|CT_UNION)) - extra = " &"; - else - extra = ""; - result = PyText_FromFormat("<cdata '%s%s' %s>", - cd->c_type->ct_name, extra, - PyText_AsUTF8(s)); - Py_DECREF(s); - return result; -} - -static PyObject *_cdata_repr2(CDataObject *cd, char *text, PyObject *x) -{ - PyObject *res, *s = PyObject_Repr(x); - if (s == NULL) - return NULL; - res = PyText_FromFormat("<cdata '%s' %s %s>", - cd->c_type->ct_name, text, PyText_AsUTF8(s)); - Py_DECREF(s); - return res; -} - -static Py_ssize_t _cdata_var_byte_size(CDataObject *cd) -{ - /* If 'cd' is a 'struct foo' or 'struct foo *' allocated with - ffi.new(), and if the struct foo contains a varsize array, - then return the real allocated size. Otherwise, return -1. */ - if (!CDataOwn_Check(cd)) - return -1; - - if (cd->c_type->ct_flags & CT_IS_PTR_TO_OWNED) { - cd = (CDataObject *)((CDataObject_own_structptr *)cd)->structobj; - } - if (cd->c_type->ct_flags & CT_WITH_VAR_ARRAY) { - return ((CDataObject_own_length *)cd)->length; - } - return -1; -} - -static PyObject *_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); - if (size < 0) { - if (cd->c_type->ct_flags & CT_POINTER) - size = cd->c_type->ct_itemdescr->ct_size; - else if (cd->c_type->ct_flags & CT_ARRAY) - size = get_array_length(cd) * cd->c_type->ct_itemdescr->ct_size; - else - size = cd->c_type->ct_size; - } - return PyText_FromFormat("<cdata '%s' owning %zd bytes>", - cd->c_type->ct_name, size); -} - -static PyObject *cdataowninggc_repr(CDataObject *cd) -{ - if (cd->c_type->ct_flags & CT_IS_VOID_PTR) { /* a handle */ - PyObject *x = ((CDataObject_own_structptr *)cd)->structobj; - return _cdata_repr2(cd, "handle to", x); - } - else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) { /* a callback */ - ffi_closure *closure = ((CDataObject_closure *)cd)->closure; - PyObject *args = (PyObject *)closure->user_data; - if (args == NULL) - return cdata_repr(cd); - else - return _cdata_repr2(cd, "calling", PyTuple_GET_ITEM(args, 1)); - } - 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) -{ - if (cd->c_type->ct_flags & CT_PRIMITIVE_ANY) { - if (cd->c_type->ct_flags & (CT_PRIMITIVE_SIGNED | - CT_PRIMITIVE_UNSIGNED | - CT_PRIMITIVE_CHAR)) - return read_raw_unsigned_data(cd->c_data, cd->c_type->ct_size) != 0; - - if (cd->c_type->ct_flags & CT_PRIMITIVE_FLOAT) { - if (cd->c_type->ct_flags & CT_IS_LONGDOUBLE) - return read_raw_longdouble_data(cd->c_data) != 0.0; - return read_raw_float_data(cd->c_data, cd->c_type->ct_size) != 0.0; - } - if (cd->c_type->ct_flags & CT_PRIMITIVE_COMPLEX) { - Py_complex value = read_raw_complex_data(cd->c_data, - cd->c_type->ct_size); - return value.real != 0.0 || value.imag != 0.0; - } - } - return cd->c_data != NULL; -} - -static PyObject *cdata_int(CDataObject *cd) -{ - if ((cd->c_type->ct_flags & (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_FITS_LONG)) - == (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_FITS_LONG)) { - /* this case is to handle enums, but also serves as a slight - performance improvement for some other primitive types */ - long value; - /*READ(cd->c_data, cd->c_type->ct_size)*/ - value = (long)read_raw_signed_data(cd->c_data, cd->c_type->ct_size); - return PyInt_FromLong(value); - } - if (cd->c_type->ct_flags & (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_UNSIGNED)) { - 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)*/ - switch (cd->c_type->ct_size) { - case sizeof(char): - return PyInt_FromLong((unsigned char)cd->c_data[0]); - case 2: - return PyInt_FromLong((long)*(cffi_char16_t *)cd->c_data); - case 4: - if (cd->c_type->ct_flags & CT_IS_SIGNED_WCHAR) - return PyInt_FromLong((long)*(int32_t *)cd->c_data); - else if (sizeof(long) > 4) - return PyInt_FromLong(*(uint32_t *)cd->c_data); - else - return PyLong_FromUnsignedLong(*(uint32_t *)cd->c_data); - } - } - else if (cd->c_type->ct_flags & CT_PRIMITIVE_FLOAT) { - PyObject *o = cdata_float(cd); -#if PY_MAJOR_VERSION < 3 - PyObject *r = o ? PyNumber_Int(o) : NULL; -#else - PyObject *r = o ? PyNumber_Long(o) : NULL; -#endif - Py_XDECREF(o); - return r; - } - PyErr_Format(PyExc_TypeError, "int() not supported on cdata '%s'", - cd->c_type->ct_name); - return NULL; -} - -#if PY_MAJOR_VERSION < 3 -static PyObject *cdata_long(CDataObject *cd) -{ - PyObject *res = cdata_int(cd); - if (res != NULL && PyInt_CheckExact(res)) { - PyObject *o = PyLong_FromLong(PyInt_AS_LONG(res)); - Py_DECREF(res); - res = o; - } - return res; -} -#endif - -static PyObject *cdata_float(CDataObject *cd) -{ - if (cd->c_type->ct_flags & CT_PRIMITIVE_FLOAT) { - double value; - /*READ(cd->c_data, cd->c_type->ct_size)*/ - if (!(cd->c_type->ct_flags & CT_IS_LONGDOUBLE)) { - value = read_raw_float_data(cd->c_data, cd->c_type->ct_size); - } - else { - value = (double)read_raw_longdouble_data(cd->c_data); - } - return PyFloat_FromDouble(value); - } - PyErr_Format(PyExc_TypeError, "float() not supported on cdata '%s'", - cd->c_type->ct_name); - return NULL; -} - -static PyObject *cdata_richcompare(PyObject *v, PyObject *w, int op) -{ - int v_is_ptr, w_is_ptr; - PyObject *pyres; - - assert(CData_Check(v)); - - /* Comparisons involving a primitive cdata work differently than - * comparisons involving a struct/array/pointer. - * - * If v or w is a struct/array/pointer, then the other must be too - * (otherwise we return NotImplemented and leave the case to - * Python). If both are, then we compare the addresses. - * - * If v and/or w is a primitive cdata, then we convert the cdata(s) - * to regular Python objects and redo the comparison there. - */ - - v_is_ptr = !(((CDataObject *)v)->c_type->ct_flags & CT_PRIMITIVE_ANY); - w_is_ptr = CData_Check(w) && - !(((CDataObject *)w)->c_type->ct_flags & CT_PRIMITIVE_ANY); - - if (v_is_ptr && w_is_ptr) { - int res; - char *v_cdata = ((CDataObject *)v)->c_data; - char *w_cdata = ((CDataObject *)w)->c_data; - - switch (op) { - case Py_EQ: res = (v_cdata == w_cdata); break; - case Py_NE: res = (v_cdata != w_cdata); break; - case Py_LT: res = (v_cdata < w_cdata); break; - case Py_LE: res = (v_cdata <= w_cdata); break; - case Py_GT: res = (v_cdata > w_cdata); break; - case Py_GE: res = (v_cdata >= w_cdata); break; - default: res = -1; - } - pyres = res ? Py_True : Py_False; - } - else if (v_is_ptr || w_is_ptr) { - pyres = Py_NotImplemented; - } - else { - PyObject *aa[2]; - int i; - - aa[0] = v; Py_INCREF(v); - aa[1] = w; Py_INCREF(w); - pyres = NULL; - - for (i = 0; i < 2; i++) { - v = aa[i]; - if (!CData_Check(v)) - continue; - w = convert_to_object(((CDataObject *)v)->c_data, - ((CDataObject *)v)->c_type); - if (w == NULL) - goto error; - if (CData_Check(w)) { - Py_DECREF(w); - PyErr_Format(PyExc_NotImplementedError, - "cannot use <cdata '%s'> in a comparison", - ((CDataObject *)v)->c_type->ct_name); - goto error; - } - aa[i] = w; - Py_DECREF(v); - } - pyres = PyObject_RichCompare(aa[0], aa[1], op); - error: - Py_DECREF(aa[1]); - Py_DECREF(aa[0]); - return pyres; - } - - Py_INCREF(pyres); - return pyres; -} - -#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, - ((CDataObject *)v)->c_type); - if (vv == NULL) - return -1; - if (!CData_Check(vv)) { - Py_hash_t hash = PyObject_Hash(vv); - Py_DECREF(vv); - return hash; - } - Py_DECREF(vv); - } - return _Py_HashPointer(((CDataObject *)v)->c_data); -} - -static Py_ssize_t -cdata_length(CDataObject *cd) -{ - if (cd->c_type->ct_flags & CT_ARRAY) { - return get_array_length(cd); - } - PyErr_Format(PyExc_TypeError, "cdata of type '%s' has no len()", - cd->c_type->ct_name); - return -1; -} - -static char * -_cdata_get_indexed_ptr(CDataObject *cd, PyObject *key) -{ - Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError); - if (i == -1 && PyErr_Occurred()) - return NULL; - - if (cd->c_type->ct_flags & CT_POINTER) { - if (CDataOwn_Check(cd)) { - if (i != 0) { - PyErr_Format(PyExc_IndexError, - "cdata '%s' can only be indexed by 0", - cd->c_type->ct_name); - return NULL; - } - } - else { - if (cd->c_data == NULL) { - PyErr_Format(PyExc_RuntimeError, - "cannot dereference null pointer from cdata '%s'", - cd->c_type->ct_name); - return NULL; - } - } - } - else if (cd->c_type->ct_flags & CT_ARRAY) { - if (i < 0) { - PyErr_SetString(PyExc_IndexError, - "negative index"); - return NULL; - } - if (i >= get_array_length(cd)) { - PyErr_Format(PyExc_IndexError, - "index too large for cdata '%s' (expected %zd < %zd)", - cd->c_type->ct_name, - i, get_array_length(cd)); - return NULL; - } - } - else { - PyErr_Format(PyExc_TypeError, "cdata of type '%s' cannot be indexed", - cd->c_type->ct_name); - return NULL; - } - return cd->c_data + i * cd->c_type->ct_itemdescr->ct_size; -} - -static PyObject * -new_array_type(CTypeDescrObject *ctptr, Py_ssize_t length); /* forward */ - -static CTypeDescrObject * -_cdata_getslicearg(CDataObject *cd, PySliceObject *slice, Py_ssize_t bounds[]) -{ - Py_ssize_t start, stop; - CTypeDescrObject *ct; - - start = PyInt_AsSsize_t(slice->start); - if (start == -1 && PyErr_Occurred()) { - if (slice->start == Py_None) - PyErr_SetString(PyExc_IndexError, "slice start must be specified"); - return NULL; - } - stop = PyInt_AsSsize_t(slice->stop); - if (stop == -1 && PyErr_Occurred()) { - if (slice->stop == Py_None) - PyErr_SetString(PyExc_IndexError, "slice stop must be specified"); - return NULL; - } - if (slice->step != Py_None) { - PyErr_SetString(PyExc_IndexError, "slice with step not supported"); - return NULL; - } - if (start > stop) { - PyErr_SetString(PyExc_IndexError, "slice start > stop"); - return NULL; - } - - ct = cd->c_type; - if (ct->ct_flags & CT_ARRAY) { - if (start < 0) { - PyErr_SetString(PyExc_IndexError, - "negative index"); - return NULL; - } - if (stop > get_array_length(cd)) { - PyErr_Format(PyExc_IndexError, - "index too large (expected %zd <= %zd)", - stop, get_array_length(cd)); - return NULL; - } - ct = (CTypeDescrObject *)ct->ct_stuff; - } - else if (!(ct->ct_flags & CT_POINTER)) { - PyErr_Format(PyExc_TypeError, "cdata of type '%s' cannot be indexed", - ct->ct_name); - return NULL; - } - - bounds[0] = start; - bounds[1] = stop - start; - return ct; -} - -static PyObject * -cdata_slice(CDataObject *cd, PySliceObject *slice) -{ - char *cdata; - Py_ssize_t bounds[2]; - CTypeDescrObject *ct = _cdata_getslicearg(cd, slice, bounds); - if (ct == NULL) - return NULL; - - if (ct->ct_stuff == NULL) { - ct->ct_stuff = new_array_type(ct, -1); - if (ct->ct_stuff == NULL) - return NULL; - } - ct = (CTypeDescrObject *)ct->ct_stuff; - - cdata = cd->c_data + ct->ct_itemdescr->ct_size * bounds[0]; - return new_sized_cdata(cdata, ct, bounds[1]); -} - -static int -cdata_ass_slice(CDataObject *cd, PySliceObject *slice, PyObject *v) -{ - Py_ssize_t bounds[2], i, length, itemsize; - PyObject *it, *item; - PyObject *(*iternext)(PyObject *); - char *cdata; - int err; - CTypeDescrObject *ct = _cdata_getslicearg(cd, slice, bounds); - if (ct == NULL) - return -1; - ct = ct->ct_itemdescr; - itemsize = ct->ct_size; - cdata = cd->c_data + itemsize * bounds[0]; - length = bounds[1]; - - if (CData_Check(v)) { - CTypeDescrObject *ctv = ((CDataObject *)v)->c_type; - if ((ctv->ct_flags & CT_ARRAY) && (ctv->ct_itemdescr == ct) && - (get_array_length((CDataObject *)v) == length)) { - /* fast path: copying from exactly the correct type */ - memmove(cdata, ((CDataObject *)v)->c_data, itemsize * length); - return 0; - } - } - - /* A fast path for <char[]>[0:N] = b"somestring" or bytearray, which - also adds support for Python 3: otherwise, you get integers while - enumerating the string, and you can't set them to characters :-/ - */ - if ((ct->ct_flags & CT_PRIMITIVE_CHAR) && itemsize == sizeof(char)) { - char *src; - Py_ssize_t srclen; - if (PyBytes_Check(v)) { - srclen = PyBytes_GET_SIZE(v); - src = PyBytes_AS_STRING(v); - } - else if (PyByteArray_Check(v)) { - srclen = PyByteArray_GET_SIZE(v); - src = PyByteArray_AS_STRING(v); - } - else - goto other_types; - - if (srclen != length) { - PyErr_Format(PyExc_ValueError, - "need a string of length %zd, got %zd", - length, srclen); - return -1; - } - memcpy(cdata, src, length); - return 0; - } - other_types: - - it = PyObject_GetIter(v); - if (it == NULL) - return -1; - iternext = *it->ob_type->tp_iternext; - - for (i = 0; i < length; i++) { - item = iternext(it); - if (item == NULL) { - if (!PyErr_Occurred()) - PyErr_Format(PyExc_ValueError, - "need %zd values to unpack, got %zd", - length, i); - goto error; - } - err = convert_from_object(cdata, ct, item); - Py_DECREF(item); - if (err < 0) - goto error; - - cdata += itemsize; - } - item = iternext(it); - if (item != NULL) { - Py_DECREF(item); - PyErr_Format(PyExc_ValueError, - "got more than %zd values to unpack", length); - } - error: - Py_DECREF(it); - return PyErr_Occurred() ? -1 : 0; -} - -static PyObject * -cdataowning_subscript(CDataObject *cd, PyObject *key) -{ - char *c; - if (PySlice_Check(key)) - return cdata_slice(cd, (PySliceObject *)key); - - c = _cdata_get_indexed_ptr(cd, key); - /* use 'mp_subscript' instead of 'sq_item' because we don't want - negative indexes to be corrected automatically */ - if (c == NULL && PyErr_Occurred()) - return NULL; - - if (cd->c_type->ct_flags & CT_IS_PTR_TO_OWNED) { - PyObject *res = ((CDataObject_own_structptr *)cd)->structobj; - Py_INCREF(res); - return res; - } - else { - return convert_to_object(c, cd->c_type->ct_itemdescr); - } -} - -static PyObject * -cdata_subscript(CDataObject *cd, PyObject *key) -{ - char *c; - if (PySlice_Check(key)) - return cdata_slice(cd, (PySliceObject *)key); - - c = _cdata_get_indexed_ptr(cd, key); - /* use 'mp_subscript' instead of 'sq_item' because we don't want - negative indexes to be corrected automatically */ - if (c == NULL && PyErr_Occurred()) - return NULL; - return convert_to_object(c, cd->c_type->ct_itemdescr); -} - -static int -cdata_ass_sub(CDataObject *cd, PyObject *key, PyObject *v) -{ - char *c; - CTypeDescrObject *ctitem; - if (PySlice_Check(key)) - return cdata_ass_slice(cd, (PySliceObject *)key, v); - - c = _cdata_get_indexed_ptr(cd, key); - ctitem = cd->c_type->ct_itemdescr; - /* use 'mp_ass_subscript' instead of 'sq_ass_item' because we don't want - negative indexes to be corrected automatically */ - if (c == NULL && PyErr_Occurred()) - return -1; - if (v == NULL) { - PyErr_SetString(PyExc_TypeError, - "'del x[n]' not supported for cdata objects"); - return -1; - } - return convert_from_object(c, ctitem, v); -} - -static PyObject * -_cdata_add_or_sub(PyObject *v, PyObject *w, int sign) -{ - Py_ssize_t i, itemsize; - CDataObject *cd; - CTypeDescrObject *ctptr; - - if (!CData_Check(v)) { - PyObject *swap; - assert(CData_Check(w)); - if (sign != 1) - goto not_implemented; - swap = v; - v = w; - w = swap; - } - - i = PyNumber_AsSsize_t(w, PyExc_OverflowError); - if (i == -1 && PyErr_Occurred()) - return NULL; - i *= sign; - - cd = (CDataObject *)v; - if (cd->c_type->ct_flags & CT_POINTER) - ctptr = cd->c_type; - else if (cd->c_type->ct_flags & CT_ARRAY) { - ctptr = (CTypeDescrObject *)cd->c_type->ct_stuff; - } - else { - PyErr_Format(PyExc_TypeError, "cannot add a cdata '%s' and a number", - cd->c_type->ct_name); - return NULL; - } - itemsize = ctptr->ct_itemdescr->ct_size; - if (itemsize < 0) { - if (ctptr->ct_flags & CT_IS_VOID_PTR) { - itemsize = 1; - } - else { - PyErr_Format(PyExc_TypeError, - "ctype '%s' points to items of unknown size", - cd->c_type->ct_name); - return NULL; - } - } - return new_simple_cdata(cd->c_data + i * itemsize, ctptr); - - not_implemented: - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; -} - -static PyObject * -cdata_add(PyObject *v, PyObject *w) -{ - return _cdata_add_or_sub(v, w, +1); -} - -static PyObject * -cdata_sub(PyObject *v, PyObject *w) -{ - if (CData_Check(v) && CData_Check(w)) { - CDataObject *cdv = (CDataObject *)v; - CDataObject *cdw = (CDataObject *)w; - CTypeDescrObject *ct = cdw->c_type; - Py_ssize_t diff, itemsize; - - if (ct->ct_flags & CT_ARRAY) /* ptr_to_T - array_of_T: ok */ - ct = (CTypeDescrObject *)ct->ct_stuff; - - if (ct != cdv->c_type || !(ct->ct_flags & CT_POINTER) || - (ct->ct_itemdescr->ct_size <= 0 && - !(ct->ct_flags & CT_IS_VOID_PTR))) { - PyErr_Format(PyExc_TypeError, - "cannot subtract cdata '%s' and cdata '%s'", - cdv->c_type->ct_name, ct->ct_name); - return NULL; - } - itemsize = ct->ct_itemdescr->ct_size; - diff = cdv->c_data - cdw->c_data; - if (itemsize > 1) { - if (diff % itemsize) { - PyErr_SetString(PyExc_ValueError, - "pointer subtraction: the distance between the two " - "pointers is not a multiple of the item size"); - return NULL; - } - diff = diff / itemsize; - } -#if PY_MAJOR_VERSION < 3 - return PyInt_FromSsize_t(diff); -#else - return PyLong_FromSsize_t(diff); -#endif - } - - return _cdata_add_or_sub(v, w, -1); -} - -static void -_cdata_attr_errmsg(char *errmsg, CDataObject *cd, PyObject *attr) -{ - const char *text; - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) - return; - PyErr_Clear(); - text = PyText_AsUTF8(attr); - if (text == NULL) - return; - PyErr_Format(PyExc_AttributeError, errmsg, cd->c_type->ct_name, text); -} - -static PyObject * -cdata_getattro(CDataObject *cd, PyObject *attr) -{ - CFieldObject *cf; - CTypeDescrObject *ct = cd->c_type; - char *errmsg = "cdata '%s' has no attribute '%s'"; - PyObject *x; - - if (ct->ct_flags & CT_POINTER) - ct = ct->ct_itemdescr; - - if (ct->ct_flags & (CT_STRUCT|CT_UNION)) { - switch (force_lazy_struct(ct)) { - case 1: - cf = (CFieldObject *)PyDict_GetItem(ct->ct_stuff, attr); - if (cf != NULL) { - /* read the field 'cf' */ - char *data = cd->c_data + cf->cf_offset; - Py_ssize_t array_len, size; - - if (cf->cf_bitshift == BS_REGULAR) { - return convert_to_object(data, cf->cf_type); - } - else if (cf->cf_bitshift != BS_EMPTY_ARRAY) { - return convert_to_object_bitfield(data, cf); - } - - /* variable-length array: */ - /* if reading variable length array from variable length - struct, calculate array type from allocated length */ - size = _cdata_var_byte_size(cd) - cf->cf_offset; - if (size >= 0) { - array_len = size / cf->cf_type->ct_itemdescr->ct_size; - return new_sized_cdata(data, cf->cf_type, array_len); - } - return new_simple_cdata(data, - (CTypeDescrObject *)cf->cf_type->ct_stuff); - } - errmsg = "cdata '%s' has no field '%s'"; - break; - case -1: - return NULL; - default: - errmsg = "cdata '%s' points to an opaque type: cannot read fields"; - break; - } - } - x = PyObject_GenericGetAttr((PyObject *)cd, attr); - if (x == NULL) - _cdata_attr_errmsg(errmsg, cd, attr); - return x; -} - -static int -cdata_setattro(CDataObject *cd, PyObject *attr, PyObject *value) -{ - CFieldObject *cf; - CTypeDescrObject *ct = cd->c_type; - char *errmsg = "cdata '%s' has no attribute '%s'"; - int x; - - if (ct->ct_flags & CT_POINTER) - ct = ct->ct_itemdescr; - - if (ct->ct_flags & (CT_STRUCT|CT_UNION)) { - switch (force_lazy_struct(ct)) { - case 1: - cf = (CFieldObject *)PyDict_GetItem(ct->ct_stuff, attr); - if (cf != NULL) { - /* write the field 'cf' */ - if (value != NULL) { - return convert_field_from_object(cd->c_data, cf, value); - } - else { - PyErr_SetString(PyExc_AttributeError, - "cannot delete struct field"); - return -1; - } - } - errmsg = "cdata '%s' has no field '%s'"; - break; - case -1: - return -1; - default: - errmsg = "cdata '%s' points to an opaque type: cannot write fields"; - break; - } - } - x = PyObject_GenericSetAttr((PyObject *)cd, attr, value); - if (x < 0) - _cdata_attr_errmsg(errmsg, cd, attr); - return x; -} - -static PyObject * -convert_struct_to_owning_object(char *data, CTypeDescrObject *ct); /*forward*/ - -static cif_description_t * -fb_prepare_cif(PyObject *fargs, CTypeDescrObject *, Py_ssize_t, ffi_abi); - /*forward*/ - -static PyObject *new_primitive_type(const char *name); /*forward*/ - -static CTypeDescrObject *_get_ct_int(void) -{ - static CTypeDescrObject *ct_int = NULL; - if (ct_int == NULL) { - ct_int = (CTypeDescrObject *)new_primitive_type("int"); - } - return ct_int; -} - -static Py_ssize_t -_prepare_pointer_call_argument(CTypeDescrObject *ctptr, PyObject *init, - char **output_data) -{ - /* 'ctptr' is here a pointer type 'ITEM *'. Accept as argument an - initializer for an array 'ITEM[]'. This includes the case of - passing a Python byte string to a 'char *' argument. - - This function returns -1 if an error occurred, - 0 if conversion succeeded (into *output_data), - or N > 0 if conversion would require N bytes of storage. - */ - Py_ssize_t length, datasize; - CTypeDescrObject *ctitem; - - if (CData_Check(init)) - goto convert_default; - - ctitem = ctptr->ct_itemdescr; - /* XXX some code duplication, how to avoid it? */ - if (PyBytes_Check(init)) { - /* from a string: just returning the string here is fine. - We assume that the C code won't modify the 'char *' data. */ - if ((ctptr->ct_flags & CT_IS_VOIDCHAR_PTR) || - ((ctitem->ct_flags & (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_UNSIGNED)) - && (ctitem->ct_size == sizeof(char)))) { -#if defined(CFFI_MEM_DEBUG) || defined(CFFI_MEM_LEAK) - length = PyBytes_GET_SIZE(init) + 1; -#else - *output_data = PyBytes_AS_STRING(init); - if (ctitem->ct_flags & CT_IS_BOOL) - if (must_be_array_of_zero_or_one(*output_data, - PyBytes_GET_SIZE(init)) < 0) - return -1; - return 0; -#endif - } - else - goto convert_default; - } - else if (PyList_Check(init) || PyTuple_Check(init)) { - length = PySequence_Fast_GET_SIZE(init); - } - else if (PyUnicode_Check(init)) { - /* from a unicode, we add the null terminator */ - if (ctitem->ct_size == 2) - length = _my_PyUnicode_SizeAsChar16(init); - else - length = _my_PyUnicode_SizeAsChar32(init); - length += 1; - } - else if ((ctitem->ct_flags & CT_IS_FILE) && PyFile_Check(init)) { - *output_data = (char *)PyFile_AsFile(init); - if (*output_data == NULL && PyErr_Occurred()) - return -1; - return 0; - } - else { - /* refuse to receive just an integer (and interpret it - as the array size) */ - goto convert_default; - } - - if (ctitem->ct_size <= 0) - goto convert_default; - datasize = MUL_WRAPAROUND(length, ctitem->ct_size); - if ((datasize / ctitem->ct_size) != length) { - PyErr_SetString(PyExc_OverflowError, - "array size would overflow a Py_ssize_t"); - return -1; - } - if (datasize <= 0) - datasize = 1; - return datasize; - - convert_default: - return convert_from_object((char *)output_data, ctptr, init); -} - -static PyObject* -cdata_call(CDataObject *cd, PyObject *args, PyObject *kwds) -{ - char *buffer; - void** buffer_array; - cif_description_t *cif_descr; - Py_ssize_t i, nargs, nargs_declared; - PyObject *signature, *res = NULL, *fvarargs; - 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"); - return NULL; - } - signature = cd->c_type->ct_stuff; - nargs = PyTuple_Size(args); - if (nargs < 0) - return NULL; - nargs_declared = PyTuple_GET_SIZE(signature) - 2; - fresult = (CTypeDescrObject *)PyTuple_GET_ITEM(signature, 1); - fvarargs = NULL; - buffer = NULL; - - cif_descr = (cif_description_t *)cd->c_type->ct_extra; - - if (cif_descr != NULL) { - /* regular case: this function does not take '...' arguments */ - if (nargs != nargs_declared) { - errormsg = "'%s' expects %zd arguments, got %zd"; - bad_number_of_arguments: - PyErr_Format(PyExc_TypeError, errormsg, - cd->c_type->ct_name, nargs_declared, nargs); - goto error; - } - } - else { - /* call of a variadic function */ - ffi_abi fabi; - if (nargs < nargs_declared) { - errormsg = "'%s' expects at least %zd arguments, got %zd"; - goto bad_number_of_arguments; - } - fvarargs = PyTuple_New(nargs); - if (fvarargs == NULL) - goto error; - for (i = 0; i < nargs_declared; i++) { - PyObject *o = PyTuple_GET_ITEM(signature, 2 + i); - Py_INCREF(o); - PyTuple_SET_ITEM(fvarargs, i, o); - } - for (i = nargs_declared; i < nargs; i++) { - PyObject *obj = PyTuple_GET_ITEM(args, i); - CTypeDescrObject *ct; - - if (CData_Check(obj)) { - ct = ((CDataObject *)obj)->c_type; - if (ct->ct_flags & (CT_PRIMITIVE_CHAR | CT_PRIMITIVE_UNSIGNED | - CT_PRIMITIVE_SIGNED)) { - if (ct->ct_size < (Py_ssize_t)sizeof(int)) { - ct = _get_ct_int(); - if (ct == NULL) - goto error; - } - } - else if (ct->ct_flags & CT_ARRAY) { - ct = (CTypeDescrObject *)ct->ct_stuff; - } - Py_INCREF(ct); - } - else { - PyErr_Format(PyExc_TypeError, - "argument %zd passed in the variadic part " - "needs to be a cdata object (got %.200s)", - i + 1, Py_TYPE(obj)->tp_name); - goto error; - } - PyTuple_SET_ITEM(fvarargs, i, (PyObject *)ct); - } -#if PY_MAJOR_VERSION < 3 - fabi = PyInt_AS_LONG(PyTuple_GET_ITEM(signature, 0)); -#else - fabi = PyLong_AS_LONG(PyTuple_GET_ITEM(signature, 0)); -#endif - cif_descr = fb_prepare_cif(fvarargs, fresult, nargs_declared, fabi); - if (cif_descr == NULL) - goto error; - } - - buffer = PyObject_Malloc(cif_descr->exchange_size); - if (buffer == NULL) { - PyErr_NoMemory(); - goto error; - } - - buffer_array = (void **)buffer; - - for (i=0; i<nargs; i++) { - CTypeDescrObject *argtype; - char *data = buffer + cif_descr->exchange_offset_arg[1 + i]; - PyObject *obj = PyTuple_GET_ITEM(args, i); - - buffer_array[i] = data; - - if (i < nargs_declared) - argtype = (CTypeDescrObject *)PyTuple_GET_ITEM(signature, 2 + i); - else - argtype = (CTypeDescrObject *)PyTuple_GET_ITEM(fvarargs, i); - - if (argtype->ct_flags & CT_POINTER) { - char *tmpbuf; - Py_ssize_t datasize = _prepare_pointer_call_argument( - argtype, obj, (char **)data); - if (datasize == 0) - ; /* successfully filled '*data' */ - else if (datasize < 0) - goto error; - else { - 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) - goto error; - } - } - else if (convert_from_object(data, argtype, obj) < 0) - goto error; - } - - resultdata = buffer + cif_descr->exchange_offset_arg[0]; - /*READ(cd->c_data, sizeof(void(*)(void)))*/ - - Py_BEGIN_ALLOW_THREADS - restore_errno(); - ffi_call(&cif_descr->cif, (void (*)(void))(cd->c_data), - resultdata, buffer_array); - save_errno(); - Py_END_ALLOW_THREADS - - if (fresult->ct_flags & (CT_PRIMITIVE_CHAR | CT_PRIMITIVE_SIGNED | - CT_PRIMITIVE_UNSIGNED)) { -#ifdef WORDS_BIGENDIAN - /* For results of precisely these types, libffi has a strange - rule that they will be returned as a whole 'ffi_arg' if they - are smaller. The difference only matters on big-endian. */ - if (fresult->ct_size < sizeof(ffi_arg)) - resultdata += (sizeof(ffi_arg) - fresult->ct_size); -#endif - res = convert_to_object(resultdata, fresult); - } - else if (fresult->ct_flags & CT_VOID) { - res = Py_None; - Py_INCREF(res); - } - else if (fresult->ct_flags & CT_STRUCT) { - res = convert_struct_to_owning_object(resultdata, fresult); - } - else { - res = convert_to_object(resultdata, fresult); - } - /* fall-through */ - - error: - while (freeme != NULL) { - void *p = (void *)freeme; - freeme = freeme->next; - PyObject_Free(p); - } - if (buffer) - PyObject_Free(buffer); - if (fvarargs != NULL) { - Py_DECREF(fvarargs); - if (cif_descr != NULL) /* but only if fvarargs != NULL, if variadic */ - PyObject_Free(cif_descr); - } - return res; -} - -static PyObject *cdata_dir(PyObject *cd, PyObject *noarg) -{ - CTypeDescrObject *ct = ((CDataObject *)cd)->c_type; - - /* replace the type 'pointer-to-t' with just 't' */ - if (ct->ct_flags & CT_POINTER) { - ct = ct->ct_itemdescr; - } - if ((ct->ct_flags & (CT_STRUCT | CT_UNION)) && - !(ct->ct_flags & CT_IS_OPAQUE)) { - - /* for non-opaque structs or unions */ - if (force_lazy_struct(ct) < 0) - return NULL; - return PyDict_Keys(ct->ct_stuff); - } - else { - return PyList_New(0); /* empty list for the other cases */ - } -} - -static PyObject *cdata_complex(PyObject *cd_, PyObject *noarg) -{ - CDataObject *cd = (CDataObject *)cd_; - - if (cd->c_type->ct_flags & CT_PRIMITIVE_COMPLEX) { - Py_complex value = read_raw_complex_data(cd->c_data, cd->c_type->ct_size); - PyObject *op = PyComplex_FromCComplex(value); - return op; - } - /* <cdata 'float'> or <cdata 'int'> cannot be directly converted by - calling complex(), just like <cdata 'int'> cannot be directly - converted by calling float() */ - - PyErr_Format(PyExc_TypeError, "complex() not supported on cdata '%s'", - cd->c_type->ct_name); - return NULL; -} - -static int explicit_release_case(PyObject *cd) -{ - CTypeDescrObject *ct = ((CDataObject *)cd)->c_type; - if (Py_TYPE(cd) == &CDataOwning_Type) { - if ((ct->ct_flags & (CT_POINTER | CT_ARRAY)) != 0) /* ffi.new() */ - return 0; - } - else if (Py_TYPE(cd) == &CDataFromBuf_Type) { - return 1; /* ffi.from_buffer() */ - } - else if (Py_TYPE(cd) == &CDataGCP_Type) { - return 2; /* ffi.gc() */ - } - PyErr_SetString(PyExc_ValueError, - "only 'cdata' object from ffi.new(), ffi.gc(), ffi.from_buffer() " - "or ffi.new_allocator()() can be used with the 'with' keyword or " - "ffi.release()"); - return -1; -} - -static PyObject *cdata_enter(PyObject *cd, PyObject *noarg) -{ - if (explicit_release_case(cd) < 0) /* only to check the ctype */ - return NULL; - Py_INCREF(cd); - return cd; -} - -static PyObject *cdata_exit(PyObject *cd, PyObject *args) -{ - /* 'args' ignored */ - CTypeDescrObject *ct; - Py_buffer *view; - switch (explicit_release_case(cd)) - { - case 0: /* ffi.new() */ - /* no effect on CPython: raw memory is allocated with the - same malloc() as the object itself, so it can't be - released independently. If we use a custom allocator, - then it's implemented with ffi.gc(). */ - ct = ((CDataObject *)cd)->c_type; - if (ct->ct_flags & CT_IS_PTR_TO_OWNED) { - 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 *") */ - cdatagcp_finalize((CDataObject_gcp *)x); - } - } - break; - - case 1: /* ffi.from_buffer() */ - view = ((CDataObject_frombuf *)cd)->bufferview; - PyBuffer_Release(view); - break; - - case 2: /* ffi.gc() or ffi.new_allocator()("not-struct-nor-union") */ - /* call the destructor immediately */ - cdatagcp_finalize((CDataObject_gcp *)cd); - break; - - default: - return NULL; - } - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject *cdata_iter(CDataObject *); - -static PyNumberMethods CData_as_number = { - (binaryfunc)cdata_add, /*nb_add*/ - (binaryfunc)cdata_sub, /*nb_subtract*/ - 0, /*nb_multiply*/ -#if PY_MAJOR_VERSION < 3 - 0, /*nb_divide*/ -#endif - 0, /*nb_remainder*/ - 0, /*nb_divmod*/ - 0, /*nb_power*/ - 0, /*nb_negative*/ - 0, /*nb_positive*/ - 0, /*nb_absolute*/ - (inquiry)cdata_nonzero, /*nb_nonzero*/ - 0, /*nb_invert*/ - 0, /*nb_lshift*/ - 0, /*nb_rshift*/ - 0, /*nb_and*/ - 0, /*nb_xor*/ - 0, /*nb_or*/ -#if PY_MAJOR_VERSION < 3 - 0, /*nb_coerce*/ -#endif - (unaryfunc)cdata_int, /*nb_int*/ -#if PY_MAJOR_VERSION < 3 - (unaryfunc)cdata_long, /*nb_long*/ -#else - 0, -#endif - (unaryfunc)cdata_float, /*nb_float*/ - 0, /*nb_oct*/ - 0, /*nb_hex*/ -}; - -static PyMappingMethods CData_as_mapping = { - (lenfunc)cdata_length, /*mp_length*/ - (binaryfunc)cdata_subscript, /*mp_subscript*/ - (objobjargproc)cdata_ass_sub, /*mp_ass_subscript*/ -}; - -static PyMappingMethods CDataOwn_as_mapping = { - (lenfunc)cdata_length, /*mp_length*/ - (binaryfunc)cdataowning_subscript, /*mp_subscript*/ - (objobjargproc)cdata_ass_sub, /*mp_ass_subscript*/ -}; - -static PyMethodDef cdata_methods[] = { - {"__dir__", cdata_dir, METH_NOARGS}, - {"__complex__", cdata_complex, METH_NOARGS}, - {"__enter__", cdata_enter, METH_NOARGS}, - {"__exit__", cdata_exit, METH_VARARGS}, - {NULL, NULL} /* sentinel */ -}; - -static PyTypeObject CData_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_cffi_backend._CDataBase", - sizeof(CDataObject), - 0, - (destructor)cdata_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - (reprfunc)cdata_repr, /* tp_repr */ - &CData_as_number, /* tp_as_number */ - 0, /* tp_as_sequence */ - &CData_as_mapping, /* tp_as_mapping */ - 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 */ - "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 */ - offsetof(CDataObject, c_weakreflist), /* tp_weaklistoffset */ - (getiterfunc)cdata_iter, /* tp_iter */ - 0, /* tp_iternext */ - cdata_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* 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_Del, /* tp_free */ -}; - -static PyTypeObject CDataOwning_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_cffi_backend.__CDataOwn", - sizeof(CDataObject), - 0, - (destructor)cdataowning_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - (reprfunc)cdataowning_repr, /* tp_repr */ - 0, /* inherited */ /* tp_as_number */ - 0, /* tp_as_sequence */ - &CDataOwn_as_mapping, /* 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 */ - "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 */ - 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 */ - free, /* tp_free */ -}; - -static PyTypeObject CDataOwningGC_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_cffi_backend.__CDataOwnGC", - sizeof(CDataObject_own_structptr), - 0, - (destructor)cdataowninggc_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - (reprfunc)cdataowninggc_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)cdataowninggc_traverse, /* tp_traverse */ - (inquiry)cdataowninggc_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 */ - &CDataOwning_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 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", - sizeof(CDataObject_gcp), - 0, - (destructor)cdatagcp_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* inherited */ /* 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 */ -#ifdef Py_TPFLAGS_HAVE_FINALIZE - | Py_TPFLAGS_HAVE_FINALIZE -#endif - | 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)cdatagcp_traverse, /* tp_traverse */ - 0, /* 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 */ -#ifdef Py_TPFLAGS_HAVE_FINALIZE /* CPython >= 3.4 */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - 0, /* tp_new */ - 0, /* inherited */ /* tp_free */ - 0, /* tp_is_gc */ - 0, /* tp_bases */ - 0, /* tp_mro */ - 0, /* tp_cache */ - 0, /* tp_subclasses */ - 0, /* tp_weaklist */ - 0, /* tp_del */ - 0, /* version_tag */ - (destructor)cdatagcp_finalize, /* tp_finalize */ -#endif -}; - -/************************************************************/ - -typedef struct { - PyObject_HEAD - char *di_next, *di_stop; - CDataObject *di_object; - CTypeDescrObject *di_itemtype; -} CDataIterObject; - -static PyObject * -cdataiter_next(CDataIterObject *it) -{ - char *result = it->di_next; - if (result != it->di_stop) { - it->di_next = result + it->di_itemtype->ct_size; - return convert_to_object(result, it->di_itemtype); - } - return NULL; -} - -static void -cdataiter_dealloc(CDataIterObject *it) -{ - Py_DECREF(it->di_object); - PyObject_Del(it); -} - -static PyTypeObject CDataIter_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_cffi_backend.__CData_iterator", /* tp_name */ - sizeof(CDataIterObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)cdataiter_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)cdataiter_next, /* tp_iternext */ -}; - -static PyObject * -cdata_iter(CDataObject *cd) -{ - CDataIterObject *it; - - if (!(cd->c_type->ct_flags & CT_ARRAY)) { - PyErr_Format(PyExc_TypeError, "cdata '%s' does not support iteration", - cd->c_type->ct_name); - return NULL; - } - - it = PyObject_New(CDataIterObject, &CDataIter_Type); - if (it == NULL) - return NULL; - - Py_INCREF(cd); - it->di_object = cd; - it->di_itemtype = cd->c_type->ct_itemdescr; - it->di_next = cd->c_data; - it->di_stop = cd->c_data + get_array_length(cd) * it->di_itemtype->ct_size; - return (PyObject *)it; -} - -/************************************************************/ - -static CDataObject *allocate_owning_object(Py_ssize_t size, - CTypeDescrObject *ct, - int dont_clear) -{ - /* note: objects with &CDataOwning_Type are always allocated with - either a plain malloc() or calloc(), and freed with free(). */ - CDataObject *cd; - if (dont_clear) - cd = malloc(size); - else - cd = calloc(size, 1); - if (PyObject_Init((PyObject *)cd, &CDataOwning_Type) == NULL) - return NULL; - - Py_INCREF(ct); - cd->c_type = ct; - cd->c_weakreflist = NULL; - return cd; -} - -static PyObject * -convert_struct_to_owning_object(char *data, CTypeDescrObject *ct) -{ - /* also accepts unions, for the API mode */ - CDataObject *cd; - Py_ssize_t dataoffset = offsetof(CDataObject_own_nolength, alignment); - Py_ssize_t datasize = ct->ct_size; - - if (datasize < 0) { - PyErr_SetString(PyExc_TypeError, - "return type is an opaque structure or union"); - return NULL; - } - if (ct->ct_flags & CT_WITH_VAR_ARRAY) { - PyErr_SetString(PyExc_TypeError, - "return type is a struct/union with a varsize array member"); - return NULL; - } - cd = allocate_owning_object(dataoffset + datasize, ct, /*dont_clear=*/1); - if (cd == NULL) - return NULL; - cd->c_data = ((char *)cd) + dataoffset; - - memcpy(cd->c_data, data, datasize); - return (PyObject *)cd; -} - -static CDataObject *allocate_gcp_object(CDataObject *origobj, - CTypeDescrObject *ct, - PyObject *destructor) -{ - CDataObject_gcp *cd = PyObject_GC_New(CDataObject_gcp, &CDataGCP_Type); - if (cd == NULL) - return NULL; - - Py_XINCREF(destructor); - Py_INCREF(origobj); - Py_INCREF(ct); - cd->head.c_data = origobj->c_data; - cd->head.c_type = ct; - cd->head.c_weakreflist = NULL; - cd->origobj = (PyObject *)origobj; - cd->destructor = destructor; - - PyObject_GC_Track(cd); - return (CDataObject *)cd; -} - -static CDataObject *allocate_with_allocator(Py_ssize_t basesize, - Py_ssize_t datasize, - CTypeDescrObject *ct, - const cffi_allocator_t *allocator) -{ - CDataObject *cd; - - if (allocator->ca_alloc == NULL) { - cd = allocate_owning_object(basesize + datasize, ct, - allocator->ca_dont_clear); - if (cd == NULL) - return NULL; - cd->c_data = ((char *)cd) + basesize; - } - else { - PyObject *res = PyObject_CallFunction(allocator->ca_alloc, "n", datasize); - if (res == NULL) - return NULL; - - if (!CData_Check(res)) { - PyErr_Format(PyExc_TypeError, - "alloc() must return a cdata object (got %.200s)", - Py_TYPE(res)->tp_name); - Py_DECREF(res); - return NULL; - } - cd = (CDataObject *)res; - if (!(cd->c_type->ct_flags & (CT_POINTER|CT_ARRAY))) { - PyErr_Format(PyExc_TypeError, - "alloc() must return a cdata pointer, not '%s'", - cd->c_type->ct_name); - Py_DECREF(res); - return NULL; - } - if (!cd->c_data) { - PyErr_SetString(PyExc_MemoryError, "alloc() returned NULL"); - Py_DECREF(res); - return NULL; - } - - cd = allocate_gcp_object(cd, ct, allocator->ca_free); - Py_DECREF(res); - if (!allocator->ca_dont_clear) - memset(cd->c_data, 0, datasize); - } - return cd; -} - -static PyObject *direct_newp(CTypeDescrObject *ct, PyObject *init, - const cffi_allocator_t *allocator) -{ - CTypeDescrObject *ctitem; - CDataObject *cd; - Py_ssize_t dataoffset, datasize, explicitlength; - - explicitlength = -1; - if (ct->ct_flags & CT_POINTER) { - dataoffset = offsetof(CDataObject_own_nolength, alignment); - ctitem = ct->ct_itemdescr; - datasize = ctitem->ct_size; - if (datasize < 0) { - PyErr_Format(PyExc_TypeError, - "cannot instantiate ctype '%s' of unknown size", - ctitem->ct_name); - return NULL; - } - if (ctitem->ct_flags & CT_PRIMITIVE_CHAR) - datasize *= 2; /* forcefully add another character: a null */ - - if (ctitem->ct_flags & (CT_STRUCT | CT_UNION)) { - if (force_lazy_struct(ctitem) < 0) /* for CT_WITH_VAR_ARRAY */ - return NULL; - - if (ctitem->ct_flags & CT_WITH_VAR_ARRAY) { - assert(ct->ct_flags & CT_IS_PTR_TO_OWNED); - dataoffset = offsetof(CDataObject_own_length, alignment); - - if (init != Py_None) { - Py_ssize_t optvarsize = datasize; - if (convert_struct_from_object(NULL, ctitem, init, - &optvarsize) < 0) - return NULL; - datasize = optvarsize; - } - } - } - } - else if (ct->ct_flags & CT_ARRAY) { - dataoffset = offsetof(CDataObject_own_nolength, alignment); - datasize = ct->ct_size; - if (datasize < 0) { - explicitlength = get_new_array_length(ct->ct_itemdescr, &init); - if (explicitlength < 0) - return NULL; - ctitem = ct->ct_itemdescr; - dataoffset = offsetof(CDataObject_own_length, alignment); - datasize = MUL_WRAPAROUND(explicitlength, ctitem->ct_size); - if (explicitlength > 0 && - (datasize / explicitlength) != ctitem->ct_size) { - PyErr_SetString(PyExc_OverflowError, - "array size would overflow a Py_ssize_t"); - return NULL; - } - } - } - else { - PyErr_Format(PyExc_TypeError, - "expected a pointer or array ctype, got '%s'", - ct->ct_name); - return NULL; - } - - if (ct->ct_flags & CT_IS_PTR_TO_OWNED) { - /* common case of ptr-to-struct (or ptr-to-union): for this case - we build two objects instead of one, with the memory-owning - one being really the struct (or union) and the returned one - having a strong reference to it */ - CDataObject *cds; - - cds = allocate_with_allocator(dataoffset, datasize, ct->ct_itemdescr, - allocator); - if (cds == NULL) - return NULL; - - cd = allocate_owning_object(sizeof(CDataObject_own_structptr), ct, - /*dont_clear=*/1); - if (cd == NULL) { - Py_DECREF(cds); - return NULL; - } - /* store the only reference to cds into cd */ - ((CDataObject_own_structptr *)cd)->structobj = (PyObject *)cds; - /* store information about the allocated size of the struct */ - if (dataoffset == offsetof(CDataObject_own_length, alignment)) { - ((CDataObject_own_length *)cds)->length = datasize; - } - assert(explicitlength < 0); - - cd->c_data = cds->c_data; - } - else { - cd = allocate_with_allocator(dataoffset, datasize, ct, allocator); - if (cd == NULL) - return NULL; - - if (explicitlength >= 0) - ((CDataObject_own_length*)cd)->length = explicitlength; - } - - if (init != Py_None) { - if (convert_from_object(cd->c_data, - (ct->ct_flags & CT_POINTER) ? ct->ct_itemdescr : ct, init) < 0) { - Py_DECREF(cd); - return NULL; - } - } - return (PyObject *)cd; -} - -static PyObject *b_newp(PyObject *self, PyObject *args) -{ - CTypeDescrObject *ct; - PyObject *init = Py_None; - if (!PyArg_ParseTuple(args, "O!|O:newp", &CTypeDescr_Type, &ct, &init)) - return NULL; - return direct_newp(ct, init, &default_allocator); -} - -static int -_my_PyObject_AsBool(PyObject *ob) -{ - /* convert and cast a Python object to a boolean. Accept an integer - or a float object, up to a CData 'long double'. */ - PyObject *io; - PyNumberMethods *nb; - int res; - -#if PY_MAJOR_VERSION < 3 - if (PyInt_Check(ob)) { - return PyInt_AS_LONG(ob) != 0; - } - else -#endif - if (PyLong_Check(ob)) { - return _PyLong_Sign(ob) != 0; - } - else if (PyFloat_Check(ob)) { - return PyFloat_AS_DOUBLE(ob) != 0.0; - } - else if (CData_Check(ob)) { - CDataObject *cd = (CDataObject *)ob; - if (cd->c_type->ct_flags & CT_PRIMITIVE_FLOAT) { - /*READ(cd->c_data, cd->c_type->ct_size)*/ - if (cd->c_type->ct_flags & CT_IS_LONGDOUBLE) { - /* 'long double' objects: return the answer directly */ - return read_raw_longdouble_data(cd->c_data) != 0.0; - } - else { - /* 'float'/'double' objects: return the answer directly */ - return read_raw_float_data(cd->c_data, - cd->c_type->ct_size) != 0.0; - } - } - } - nb = ob->ob_type->tp_as_number; - if (nb == NULL || (nb->nb_float == NULL && nb->nb_int == NULL)) { - PyErr_SetString(PyExc_TypeError, "integer/float expected"); - return -1; - } - if (nb->nb_float && !CData_Check(ob)) - io = (*nb->nb_float) (ob); - else - io = (*nb->nb_int) (ob); - if (io == NULL) - return -1; - - if (PyIntOrLong_Check(io) || PyFloat_Check(io)) { - res = _my_PyObject_AsBool(io); - } - else { - PyErr_SetString(PyExc_TypeError, "integer/float conversion failed"); - res = -1; - } - Py_DECREF(io); - return res; -} - -static CDataObject *_new_casted_primitive(CTypeDescrObject *ct) -{ - int dataoffset = offsetof(CDataObject_casted_primitive, alignment); - CDataObject *cd = (CDataObject *)PyObject_Malloc(dataoffset + ct->ct_size); - if (PyObject_Init((PyObject *)cd, &CData_Type) == NULL) - return NULL; - Py_INCREF(ct); - cd->c_type = ct; - cd->c_data = ((char*)cd) + dataoffset; - cd->c_weakreflist = NULL; - return cd; -} - -static CDataObject *cast_to_integer_or_char(CTypeDescrObject *ct, PyObject *ob) -{ - unsigned PY_LONG_LONG value; - CDataObject *cd; - - if (CData_Check(ob) && - ((CDataObject *)ob)->c_type->ct_flags & - (CT_POINTER|CT_FUNCTIONPTR|CT_ARRAY)) { - value = (Py_intptr_t)((CDataObject *)ob)->c_data; - } -#if PY_MAJOR_VERSION < 3 - else if (PyString_Check(ob)) { - if (PyString_GET_SIZE(ob) != 1) { - PyErr_Format(PyExc_TypeError, - "cannot cast string of length %zd to ctype '%s'", - PyString_GET_SIZE(ob), ct->ct_name); - return NULL; - } - value = (unsigned char)PyString_AS_STRING(ob)[0]; - } -#endif - else if (PyUnicode_Check(ob)) { - char err_buf[80]; - cffi_char32_t ordinal; - if (_my_PyUnicode_AsSingleChar32(ob, &ordinal, err_buf) < 0) { - PyErr_Format(PyExc_TypeError, - "cannot cast %s to ctype '%s'", err_buf, ct->ct_name); - return NULL; - } - /* the types char16_t and char32_t are both unsigned. However, - wchar_t might be signed. In theory it does not matter, - because 'ordinal' comes from a regular Python unicode. */ -#ifdef HAVE_WCHAR_H - if (ct->ct_flags & CT_IS_SIGNED_WCHAR) - value = (wchar_t)ordinal; - else -#endif - value = ordinal; - } - else if (PyBytes_Check(ob)) { - int res = _convert_to_char(ob); - if (res < 0) - return NULL; - value = (unsigned char)res; - } - else if (ct->ct_flags & CT_IS_BOOL) { - int res = _my_PyObject_AsBool(ob); - if (res < 0) - return NULL; - value = res; - } - else { - value = _my_PyLong_AsUnsignedLongLong(ob, 0); - if (value == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred()) - return NULL; - } - if (ct->ct_flags & CT_IS_BOOL) - value = !!value; - cd = _new_casted_primitive(ct); - if (cd != NULL) - write_raw_integer_data(cd->c_data, value, ct->ct_size); - return cd; -} - -/* returns -1 if cannot cast, 0 if we don't get a value, 1 if we do */ -static int check_bytes_for_float_compatible(PyObject *io, double *out_value) -{ - if (PyBytes_Check(io)) { - if (PyBytes_GET_SIZE(io) != 1) - goto error; - *out_value = (unsigned char)PyBytes_AS_STRING(io)[0]; - return 1; - } - else if (PyUnicode_Check(io)) { - char ignored[80]; - cffi_char32_t ordinal; - if (_my_PyUnicode_AsSingleChar32(io, &ordinal, ignored) < 0) - goto error; - /* the signness of the 32-bit version of wide chars should not - * matter here, because 'ordinal' comes from a normal Python - * unicode string */ - *out_value = ordinal; - return 1; - } - *out_value = 0; /* silence a gcc warning if this function is inlined */ - return 0; - - error: - Py_DECREF(io); - *out_value = 0; /* silence a gcc warning if this function is inlined */ - return -1; -} - -static PyObject *do_cast(CTypeDescrObject *ct, PyObject *ob) -{ - CDataObject *cd; - - if (ct->ct_flags & (CT_POINTER|CT_FUNCTIONPTR|CT_ARRAY) && - ct->ct_size >= 0) { - /* cast to a pointer, to a funcptr, or to an array. - Note that casting to an array is an extension to the C language, - which seems to be necessary in order to sanely get a - <cdata 'int[3]'> at some address. */ - unsigned PY_LONG_LONG value; - - if (CData_Check(ob)) { - CDataObject *cdsrc = (CDataObject *)ob; - if (cdsrc->c_type->ct_flags & - (CT_POINTER|CT_FUNCTIONPTR|CT_ARRAY)) { - return new_simple_cdata(cdsrc->c_data, ct); - } - } - if ((ct->ct_flags & CT_POINTER) && - (ct->ct_itemdescr->ct_flags & CT_IS_FILE) && - PyFile_Check(ob)) { - FILE *f = PyFile_AsFile(ob); - if (f == NULL && PyErr_Occurred()) - return NULL; - return new_simple_cdata((char *)f, ct); - } - value = _my_PyLong_AsUnsignedLongLong(ob, 0); - if (value == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred()) - return NULL; - return new_simple_cdata((char *)(Py_intptr_t)value, ct); - } - else if (ct->ct_flags & (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_UNSIGNED - |CT_PRIMITIVE_CHAR)) { - /* cast to an integer type or a char */ - return (PyObject *)cast_to_integer_or_char(ct, ob); - } - else if (ct->ct_flags & CT_PRIMITIVE_FLOAT) { - /* cast to a float */ - double value; - PyObject *io; - int res; - - if (CData_Check(ob)) { - CDataObject *cdsrc = (CDataObject *)ob; - - if (!(cdsrc->c_type->ct_flags & CT_PRIMITIVE_ANY)) - goto cannot_cast; - io = convert_to_object(cdsrc->c_data, cdsrc->c_type); - if (io == NULL) - return NULL; - } - else { - io = ob; - Py_INCREF(io); - } - - res = check_bytes_for_float_compatible(io, &value); - if (res == -1) - goto cannot_cast; - if (res == 0) { - if ((ct->ct_flags & CT_IS_LONGDOUBLE) && - CData_Check(io) && - (((CDataObject *)io)->c_type->ct_flags & CT_IS_LONGDOUBLE)) { - long double lvalue; - char *data = ((CDataObject *)io)->c_data; - /*READ(data, sizeof(long double)*/ - lvalue = read_raw_longdouble_data(data); - Py_DECREF(io); - cd = _new_casted_primitive(ct); - if (cd != NULL) - write_raw_longdouble_data(cd->c_data, lvalue); - return (PyObject *)cd; - } - value = PyFloat_AsDouble(io); - } - Py_DECREF(io); - if (value == -1.0 && PyErr_Occurred()) - return NULL; - - cd = _new_casted_primitive(ct); - if (cd != NULL) { - if (!(ct->ct_flags & CT_IS_LONGDOUBLE)) - write_raw_float_data(cd->c_data, value, ct->ct_size); - else - write_raw_longdouble_data(cd->c_data, (long double)value); - } - return (PyObject *)cd; - } - else if (ct->ct_flags & CT_PRIMITIVE_COMPLEX) { - /* cast to a complex */ - Py_complex value; - PyObject *io; - int res; - - if (CData_Check(ob)) { - CDataObject *cdsrc = (CDataObject *)ob; - - if (!(cdsrc->c_type->ct_flags & CT_PRIMITIVE_ANY)) - goto cannot_cast; - io = convert_to_object(cdsrc->c_data, cdsrc->c_type); - if (io == NULL) - return NULL; - } - else { - io = ob; - Py_INCREF(io); - } - - res = check_bytes_for_float_compatible(io, &value.real); - if (res == -1) - goto cannot_cast; - if (res == 1) { - // got it from string - value.imag = 0.0; - } else { - value = PyComplex_AsCComplex(io); - } - Py_DECREF(io); - if (PyErr_Occurred()) { - return NULL; - } - cd = _new_casted_primitive(ct); - if (cd != NULL) { - write_raw_complex_data(cd->c_data, value, ct->ct_size); - } - return (PyObject *)cd; - } - else { - PyErr_Format(PyExc_TypeError, "cannot cast to ctype '%s'", - ct->ct_name); - return NULL; - } - - cannot_cast: - if (CData_Check(ob)) - PyErr_Format(PyExc_TypeError, "cannot cast ctype '%s' to ctype '%s'", - ((CDataObject *)ob)->c_type->ct_name, ct->ct_name); - else - PyErr_Format(PyExc_TypeError, - "cannot cast %.200s object to ctype '%s'", - Py_TYPE(ob)->tp_name, ct->ct_name); - return NULL; -} - -static PyObject *b_cast(PyObject *self, PyObject *args) -{ - CTypeDescrObject *ct; - PyObject *ob; - if (!PyArg_ParseTuple(args, "O!O:cast", &CTypeDescr_Type, &ct, &ob)) - return NULL; - - return do_cast(ct, ob); -} - -/************************************************************/ - -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 && dlobj->dl_auto_close) - dlclose(dlobj->dl_handle); - free(dlobj->dl_name); - PyObject_Del(dlobj); -} - -static PyObject *dl_repr(DynLibObject *dlobj) -{ - return PyText_FromFormat("<clibrary '%s'>", dlobj->dl_name); -} - -static int dl_check_closed(DynLibObject *dlobj) -{ - if (dlobj->dl_handle == NULL) - { - PyErr_Format(PyExc_ValueError, "library '%s' has already been closed", - dlobj->dl_name); - return -1; - } - return 0; -} - -static PyObject *dl_load_function(DynLibObject *dlobj, PyObject *args) -{ - CTypeDescrObject *ct; - char *funcname; - void *funcptr; - - if (!PyArg_ParseTuple(args, "O!s:load_function", - &CTypeDescr_Type, &ct, &funcname)) - return NULL; - - if (dl_check_closed(dlobj) < 0) - return NULL; - - if (!(ct->ct_flags & (CT_FUNCTIONPTR | CT_POINTER | CT_ARRAY))) { - PyErr_Format(PyExc_TypeError, - "function or pointer or array cdata expected, got '%s'", - ct->ct_name); - return NULL; - } - dlerror(); /* clear error condition */ - funcptr = dlsym(dlobj->dl_handle, funcname); - if (funcptr == NULL) { - const char *error = dlerror(); - PyErr_Format(PyExc_AttributeError, - "function/symbol '%s' not found in library '%s': %s", - funcname, dlobj->dl_name, error); - return NULL; - } - - if ((ct->ct_flags & CT_ARRAY) && ct->ct_length < 0) { - ct = (CTypeDescrObject *)ct->ct_stuff; - } - return new_simple_cdata(funcptr, ct); -} - -static PyObject *dl_read_variable(DynLibObject *dlobj, PyObject *args) -{ - CTypeDescrObject *ct; - char *varname; - char *data; - - if (!PyArg_ParseTuple(args, "O!s:read_variable", - &CTypeDescr_Type, &ct, &varname)) - return NULL; - - if (dl_check_closed(dlobj) < 0) - return NULL; - - dlerror(); /* clear error condition */ - data = dlsym(dlobj->dl_handle, varname); - if (data == NULL) { - const char *error = dlerror(); - if (error != NULL) { - PyErr_Format(PyExc_KeyError, - "variable '%s' not found in library '%s': %s", - varname, dlobj->dl_name, error); - return NULL; - } - } - return convert_to_object(data, ct); -} - -static PyObject *dl_write_variable(DynLibObject *dlobj, PyObject *args) -{ - CTypeDescrObject *ct; - PyObject *value; - char *varname; - char *data; - - if (!PyArg_ParseTuple(args, "O!sO:write_variable", - &CTypeDescr_Type, &ct, &varname, &value)) - return NULL; - - if (dl_check_closed(dlobj) < 0) - return NULL; - - dlerror(); /* clear error condition */ - data = dlsym(dlobj->dl_handle, varname); - if (data == NULL) { - const char *error = dlerror(); - PyErr_Format(PyExc_KeyError, - "variable '%s' not found in library '%s': %s", - varname, dlobj->dl_name, error); - return NULL; - } - if (convert_from_object(data, ct, value) < 0) - return NULL; - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject *dl_close_lib(DynLibObject *dlobj, PyObject *no_args) -{ - if (dlobj->dl_handle != NULL) - { - dlclose(dlobj->dl_handle); - dlobj->dl_handle = NULL; - } - Py_INCREF(Py_None); - return Py_None; -} - -static PyMethodDef dl_methods[] = { - {"load_function", (PyCFunction)dl_load_function, METH_VARARGS}, - {"read_variable", (PyCFunction)dl_read_variable, METH_VARARGS}, - {"write_variable", (PyCFunction)dl_write_variable, METH_VARARGS}, - {"close_lib", (PyCFunction)dl_close_lib, METH_NOARGS}, - {NULL, NULL} /* sentinel */ -}; - -static PyTypeObject dl_type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_cffi_backend.CLibrary", /* tp_name */ - sizeof(DynLibObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)dl_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - (reprfunc)dl_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - dl_methods, /* tp_methods */ -}; - -static void *b_do_dlopen(PyObject *args, const char **p_printable_filename, - 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 - the filename (maybe utf-8-encoded). '*p_temp' will be set either to NULL or - to a temporary object that must be freed after looking at printable_filename. - */ - void *handle; - 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; - if (!PyArg_ParseTuple(args, "|Oi:load_library", - &dummy, &flags)) - return NULL; - 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 - 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) - return NULL; - *p_temp = s; -#endif - *p_printable_filename = PyText_AsUTF8(s); - if (*p_printable_filename == NULL) - return NULL; - - 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(); -#endif - if (!PyArg_ParseTuple(args, "et|i:load_library", - Py_FileSystemDefaultEncoding, &filename_or_null, &flags)) - return NULL; -#if PY_MAJOR_VERSION < 3 - if (PyUnicode_Check(s)) - { - s = PyUnicode_AsUTF8String(s); - 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) { - 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: -#endif - if (handle == NULL) { - const char *error = dlerror(); - PyErr_Format(PyExc_OSError, "cannot load library '%s': %s", - *p_printable_filename, error); - return NULL; - } - return handle; -} - -static PyObject *b_load_library(PyObject *self, PyObject *args) -{ - const char *printable_filename; - PyObject *temp; - void *handle; - DynLibObject *dlobj = NULL; - int auto_close; - - handle = b_do_dlopen(args, &printable_filename, &temp, &auto_close); - if (handle == NULL) - goto error; - - dlobj = PyObject_New(DynLibObject, &dl_type); - if (dlobj == NULL) { - dlclose(handle); - goto error; - } - dlobj->dl_handle = handle; - dlobj->dl_name = strdup(printable_filename); - dlobj->dl_auto_close = auto_close; - - error: - Py_XDECREF(temp); - return (PyObject *)dlobj; -} - -/************************************************************/ - -static PyObject *get_unique_type(CTypeDescrObject *x, - const void *unique_key[], long keylength) -{ - /* Replace the CTypeDescrObject 'x' with a standardized one. - This either just returns x, or x is decrefed and a new reference - to the already-existing equivalent is returned. - - In this function, 'x' always contains a reference that must be - either decrefed or returned. - - Keys: - void ["void"] - primitive [&static_struct] - pointer [ctype] - array [ctype, length] - funcptr [ctresult, ellipsis+abi, num_args, ctargs...] - */ - PyObject *key, *y; - void *pkey; - - key = PyBytes_FromStringAndSize(NULL, keylength * sizeof(void *)); - if (key == NULL) - goto error; - - pkey = PyBytes_AS_STRING(key); - memcpy(pkey, unique_key, keylength * sizeof(void *)); - - y = PyDict_GetItem(unique_cache, key); - if (y != NULL) { - Py_DECREF(key); - Py_INCREF(y); - Py_DECREF(x); - return y; - } - if (PyDict_SetItem(unique_cache, key, (PyObject *)x) < 0) { - Py_DECREF(key); - goto error; - } - /* Haaaack for our reference count hack: gcmodule.c must not see this - dictionary. The problem is that any PyDict_SetItem() notices that - 'x' is tracked and re-tracks the unique_cache dictionary. So here - we re-untrack it again... */ - PyObject_GC_UnTrack(unique_cache); - - assert(x->ct_unique_key == NULL); - x->ct_unique_key = key; /* the key will be freed in ctypedescr_dealloc() */ - /* the 'value' in unique_cache doesn't count as 1, but don't use - Py_DECREF(x) here because it will confuse debug builds into thinking - there was an extra DECREF in total. */ - ((PyObject *)x)->ob_refcnt--; - return (PyObject *)x; - - error: - Py_DECREF(x); - return NULL; -} - -/* according to the C standard, these types should be equivalent to the - _Complex types for the purposes of storage (not arguments in calls!) */ -typedef float cffi_float_complex_t[2]; -typedef double cffi_double_complex_t[2]; - -static PyObject *new_primitive_type(const char *name) -{ -#define ENUM_PRIMITIVE_TYPES \ - EPTYPE(c, char, CT_PRIMITIVE_CHAR) \ - EPTYPE(s, short, CT_PRIMITIVE_SIGNED ) \ - EPTYPE(i, int, CT_PRIMITIVE_SIGNED ) \ - EPTYPE(l, long, CT_PRIMITIVE_SIGNED ) \ - EPTYPE(ll, long long, CT_PRIMITIVE_SIGNED ) \ - EPTYPE(sc, signed char, CT_PRIMITIVE_SIGNED ) \ - EPTYPE(uc, unsigned char, CT_PRIMITIVE_UNSIGNED ) \ - EPTYPE(us, unsigned short, CT_PRIMITIVE_UNSIGNED ) \ - EPTYPE(ui, unsigned int, CT_PRIMITIVE_UNSIGNED ) \ - EPTYPE(ul, unsigned long, CT_PRIMITIVE_UNSIGNED ) \ - EPTYPE(ull, unsigned long long, CT_PRIMITIVE_UNSIGNED ) \ - EPTYPE(f, float, CT_PRIMITIVE_FLOAT ) \ - EPTYPE(d, double, CT_PRIMITIVE_FLOAT ) \ - EPTYPE(ld, long double, CT_PRIMITIVE_FLOAT | CT_IS_LONGDOUBLE ) \ - EPTYPE2(fc, "float _Complex", cffi_float_complex_t, CT_PRIMITIVE_COMPLEX ) \ - EPTYPE2(dc, "double _Complex", cffi_double_complex_t, CT_PRIMITIVE_COMPLEX ) \ - ENUM_PRIMITIVE_TYPES_WCHAR \ - EPTYPE2(c16, "char16_t", cffi_char16_t, CT_PRIMITIVE_CHAR ) \ - EPTYPE2(c32, "char32_t", cffi_char32_t, CT_PRIMITIVE_CHAR ) \ - EPTYPE(b, _Bool, CT_PRIMITIVE_UNSIGNED | CT_IS_BOOL ) \ - /* the following types are not primitive in the C sense */ \ - EPTYPE(i8, int8_t, CT_PRIMITIVE_SIGNED) \ - EPTYPE(u8, uint8_t, CT_PRIMITIVE_UNSIGNED) \ - EPTYPE(i16, int16_t, CT_PRIMITIVE_SIGNED) \ - EPTYPE(u16, uint16_t, CT_PRIMITIVE_UNSIGNED) \ - EPTYPE(i32, int32_t, CT_PRIMITIVE_SIGNED) \ - EPTYPE(u32, uint32_t, CT_PRIMITIVE_UNSIGNED) \ - EPTYPE(i64, int64_t, CT_PRIMITIVE_SIGNED) \ - EPTYPE(u64, uint64_t, CT_PRIMITIVE_UNSIGNED) \ - EPTYPE(il8, int_least8_t, CT_PRIMITIVE_SIGNED) \ - EPTYPE(ul8, uint_least8_t, CT_PRIMITIVE_UNSIGNED) \ - EPTYPE(il16, int_least16_t, CT_PRIMITIVE_SIGNED) \ - EPTYPE(ul16, uint_least16_t, CT_PRIMITIVE_UNSIGNED) \ - EPTYPE(il32, int_least32_t, CT_PRIMITIVE_SIGNED) \ - EPTYPE(ul32, uint_least32_t, CT_PRIMITIVE_UNSIGNED) \ - EPTYPE(il64, int_least64_t, CT_PRIMITIVE_SIGNED) \ - EPTYPE(ul64, uint_least64_t, CT_PRIMITIVE_UNSIGNED) \ - EPTYPE(if8, int_fast8_t, CT_PRIMITIVE_SIGNED) \ - EPTYPE(uf8, uint_fast8_t, CT_PRIMITIVE_UNSIGNED) \ - EPTYPE(if16, int_fast16_t, CT_PRIMITIVE_SIGNED) \ - EPTYPE(uf16, uint_fast16_t, CT_PRIMITIVE_UNSIGNED) \ - EPTYPE(if32, int_fast32_t, CT_PRIMITIVE_SIGNED) \ - EPTYPE(uf32, uint_fast32_t, CT_PRIMITIVE_UNSIGNED) \ - EPTYPE(if64, int_fast64_t, CT_PRIMITIVE_SIGNED) \ - EPTYPE(uf64, uint_fast64_t, CT_PRIMITIVE_UNSIGNED) \ - EPTYPE(ip, intptr_t, CT_PRIMITIVE_SIGNED) \ - EPTYPE(up, uintptr_t, CT_PRIMITIVE_UNSIGNED) \ - EPTYPE(im, intmax_t, CT_PRIMITIVE_SIGNED) \ - EPTYPE(um, uintmax_t, CT_PRIMITIVE_UNSIGNED) \ - EPTYPE(pd, ptrdiff_t, CT_PRIMITIVE_SIGNED) \ - EPTYPE(sz, size_t, CT_PRIMITIVE_UNSIGNED) \ - EPTYPE2(ssz, "ssize_t", Py_ssize_t, CT_PRIMITIVE_SIGNED) - -#ifdef HAVE_WCHAR_H -# define ENUM_PRIMITIVE_TYPES_WCHAR \ - EPTYPE(wc, wchar_t, CT_PRIMITIVE_CHAR | \ - (((wchar_t)-1) > 0 ? 0 : CT_IS_SIGNED_WCHAR)) -#else -# define ENUM_PRIMITIVE_TYPES_WCHAR /* nothing */ -#endif - -#define EPTYPE(code, typename, flags) EPTYPE2(code, #typename, typename, flags) - -#define EPTYPE2(code, export_name, typename, flags) \ - struct aligncheck_##code { char x; typename y; }; - ENUM_PRIMITIVE_TYPES -#undef EPTYPE2 - - CTypeDescrObject *td; - static const struct descr_s { const char *name; int size, align, flags; } - types[] = { -#define EPTYPE2(code, export_name, typename, flags) \ - { export_name, \ - sizeof(typename), \ - offsetof(struct aligncheck_##code, y), \ - flags \ - }, - ENUM_PRIMITIVE_TYPES -#undef EPTYPE2 -#undef EPTYPE -#undef ENUM_PRIMITIVE_TYPES_WCHAR -#undef ENUM_PRIMITIVE_TYPES - { NULL } - }; - const struct descr_s *ptypes; - const void *unique_key[1]; - int name_size; - ffi_type *ffitype; - - for (ptypes=types; ; ptypes++) { - if (ptypes->name == NULL) { -#ifndef HAVE_WCHAR_H - if (strcmp(name, "wchar_t")) - PyErr_SetString(PyExc_NotImplementedError, name); - else -#endif - PyErr_SetString(PyExc_KeyError, name); - return NULL; - } - if (strcmp(name, ptypes->name) == 0) - break; - } - - if (ptypes->flags & CT_PRIMITIVE_SIGNED) { - switch (ptypes->size) { - case 1: ffitype = &ffi_type_sint8; break; - case 2: ffitype = &ffi_type_sint16; break; - case 4: ffitype = &ffi_type_sint32; break; - case 8: ffitype = &ffi_type_sint64; break; - default: goto bad_ffi_type; - } - } - else if (ptypes->flags & CT_PRIMITIVE_FLOAT) { - if (strcmp(ptypes->name, "float") == 0) - ffitype = &ffi_type_float; - else if (strcmp(ptypes->name, "double") == 0) - ffitype = &ffi_type_double; - else if (strcmp(ptypes->name, "long double") == 0) { - /* assume that if sizeof(double) == sizeof(long double), then - the two types are equivalent for C. libffi bugs on Win64 - if a function's return type is ffi_type_longdouble... */ - if (sizeof(double) == sizeof(long double)) - ffitype = &ffi_type_double; - else - ffitype = &ffi_type_longdouble; - } - else - goto bad_ffi_type; - } - else if (ptypes->flags & CT_PRIMITIVE_COMPLEX) { - /* As of March 2017, still no libffi support for complex. - It fails silently if we try to use ffi_type_complex_float - or ffi_type_complex_double. Better not use it at all. - */ - ffitype = NULL; - } - else { - switch (ptypes->size) { - case 1: ffitype = &ffi_type_uint8; break; - case 2: ffitype = &ffi_type_uint16; break; - case 4: ffitype = &ffi_type_uint32; break; - case 8: ffitype = &ffi_type_uint64; break; - default: goto bad_ffi_type; - } - } - - name_size = strlen(ptypes->name) + 1; - td = ctypedescr_new(name_size); - if (td == NULL) - return NULL; - - memcpy(td->ct_name, name, name_size); - td->ct_size = ptypes->size; - td->ct_length = ptypes->align; - td->ct_extra = ffitype; - td->ct_flags = ptypes->flags; - if (td->ct_flags & (CT_PRIMITIVE_SIGNED | CT_PRIMITIVE_CHAR)) { - if (td->ct_size <= (Py_ssize_t)sizeof(long)) - td->ct_flags |= CT_PRIMITIVE_FITS_LONG; - } - else if (td->ct_flags & CT_PRIMITIVE_UNSIGNED) { - if (td->ct_size < (Py_ssize_t)sizeof(long)) - td->ct_flags |= CT_PRIMITIVE_FITS_LONG; - } - td->ct_name_position = strlen(td->ct_name); - unique_key[0] = ptypes; - return get_unique_type(td, unique_key, 1); - - bad_ffi_type: - PyErr_Format(PyExc_NotImplementedError, - "primitive type '%s' has size %d; " - "the supported sizes are 1, 2, 4, 8", - name, (int)ptypes->size); - return NULL; -} - -static PyObject *b_new_primitive_type(PyObject *self, PyObject *args) -{ - char *name; - if (!PyArg_ParseTuple(args, "s:new_primitive_type", &name)) - return NULL; - return new_primitive_type(name); -} - -static PyObject *new_pointer_type(CTypeDescrObject *ctitem) -{ - CTypeDescrObject *td; - const char *extra; - const void *unique_key[1]; - - if (ctitem->ct_flags & CT_ARRAY) - extra = "(*)"; /* obscure case: see test_array_add */ - else - extra = " *"; - td = ctypedescr_new_on_top(ctitem, extra, 2); - if (td == NULL) - return NULL; - - td->ct_size = sizeof(void *); - td->ct_length = -1; - td->ct_flags = CT_POINTER; - if (ctitem->ct_flags & (CT_STRUCT|CT_UNION)) - td->ct_flags |= CT_IS_PTR_TO_OWNED; - if (ctitem->ct_flags & CT_VOID) - td->ct_flags |= CT_IS_VOID_PTR; - if ((ctitem->ct_flags & CT_VOID) || - ((ctitem->ct_flags & CT_PRIMITIVE_CHAR) && - ctitem->ct_size == sizeof(char))) - td->ct_flags |= CT_IS_VOIDCHAR_PTR; /* 'void *' or 'char *' only */ - unique_key[0] = ctitem; - return get_unique_type(td, unique_key, 1); -} - -static PyObject *b_new_pointer_type(PyObject *self, PyObject *args) -{ - CTypeDescrObject *ctitem; - if (!PyArg_ParseTuple(args, "O!:new_pointer_type", - &CTypeDescr_Type, &ctitem)) - return NULL; - return new_pointer_type(ctitem); -} - -static PyObject *b_new_array_type(PyObject *self, PyObject *args) -{ - PyObject *lengthobj; - Py_ssize_t length; - CTypeDescrObject *ctptr; - - if (!PyArg_ParseTuple(args, "O!O:new_array_type", - &CTypeDescr_Type, &ctptr, &lengthobj)) - return NULL; - - if (lengthobj == Py_None) { - length = -1; - } - else { - length = PyNumber_AsSsize_t(lengthobj, PyExc_OverflowError); - if (length < 0) { - if (!PyErr_Occurred()) - PyErr_SetString(PyExc_ValueError, "negative array length"); - return NULL; - } - } - return new_array_type(ctptr, length); -} - -static PyObject * -new_array_type(CTypeDescrObject *ctptr, Py_ssize_t length) -{ - CTypeDescrObject *td, *ctitem; - char extra_text[32]; - Py_ssize_t arraysize; - int flags = CT_ARRAY; - const void *unique_key[2]; - - if (!(ctptr->ct_flags & CT_POINTER)) { - PyErr_SetString(PyExc_TypeError, "first arg must be a pointer ctype"); - return NULL; - } - ctitem = ctptr->ct_itemdescr; - if (ctitem->ct_size < 0) { - PyErr_Format(PyExc_ValueError, "array item of unknown size: '%s'", - ctitem->ct_name); - return NULL; - } - - if (length < 0) { - sprintf(extra_text, "[]"); - length = -1; - arraysize = -1; - } - else { - sprintf(extra_text, "[%llu]", (unsigned PY_LONG_LONG)length); - arraysize = MUL_WRAPAROUND(length, ctitem->ct_size); - if (length > 0 && (arraysize / length) != ctitem->ct_size) { - PyErr_SetString(PyExc_OverflowError, - "array size would overflow a Py_ssize_t"); - return NULL; - } - } - td = ctypedescr_new_on_top(ctitem, extra_text, 0); - if (td == NULL) - return NULL; - - Py_INCREF(ctptr); - td->ct_stuff = (PyObject *)ctptr; - td->ct_size = arraysize; - td->ct_length = length; - td->ct_flags = flags; - unique_key[0] = ctptr; - unique_key[1] = (void *)length; - return get_unique_type(td, unique_key, 2); -} - -static PyObject *new_void_type(void) -{ - int name_size = strlen("void") + 1; - const void *unique_key[1]; - CTypeDescrObject *td = ctypedescr_new(name_size); - if (td == NULL) - return NULL; - - memcpy(td->ct_name, "void", name_size); - td->ct_size = -1; - td->ct_flags = CT_VOID | CT_IS_OPAQUE; - td->ct_name_position = strlen("void"); - unique_key[0] = "void"; - return get_unique_type(td, unique_key, 1); -} - -static PyObject *b_new_void_type(PyObject *self, PyObject *args) -{ - return new_void_type(); -} - -static PyObject *new_struct_or_union_type(const char *name, int flag) -{ - int namelen = strlen(name); - CTypeDescrObject *td = ctypedescr_new(namelen + 1); - if (td == NULL) - return NULL; - - td->ct_size = -1; - td->ct_length = -1; - td->ct_flags = flag | CT_IS_OPAQUE; - td->ct_extra = NULL; - memcpy(td->ct_name, name, namelen + 1); - td->ct_name_position = namelen; - return (PyObject *)td; -} - -static PyObject *b_new_struct_type(PyObject *self, PyObject *args) -{ - char *name; - int flag; - if (!PyArg_ParseTuple(args, "s:new_struct_type", &name)) - return NULL; - - flag = CT_STRUCT; - if (strcmp(name, "struct _IO_FILE") == 0 || strcmp(name, "FILE") == 0) - flag |= CT_IS_FILE; - return new_struct_or_union_type(name, flag); -} - -static PyObject *b_new_union_type(PyObject *self, PyObject *args) -{ - char *name; - if (!PyArg_ParseTuple(args, "s:new_union_type", &name)) - return NULL; - return new_struct_or_union_type(name, CT_UNION); -} - -static CFieldObject * -_add_field(PyObject *interned_fields, PyObject *fname, CTypeDescrObject *ftype, - Py_ssize_t offset, int bitshift, int fbitsize, int flags) -{ - int err; - Py_ssize_t prev_size; - CFieldObject *cf = PyObject_New(CFieldObject, &CField_Type); - if (cf == NULL) - return NULL; - - Py_INCREF(ftype); - cf->cf_type = ftype; - cf->cf_offset = offset; - cf->cf_bitshift = bitshift; - cf->cf_bitsize = fbitsize; - cf->cf_flags = flags; - - Py_INCREF(fname); - PyText_InternInPlace(&fname); - prev_size = PyDict_Size(interned_fields); - err = PyDict_SetItem(interned_fields, fname, (PyObject *)cf); - Py_DECREF(fname); - Py_DECREF(cf); - if (err < 0) - return NULL; - - if (PyDict_Size(interned_fields) != prev_size + 1) { - PyErr_Format(PyExc_KeyError, "duplicate field name '%s'", - PyText_AS_UTF8(fname)); - return NULL; - } - return cf; /* borrowed reference */ -} - -#define SF_MSVC_BITFIELDS 0x01 -#define SF_GCC_ARM_BITFIELDS 0x02 -#define SF_GCC_X86_BITFIELDS 0x10 - -#define SF_GCC_BIG_ENDIAN 0x04 -#define SF_GCC_LITTLE_ENDIAN 0x40 - -#define SF_PACKED 0x08 -#define SF_STD_FIELD_POS 0x80 - -#ifdef MS_WIN32 -# define SF_DEFAULT_PACKING 8 -#else -# define SF_DEFAULT_PACKING 0x40000000 /* a huge power of two */ -#endif - -static int complete_sflags(int sflags) -{ - /* add one of the SF_xxx_BITFIELDS flags if none is specified */ - if (!(sflags & (SF_MSVC_BITFIELDS | SF_GCC_ARM_BITFIELDS | - SF_GCC_X86_BITFIELDS))) { -#ifdef MS_WIN32 - sflags |= SF_MSVC_BITFIELDS; -#else -# 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; -# endif -#endif - } - /* add one of SF_GCC_xx_ENDIAN if none is specified */ - if (!(sflags & (SF_GCC_BIG_ENDIAN | SF_GCC_LITTLE_ENDIAN))) { - int _check_endian = 1; - if (*(char *)&_check_endian == 0) - sflags |= SF_GCC_BIG_ENDIAN; - else - sflags |= SF_GCC_LITTLE_ENDIAN; - } - return sflags; -} - -static int detect_custom_layout(CTypeDescrObject *ct, int sflags, - Py_ssize_t cdef_value, - Py_ssize_t compiler_value, - const char *msg1, const char *txt, - const char *msg2) -{ - if (compiler_value != cdef_value) { - 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 \"...;\" 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); - return -1; - } - ct->ct_flags |= CT_CUSTOM_FIELD_POS; - } - 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 byteoffset, i, nb_fields, byteoffsetmax, alignedsize; - int bitoffset; - Py_ssize_t byteoffsetorg; - Py_ssize_t totalsize = -1; - int totalalignment = -1; - CFieldObject **previous; - int prev_bitfield_size, prev_bitfield_free; - int sflags = 0, fflags; - int pack = 0; - - if (!PyArg_ParseTuple(args, "O!O!|Oniii:complete_struct_or_union", - &CTypeDescr_Type, &ct, - &PyList_Type, &fields, - &ignored, &totalsize, &totalalignment, &sflags, - &pack)) - return NULL; - - sflags = complete_sflags(sflags); - if (sflags & SF_PACKED) - pack = 1; - else if (pack <= 0) - pack = SF_DEFAULT_PACKING; - else - sflags |= SF_PACKED; - - if ((ct->ct_flags & (CT_STRUCT|CT_IS_OPAQUE)) == - (CT_STRUCT|CT_IS_OPAQUE)) { - is_union = 0; - } - else if ((ct->ct_flags & (CT_UNION|CT_IS_OPAQUE)) == - (CT_UNION|CT_IS_OPAQUE)) { - is_union = 1; - } - else { - PyErr_SetString(PyExc_TypeError, - "first arg must be a non-initialized struct or union ctype"); - return NULL; - } - ct->ct_flags &= ~(CT_CUSTOM_FIELD_POS | CT_WITH_PACKED_CHANGE); - - alignment = 1; - 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); - interned_fields = PyDict_New(); - if (interned_fields == NULL) - return NULL; - - previous = (CFieldObject **)&ct->ct_extra; - - for (i=0; i<nb_fields; i++) { - PyObject *fname; - CTypeDescrObject *ftype; - int fbitsize = -1, falign, falignorg, do_align; - Py_ssize_t foffset = -1; - - if (!PyArg_ParseTuple(PyList_GET_ITEM(fields, i), "O!O!|in:list item", - &PyText_Type, &fname, - &CTypeDescr_Type, &ftype, - &fbitsize, &foffset)) - goto error; - - if (ftype->ct_size < 0) { - if ((ftype->ct_flags & CT_ARRAY) && fbitsize < 0 - && (i == nb_fields - 1 || foffset != -1)) { - ct->ct_flags |= CT_WITH_VAR_ARRAY; - } - else { - PyErr_Format(PyExc_TypeError, - "field '%s.%s' has ctype '%s' of unknown size", - ct->ct_name, PyText_AS_UTF8(fname), - ftype->ct_name); - 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) - 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 */ - falignorg = get_alignment(ftype); - if (falignorg < 0) - goto error; - falign = (pack < falignorg) ? pack : falignorg; - - do_align = 1; - if (!(sflags & SF_GCC_ARM_BITFIELDS) && fbitsize >= 0) { - if (!(sflags & SF_MSVC_BITFIELDS)) { - /* GCC: anonymous bitfields (of any size) don't cause alignment */ - do_align = PyText_GetSize(fname) > 0; - } - else { - /* MSVC: zero-sized bitfields don't cause alignment */ - do_align = fbitsize > 0; - } - } - if (alignment < falign && do_align) - alignment = falign; - - fflags = (is_union && i > 0) ? BF_IGNORE_IN_CTOR : 0; - - if (fbitsize < 0) { - /* not a bitfield: common case */ - int bs_flag; - - if ((ftype->ct_flags & CT_ARRAY) && ftype->ct_length <= 0) - bs_flag = BS_EMPTY_ARRAY; - else - bs_flag = BS_REGULAR; - - /* align this field to its own 'falign' by inserting padding */ - - /* 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, byteoffset, foffset, - "wrong offset for field '", - PyText_AS_UTF8(fname), "'") < 0) - goto error; - byteoffset = foffset; - } - - if (PyText_GetSize(fname) == 0 && - ftype->ct_flags & (CT_STRUCT|CT_UNION)) { - /* a nested anonymous struct or union */ - CFieldObject *cfsrc = (CFieldObject *)ftype->ct_extra; - for (; cfsrc != NULL; cfsrc = cfsrc->cf_next) { - /* broken complexity in the call to get_field_name(), - but we'll assume you never do that with nested - anonymous structures with thousand of fields */ - *previous = _add_field(interned_fields, - get_field_name(ftype, cfsrc), - cfsrc->cf_type, - byteoffset + cfsrc->cf_offset, - cfsrc->cf_bitshift, - cfsrc->cf_bitsize, - cfsrc->cf_flags | fflags); - if (*previous == NULL) - goto error; - previous = &(*previous)->cf_next; - } - /* always forbid such structures from being passed by value */ - ct->ct_flags |= CT_CUSTOM_FIELD_POS; - } - else { - *previous = _add_field(interned_fields, fname, ftype, - byteoffset, bs_flag, -1, fflags); - if (*previous == NULL) - goto error; - previous = &(*previous)->cf_next; - } - if (ftype->ct_size >= 0) - byteoffset += ftype->ct_size; - prev_bitfield_size = 0; - } - else { - /* this is the case of a bitfield */ - Py_ssize_t field_offset_bytes; - int bits_already_occupied, bitshift; - - if (foffset >= 0) { - PyErr_Format(PyExc_TypeError, - "field '%s.%s' is a bitfield, " - "but a fixed offset is specified", - ct->ct_name, PyText_AS_UTF8(fname)); - goto error; - } - - if (!(ftype->ct_flags & (CT_PRIMITIVE_SIGNED | - CT_PRIMITIVE_UNSIGNED | - CT_PRIMITIVE_CHAR))) { - PyErr_Format(PyExc_TypeError, - "field '%s.%s' declared as '%s' cannot be a bit field", - ct->ct_name, PyText_AS_UTF8(fname), - ftype->ct_name); - goto error; - } - if (fbitsize > 8 * ftype->ct_size) { - PyErr_Format(PyExc_TypeError, - "bit field '%s.%s' is declared '%s:%d', which " - "exceeds the width of the type", - ct->ct_name, PyText_AS_UTF8(fname), - ftype->ct_name, fbitsize); - goto error; - } - - /* 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 = byteoffset; - field_offset_bytes &= ~(falign - 1); - - if (fbitsize == 0) { - if (PyText_GetSize(fname) > 0) { - PyErr_Format(PyExc_TypeError, - "field '%s.%s' is declared with :0", - ct->ct_name, PyText_AS_UTF8(fname)); - goto error; - } - if (!(sflags & SF_MSVC_BITFIELDS)) { - /* GCC's notion of "ftype :0;" */ - - /* pad byteoffset to a value aligned for "ftype" */ - if (ROUNDUP_BYTES(byteoffset, bitoffset) > field_offset_bytes) { - field_offset_bytes += falign; - assert(byteoffset < field_offset_bytes); - } - byteoffset = field_offset_bytes; - bitoffset = 0; - } - else { - /* MSVC's notion of "ftype :0;" */ - - /* Mostly ignored. It seems they only serve as - separator between other bitfields, to force them - into separate words. */ - } - prev_bitfield_size = 0; - } - else { - if (!(sflags & SF_MSVC_BITFIELDS)) { - /* GCC's algorithm */ - - /* 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 = (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 - allowed position */ - if ((sflags & SF_PACKED) && - (bits_already_occupied & 7)) { - PyErr_Format(PyExc_NotImplementedError, - "with 'packed', gcc would compile field " - "'%s.%s' to reuse some bits in the previous " - "field", ct->ct_name, PyText_AS_UTF8(fname)); - goto error; - } - field_offset_bytes += falign; - assert(byteoffset < field_offset_bytes); - byteoffset = field_offset_bytes; - bitoffset = 0; - bitshift = 0; - } - else { - bitshift = bits_already_occupied; - assert(bitshift >= 0); - } - bitoffset += fbitsize; - byteoffset += (bitoffset >> 3); - bitoffset &= 7; - } - else { - /* MSVC's algorithm */ - - /* A bitfield is considered as taking the full width - of their declared type. It can share some bits - with the previous field only if it was also a - bitfield and used a type of the same size. */ - if (prev_bitfield_size == ftype->ct_size && - prev_bitfield_free >= fbitsize) { - /* yes: reuse */ - bitshift = 8 * prev_bitfield_size - prev_bitfield_free; - } - else { - /* no: start a new full field */ - 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 = byteoffset - ftype->ct_size; - } - if (sflags & SF_GCC_BIG_ENDIAN) - bitshift = 8 * ftype->ct_size - fbitsize - bitshift; - - 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; - } - } - } - - 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. */ - alignedsize = (byteoffsetmax + alignment - 1) & ~(alignment-1); - if (alignedsize == 0) - alignedsize = 1; - - if (totalsize < 0) { - totalsize = alignedsize; - } - else { - if (detect_custom_layout(ct, sflags, alignedsize, - totalsize, "wrong total size", "", "") < 0) - goto error; - 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, byteoffsetmax); - goto error; - } - } - if (totalalignment < 0) { - totalalignment = alignment; - } - else { - if (detect_custom_layout(ct, sflags, alignment, totalalignment, - "wrong total alignment", "", "") < 0) - goto error; - } - - ct->ct_size = totalsize; - ct->ct_length = totalalignment; - ct->ct_stuff = interned_fields; - ct->ct_flags &= ~CT_IS_OPAQUE; - - Py_INCREF(Py_None); - return Py_None; - - error: - ct->ct_extra = NULL; - Py_DECREF(interned_fields); - return NULL; -} - -struct funcbuilder_s { - Py_ssize_t nb_bytes; - char *bufferp; - ffi_type **atypes; - ffi_type *rtype; - Py_ssize_t nargs; - CTypeDescrObject *fct; -}; - -static void *fb_alloc(struct funcbuilder_s *fb, Py_ssize_t size) -{ - if (fb->bufferp == NULL) { - fb->nb_bytes += size; - return NULL; - } - else { - char *result = fb->bufferp; - fb->bufferp += size; - return result; - } -} - -#define SUPPORTED_IN_API_MODE \ - " are only supported as %s if the function is " \ - "'API mode' and non-variadic (i.e. declared inside ffibuilder" \ - ".cdef()+ffibuilder.set_source() and not taking a final '...' " \ - "argument)" - -static ffi_type *fb_unsupported(CTypeDescrObject *ct, const char *place, - const char *detail) -{ - PyErr_Format(PyExc_NotImplementedError, - "ctype '%s' not supported as %s. %s. " - "Such structs" SUPPORTED_IN_API_MODE, - ct->ct_name, place, detail, place); - return NULL; -} - -static ffi_type *fb_fill_type(struct funcbuilder_s *fb, CTypeDescrObject *ct, - int is_result_type) -{ - const char *place = is_result_type ? "return value" : "argument"; - - if (ct->ct_flags & (CT_PRIMITIVE_ANY & ~CT_PRIMITIVE_COMPLEX)) { - return (ffi_type *)ct->ct_extra; - } - else if (ct->ct_flags & (CT_POINTER|CT_FUNCTIONPTR)) { - return &ffi_type_pointer; - } - else if ((ct->ct_flags & CT_VOID) && is_result_type) { - return &ffi_type_void; - } - - if (ct->ct_size <= 0) { - PyErr_Format(PyExc_TypeError, - ct->ct_size < 0 ? "ctype '%s' has incomplete type" - : "ctype '%s' has size 0", - ct->ct_name); - return NULL; - } - if (ct->ct_flags & CT_STRUCT) { - ffi_type *ffistruct, *ffifield; - ffi_type **elements; - Py_ssize_t i, n, nflat; - CFieldObject *cf; - - /* We can't pass a struct that was completed by verify(). - Issue: assume verify() is given "struct { long b; ...; }". - Then it will complete it in the same way whether it is actually - "struct { long a, b; }" or "struct { double a; long b; }". - But on 64-bit UNIX, these two structs are passed by value - differently: e.g. on x86-64, "b" ends up in register "rsi" in - the first case and "rdi" in the second case. - - Another reason for CT_CUSTOM_FIELD_POS would be anonymous - nested structures: we lost the information about having it - here, so better safe (and forbid it) than sorry (and maybe - crash). Note: it seems we only get in this case with - ffi.verify(). - */ - if (force_lazy_struct(ct) < 0) - return NULL; - if (ct->ct_flags & CT_CUSTOM_FIELD_POS) { - /* these NotImplementedErrors may be caught and ignored until - a real call is made to a function of this type */ - return fb_unsupported(ct, place, - "It is a struct declared with \"...;\", but the C " - "calling convention may depend on the missing fields; " - "or, it contains anonymous struct/unions"); - } - /* Another reason: __attribute__((packed)) is not supported by libffi. - */ - if (ct->ct_flags & CT_WITH_PACKED_CHANGE) { - return fb_unsupported(ct, place, - "It is a 'packed' structure, with a different layout than " - "expected by libffi"); - } - - n = PyDict_Size(ct->ct_stuff); - nflat = 0; - - /* walk the fields, expanding arrays into repetitions; first, - only count how many flattened fields there are */ - cf = (CFieldObject *)ct->ct_extra; - for (i=0; i<n; i++) { - Py_ssize_t flat; - CTypeDescrObject *ct1; - assert(cf != NULL); - if (cf->cf_bitshift >= 0) { - return fb_unsupported(ct, place, - "It is a struct with bit fields, which libffi does not " - "support"); - } - flat = 1; - ct1 = cf->cf_type; - while (ct1->ct_flags & CT_ARRAY) { - flat *= ct1->ct_length; - ct1 = ct1->ct_itemdescr; - } - if (flat <= 0) { - return fb_unsupported(ct, place, - "It is a struct with a zero-length array, which libffi " - "does not support"); - } - nflat += flat; - cf = cf->cf_next; - } - assert(cf == NULL); - - /* next, allocate and fill the flattened list */ - elements = fb_alloc(fb, (nflat + 1) * sizeof(ffi_type*)); - nflat = 0; - cf = (CFieldObject *)ct->ct_extra; - for (i=0; i<n; i++) { - Py_ssize_t j, flat = 1; - CTypeDescrObject *ct = cf->cf_type; - while (ct->ct_flags & CT_ARRAY) { - flat *= ct->ct_length; - ct = ct->ct_itemdescr; - } - ffifield = fb_fill_type(fb, ct, 0); - if (PyErr_Occurred()) - return NULL; - if (elements != NULL) { - for (j=0; j<flat; j++) - elements[nflat++] = ffifield; - } - cf = cf->cf_next; - } - - /* finally, allocate the FFI_TYPE_STRUCT */ - ffistruct = fb_alloc(fb, sizeof(ffi_type)); - if (ffistruct != NULL) { - elements[nflat] = NULL; - ffistruct->size = ct->ct_size; - ffistruct->alignment = ct->ct_length; - ffistruct->type = FFI_TYPE_STRUCT; - ffistruct->elements = elements; - } - return ffistruct; - } - else if (ct->ct_flags & CT_UNION) { - PyErr_Format(PyExc_NotImplementedError, - "ctype '%s' not supported as %s by libffi. " - "Unions" SUPPORTED_IN_API_MODE, - ct->ct_name, place, place); - return NULL; - } - else { - char *extra = ""; - if (ct->ct_flags & CT_PRIMITIVE_COMPLEX) - extra = " (the support for complex types inside libffi " - "is mostly missing at this point, so CFFI only " - "supports complex types as arguments or return " - "value in API-mode functions)"; - - PyErr_Format(PyExc_NotImplementedError, - "ctype '%s' (size %zd) not supported as %s%s", - ct->ct_name, ct->ct_size, place, extra); - return NULL; - } -} - -#define ALIGN_ARG(n) ((n) + 7) & ~7 - -static int fb_build(struct funcbuilder_s *fb, PyObject *fargs, - CTypeDescrObject *fresult) -{ - Py_ssize_t i, nargs = PyTuple_GET_SIZE(fargs); - Py_ssize_t exchange_offset; - cif_description_t *cif_descr; - - /* ffi buffer: start with a cif_description */ - cif_descr = fb_alloc(fb, sizeof(cif_description_t) + - nargs * sizeof(Py_ssize_t)); - - /* ffi buffer: next comes an array of 'ffi_type*', one per argument */ - fb->atypes = fb_alloc(fb, nargs * sizeof(ffi_type*)); - fb->nargs = nargs; - - /* ffi buffer: next comes the result type */ - fb->rtype = fb_fill_type(fb, fresult, 1); - if (PyErr_Occurred()) - return -1; - if (cif_descr != NULL) { - /* exchange data size */ - /* first, enough room for an array of 'nargs' pointers */ - exchange_offset = nargs * sizeof(void*); - exchange_offset = ALIGN_ARG(exchange_offset); - cif_descr->exchange_offset_arg[0] = exchange_offset; - /* then enough room for the result --- which means at least - sizeof(ffi_arg), according to the ffi docs */ - i = fb->rtype->size; - if (i < (Py_ssize_t)sizeof(ffi_arg)) - i = sizeof(ffi_arg); - exchange_offset += i; - } - else - exchange_offset = 0; /* not used */ - - /* loop over the arguments */ - for (i=0; i<nargs; i++) { - CTypeDescrObject *farg; - ffi_type *atype; - - farg = (CTypeDescrObject *)PyTuple_GET_ITEM(fargs, i); - /* convert arrays to pointers */ - if (farg->ct_flags & CT_ARRAY) - farg = (CTypeDescrObject *)farg->ct_stuff; - - /* ffi buffer: fill in the ffi for the i'th argument */ - assert(farg != NULL); - atype = fb_fill_type(fb, farg, 0); - if (PyErr_Occurred()) - return -1; - - if (fb->atypes != NULL) { - fb->atypes[i] = atype; - /* exchange data size */ - exchange_offset = ALIGN_ARG(exchange_offset); - cif_descr->exchange_offset_arg[1 + i] = exchange_offset; - exchange_offset += atype->size; - } - } - - if (cif_descr != NULL) { - /* exchange data size */ - /* we also align it to the next multiple of 8, in an attempt to - work around bugs(?) of libffi like #241 */ - cif_descr->exchange_size = ALIGN_ARG(exchange_offset); - } - return 0; -} - -#undef ALIGN_ARG - -static void fb_cat_name(struct funcbuilder_s *fb, const char *piece, - int piecelen) -{ - if (fb->bufferp == NULL) { - fb->nb_bytes += piecelen; - } - else { - memcpy(fb->bufferp, piece, piecelen); - fb->bufferp += piecelen; - } -} - -static int fb_build_name(struct funcbuilder_s *fb, const char *repl, - CTypeDescrObject **pfargs, Py_ssize_t nargs, - CTypeDescrObject *fresult, int ellipsis) -{ - Py_ssize_t i; - fb->nargs = nargs; - - /* name: the function type name we build here is, like in C, made - as follows: - - RESULT_TYPE_HEAD (*)(ARG_1_TYPE, ARG_2_TYPE, etc) RESULT_TYPE_TAIL - */ - fb_cat_name(fb, fresult->ct_name, fresult->ct_name_position); - if (repl[0] != '(' && - fresult->ct_name[fresult->ct_name_position - 1] != '*') - fb_cat_name(fb, " ", 1); /* add a space */ - fb_cat_name(fb, repl, strlen(repl)); - if (fb->fct) { - i = strlen(repl) - 1; /* between '(*' and ')' */ - assert(repl[i] == ')'); - fb->fct->ct_name_position = fresult->ct_name_position + i; - } - fb_cat_name(fb, "(", 1); - - /* loop over the arguments */ - for (i=0; i<nargs; i++) { - CTypeDescrObject *farg; - - farg = pfargs[i]; - if (!CTypeDescr_Check(farg)) { - PyErr_SetString(PyExc_TypeError, "expected a tuple of ctypes"); - return -1; - } - /* name: concatenate the name of the i'th argument's type */ - if (i > 0) - fb_cat_name(fb, ", ", 2); - fb_cat_name(fb, farg->ct_name, strlen(farg->ct_name)); - } - - /* name: add the '...' if needed */ - if (ellipsis) { - if (nargs > 0) - fb_cat_name(fb, ", ", 2); - fb_cat_name(fb, "...", 3); - } - - /* name: concatenate the tail of the result type */ - fb_cat_name(fb, ")", 1); - fb_cat_name(fb, fresult->ct_name + fresult->ct_name_position, - strlen(fresult->ct_name) - fresult->ct_name_position + 1); - return 0; -} - -static CTypeDescrObject *fb_prepare_ctype(struct funcbuilder_s *fb, - PyObject *fargs, - CTypeDescrObject *fresult, - int ellipsis, int fabi) -{ - CTypeDescrObject *fct, **pfargs; - Py_ssize_t nargs; - char *repl = "(*)"; - - fb->nb_bytes = 0; - fb->bufferp = NULL; - fb->fct = NULL; - - pfargs = (CTypeDescrObject **)&PyTuple_GET_ITEM(fargs, 0); - nargs = PyTuple_GET_SIZE(fargs); -#if defined(MS_WIN32) && !defined(_WIN64) - if (fabi == FFI_STDCALL) - repl = "(__stdcall *)"; -#endif - - /* compute the total size needed for the name */ - if (fb_build_name(fb, repl, pfargs, nargs, fresult, ellipsis) < 0) - return NULL; - - /* allocate the function type */ - fct = ctypedescr_new(fb->nb_bytes); - if (fct == NULL) - return NULL; - fb->fct = fct; - - /* call again fb_build_name() to really build the ct_name */ - fb->bufferp = fct->ct_name; - if (fb_build_name(fb, repl, pfargs, nargs, fresult, ellipsis) < 0) - goto error; - assert(fb->bufferp == fct->ct_name + fb->nb_bytes); - - fct->ct_extra = NULL; - fct->ct_size = sizeof(void(*)(void)); - fct->ct_flags = CT_FUNCTIONPTR; - return fct; - - error: - Py_DECREF(fct); - return NULL; -} - -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; - - /* compute the total size needed in the buffer for libffi */ - if (fb_build(&funcbuffer, fargs, fresult) < 0) - return NULL; - - /* allocate the buffer */ - buffer = PyObject_Malloc(funcbuffer.nb_bytes); - if (buffer == NULL) { - PyErr_NoMemory(); - return NULL; - } - - /* call again fb_build() to really build the libffi data structures */ - funcbuffer.bufferp = buffer; - if (fb_build(&funcbuffer, fargs, fresult) < 0) - goto error; - assert(funcbuffer.bufferp == buffer + funcbuffer.nb_bytes); - - cif_descr = (cif_description_t *)buffer; - - /* use `ffi_prep_cif_var` if necessary and available */ -#if CFFI_CHECK_FFI_PREP_CIF_VAR_MAYBE - if (variadic_nargs_declared >= 0) { - if (CFFI_CHECK_FFI_PREP_CIF_VAR) { - status = ffi_prep_cif_var(&cif_descr->cif, fabi, - variadic_nargs_declared, funcbuffer.nargs, - funcbuffer.rtype, funcbuffer.atypes); - } - } -#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; - } - return cif_descr; - - error: - PyObject_Free(buffer); - return NULL; -} - -static PyObject *new_function_type(PyObject *fargs, /* tuple */ - CTypeDescrObject *fresult, - int ellipsis, int fabi) -{ - PyObject *fabiobj; - CTypeDescrObject *fct; - struct funcbuilder_s funcbuilder; - Py_ssize_t i; - const void **unique_key; - - if ((fresult->ct_size < 0 && !(fresult->ct_flags & CT_VOID)) || - (fresult->ct_flags & CT_ARRAY)) { - char *msg; - if (fresult->ct_flags & CT_IS_OPAQUE) - msg = "result type '%s' is opaque"; - else - msg = "invalid result type: '%s'"; - PyErr_Format(PyExc_TypeError, msg, fresult->ct_name); - return NULL; - } - - fct = fb_prepare_ctype(&funcbuilder, fargs, fresult, ellipsis, fabi); - if (fct == NULL) - return NULL; - - if (!ellipsis) { - /* Functions with '...' varargs are stored without a cif_descr - at all. The cif is computed on every call from the actual - types passed in. For all other functions, the cif_descr - is computed here. */ - cif_description_t *cif_descr; - - 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 - actual call */ - } - else - goto error; - } - - fct->ct_extra = (char *)cif_descr; - } - - /* build the signature, given by a tuple of ctype objects */ - fct->ct_stuff = PyTuple_New(2 + funcbuilder.nargs); - if (fct->ct_stuff == NULL) - goto error; - fabiobj = PyInt_FromLong(fabi); - if (fabiobj == NULL) - goto error; - PyTuple_SET_ITEM(fct->ct_stuff, 0, fabiobj); - - Py_INCREF(fresult); - PyTuple_SET_ITEM(fct->ct_stuff, 1, (PyObject *)fresult); - for (i=0; i<funcbuilder.nargs; i++) { - PyObject *o = PyTuple_GET_ITEM(fargs, i); - /* convert arrays into pointers */ - if (((CTypeDescrObject *)o)->ct_flags & CT_ARRAY) - o = ((CTypeDescrObject *)o)->ct_stuff; - Py_INCREF(o); - PyTuple_SET_ITEM(fct->ct_stuff, 2 + i, o); - } - - /* [ctresult, ellipsis+abi, num_args, ctargs...] */ - unique_key = alloca((3 + funcbuilder.nargs) * sizeof(void *)); - unique_key[0] = fresult; - unique_key[1] = (const void *)(Py_ssize_t)((fabi << 1) | !!ellipsis); - unique_key[2] = (const void *)(Py_ssize_t)(funcbuilder.nargs); - for (i=0; i<funcbuilder.nargs; i++) - unique_key[3 + i] = PyTuple_GET_ITEM(fct->ct_stuff, 2 + i); - return get_unique_type(fct, unique_key, 3 + funcbuilder.nargs); - - error: - Py_DECREF(fct); - return NULL; -} - -static PyObject *b_new_function_type(PyObject *self, PyObject *args) -{ - PyObject *fargs; - CTypeDescrObject *fresult; - int ellipsis = 0, fabi = FFI_DEFAULT_ABI; - - if (!PyArg_ParseTuple(args, "O!O!|ii:new_function_type", - &PyTuple_Type, &fargs, - &CTypeDescr_Type, &fresult, - &ellipsis, - &fabi)) - return NULL; - - return new_function_type(fargs, fresult, ellipsis, fabi); -} - -static int convert_from_object_fficallback(char *result, - CTypeDescrObject *ctype, - PyObject *pyobj, - int encode_result_for_libffi) -{ - /* work work work around a libffi irregularity: for integer return - types we have to fill at least a complete 'ffi_arg'-sized result - buffer. */ - if (ctype->ct_size < (Py_ssize_t)sizeof(ffi_arg)) { - if (ctype->ct_flags & CT_VOID) { - if (pyobj == Py_None) { - return 0; - } - else { - PyErr_SetString(PyExc_TypeError, - "callback with the return type 'void' must return None"); - return -1; - } - } - if (!encode_result_for_libffi) - goto skip; - if (ctype->ct_flags & CT_PRIMITIVE_SIGNED) { - PY_LONG_LONG value; - /* It's probably fine to always zero-extend, but you never - know: maybe some code somewhere expects a negative - 'short' result to be returned into EAX as a 32-bit - negative number. Better safe than sorry. This code - is about that case. Let's ignore this for enums. - */ - /* do a first conversion only to detect overflows. This - conversion produces stuff that is otherwise ignored. */ - if (convert_from_object(result, ctype, pyobj) < 0) - return -1; - /* manual inlining and tweaking of convert_from_object() - in order to write a whole 'ffi_arg'. */ - value = _my_PyLong_AsLongLong(pyobj); - if (value == -1 && PyErr_Occurred()) - return -1; - write_raw_integer_data(result, value, sizeof(ffi_arg)); - return 0; - } - else if (ctype->ct_flags & (CT_PRIMITIVE_CHAR | CT_PRIMITIVE_SIGNED | - CT_PRIMITIVE_UNSIGNED | - CT_POINTER | CT_FUNCTIONPTR)) { - /* zero extension: fill the '*result' with zeros, and (on big- - endian machines) correct the 'result' pointer to write to. - We also do that for pointers, even though we're normally not - in this branch because ctype->ct_size == sizeof(ffi_arg) for - pointers---except on some architectures like x32 (issue #372). - */ - memset(result, 0, sizeof(ffi_arg)); -#ifdef WORDS_BIGENDIAN - result += (sizeof(ffi_arg) - ctype->ct_size); -#endif - } - } - skip: - return convert_from_object(result, ctype, pyobj); -} - -static void _my_PyErr_WriteUnraisable(PyObject *t, PyObject *v, PyObject *tb, - char *objdescr, PyObject *obj, - 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 */ - PyErr_NormalizeException(&t, &v, &tb); - if (tb == NULL) { - tb = Py_None; - Py_INCREF(tb); - } - PyException_SetTraceback(v, tb); -#endif - f = PySys_GetObject("stderr"); - if (f != NULL) { - if (obj != NULL) { - PyFile_WriteString(objdescr, f); - PyFile_WriteObject(obj, f, 0); - PyFile_WriteString(":\n", f); - } - if (extra_error_line != NULL) - PyFile_WriteString(extra_error_line, f); - PyErr_Display(t, v, tb); - } - Py_XDECREF(t); - Py_XDECREF(v); - Py_XDECREF(tb); - -#endif -} - -static void general_invoke_callback(int decode_args_from_libffi, - void *result, char *args, void *userdata) -{ - PyObject *cb_args = (PyObject *)userdata; - CTypeDescrObject *ct = (CTypeDescrObject *)PyTuple_GET_ITEM(cb_args, 0); - PyObject *signature = ct->ct_stuff; - PyObject *py_ob = PyTuple_GET_ITEM(cb_args, 1); - PyObject *py_args = NULL; - PyObject *py_res = NULL; - PyObject *py_rawerr; - PyObject *onerror_cb; - Py_ssize_t i, n; - char *extra_error_line = NULL; - -#define SIGNATURE(i) ((CTypeDescrObject *)PyTuple_GET_ITEM(signature, i)) - - Py_INCREF(cb_args); - - n = PyTuple_GET_SIZE(signature) - 2; - py_args = PyTuple_New(n); - if (py_args == NULL) - goto error; - - for (i=0; i<n; i++) { - char *a_src; - PyObject *a; - CTypeDescrObject *a_ct = SIGNATURE(2 + i); - - if (decode_args_from_libffi) { - a_src = ((void **)args)[i]; - } - else { - a_src = args + i * 8; - if (a_ct->ct_flags & (CT_IS_LONGDOUBLE | CT_STRUCT | CT_UNION)) - a_src = *(char **)a_src; - } - a = convert_to_object(a_src, a_ct); - if (a == NULL) - goto error; - PyTuple_SET_ITEM(py_args, i, a); - } - - py_res = PyObject_Call(py_ob, py_args, NULL); - if (py_res == NULL) - 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: - Py_XDECREF(py_args); - Py_XDECREF(py_res); - Py_DECREF(cb_args); - return; - - error: - if (SIGNATURE(1)->ct_size > 0) { - py_rawerr = PyTuple_GET_ITEM(cb_args, 2); - memcpy(result, PyBytes_AS_STRING(py_rawerr), - PyBytes_GET_SIZE(py_rawerr)); - } - onerror_cb = PyTuple_GET_ITEM(cb_args, 3); - if (onerror_cb == Py_None) { - PyObject *ecap, *t, *v, *tb; - PyErr_Fetch(&t, &v, &tb); - ecap = _cffi_start_error_capture(); - _my_PyErr_WriteUnraisable(t, v, tb, "From cffi callback ", py_ob, - extra_error_line); - _cffi_stop_error_capture(ecap); - } - else { - PyObject *exc1, *val1, *tb1, *res1, *exc2, *val2, *tb2; - PyErr_Fetch(&exc1, &val1, &tb1); - PyErr_NormalizeException(&exc1, &val1, &tb1); - res1 = PyObject_CallFunctionObjArgs(onerror_cb, - exc1 ? exc1 : Py_None, - val1 ? val1 : Py_None, - tb1 ? tb1 : Py_None, - NULL); - if (res1 != NULL) { - if (res1 != Py_None) - convert_from_object_fficallback(result, SIGNATURE(1), res1, - decode_args_from_libffi); - Py_DECREF(res1); - } - if (!PyErr_Occurred()) { - Py_XDECREF(exc1); - Py_XDECREF(val1); - Py_XDECREF(tb1); - } - else { - /* double exception! print a double-traceback... */ - PyObject *ecap; - PyErr_Fetch(&exc2, &val2, &tb2); - ecap = _cffi_start_error_capture(); - _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); - } - } - goto done; - -#undef SIGNATURE -} - -static void invoke_callback(ffi_cif *cif, void *result, void **args, - void *userdata) -{ - save_errno(); - { - PyGILState_STATE state = gil_ensure(); - general_invoke_callback(1, result, (char *)args, userdata); - gil_release(state); - } - restore_errno(); -} - -static PyObject *prepare_callback_info_tuple(CTypeDescrObject *ct, - PyObject *ob, - PyObject *error_ob, - PyObject *onerror_ob, - int decode_args_from_libffi) -{ - CTypeDescrObject *ctresult; - PyObject *py_rawerr, *infotuple; - Py_ssize_t size; - - if (!(ct->ct_flags & CT_FUNCTIONPTR)) { - PyErr_Format(PyExc_TypeError, "expected a function ctype, got '%s'", - ct->ct_name); - return NULL; - } - if (!PyCallable_Check(ob)) { - PyErr_Format(PyExc_TypeError, - "expected a callable object, not %.200s", - Py_TYPE(ob)->tp_name); - return NULL; - } - if (onerror_ob != Py_None && !PyCallable_Check(onerror_ob)) { - PyErr_Format(PyExc_TypeError, - "expected a callable object for 'onerror', not %.200s", - Py_TYPE(onerror_ob)->tp_name); - return NULL; - } - - ctresult = (CTypeDescrObject *)PyTuple_GET_ITEM(ct->ct_stuff, 1); - size = ctresult->ct_size; - if (size < (Py_ssize_t)sizeof(ffi_arg)) - size = sizeof(ffi_arg); - py_rawerr = PyBytes_FromStringAndSize(NULL, size); - if (py_rawerr == NULL) - return NULL; - memset(PyBytes_AS_STRING(py_rawerr), 0, size); - if (error_ob != Py_None) { - if (convert_from_object_fficallback( - PyBytes_AS_STRING(py_rawerr), ctresult, error_ob, - decode_args_from_libffi) < 0) { - Py_DECREF(py_rawerr); - return NULL; - } - } - infotuple = Py_BuildValue("OOOO", ct, ob, py_rawerr, onerror_ob); - Py_DECREF(py_rawerr); - -#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. - 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; - CDataObject_closure *cd; - PyObject *ob, *error_ob = Py_None, *onerror_ob = Py_None; - 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, - &error_ob, &onerror_ob)) - return NULL; - - infotuple = prepare_callback_info_tuple(ct, ob, error_ob, onerror_ob, 1); - if (infotuple == NULL) - return NULL; - -#if CFFI_CHECK_FFI_CLOSURE_ALLOC_MAYBE - if (CFFI_CHECK_FFI_CLOSURE_ALLOC) { - closure = ffi_closure_alloc(sizeof(ffi_closure), &closure_exec); - } else -#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); - if (cd == NULL) - goto error; - Py_INCREF(ct); - cd->head.c_type = ct; - cd->head.c_data = (char *)closure_exec; - cd->head.c_weakreflist = NULL; - closure->user_data = NULL; - cd->closure = closure; - - cif_descr = (cif_description_t *)ct->ct_extra; - if (cif_descr == NULL) { - PyErr_Format(PyExc_NotImplementedError, - "%s: callback with unsupported argument or " - "return type or with '...'", ct->ct_name); - goto error; - } - -#if CFFI_CHECK_FFI_PREP_CLOSURE_LOC_MAYBE - if (CFFI_CHECK_FFI_PREP_CLOSURE_LOC) { - status = ffi_prep_closure_loc(closure, &cif_descr->cif, - invoke_callback, infotuple, closure_exec); - } - else -#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 - 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 - 'ffi_closure' structure than the one we expect from ffi.h - (e.g. difference in details of the platform): a difference - in FFI_TRAMPOLINE_SIZE means that the 'user_data' field - ends up somewhere else, and so the test above fails. - */ - PyErr_SetString(PyExc_SystemError, - "ffi_prep_closure(): bad user_data (it seems that the " - "version of the libffi library seen at runtime is " - "different from the 'ffi.h' file seen at compile-time)"); - goto error; - } - PyObject_GC_Track(cd); - return (PyObject *)cd; - - error: - closure->user_data = NULL; - if (cd == NULL) { -#if CFFI_CHECK_FFI_CLOSURE_ALLOC_MAYBE - if (CFFI_CHECK_FFI_CLOSURE_ALLOC) { - ffi_closure_free(closure); - } - else -#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) -{ - char *ename; - PyObject *enumerators, *enumvalues; - PyObject *dict1 = NULL, *dict2 = NULL, *combined = NULL, *tmpkey = NULL; - int name_size; - CTypeDescrObject *td, *basetd; - Py_ssize_t i, n; - - if (!PyArg_ParseTuple(args, "sO!O!O!:new_enum_type", - &ename, - &PyTuple_Type, &enumerators, - &PyTuple_Type, &enumvalues, - &CTypeDescr_Type, &basetd)) - return NULL; - - n = PyTuple_GET_SIZE(enumerators); - if (n != PyTuple_GET_SIZE(enumvalues)) { - PyErr_SetString(PyExc_ValueError, - "tuple args must have the same size"); - return NULL; - } - - if (!(basetd->ct_flags & (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_UNSIGNED))) { - PyErr_SetString(PyExc_TypeError, - "expected a primitive signed or unsigned base type"); - return NULL; - } - - dict1 = PyDict_New(); - if (dict1 == NULL) - goto error; - dict2 = PyDict_New(); - if (dict2 == NULL) - goto error; - - for (i=n; --i >= 0; ) { - long long lvalue; - PyObject *value = PyTuple_GET_ITEM(enumvalues, i); - tmpkey = PyTuple_GET_ITEM(enumerators, i); - Py_INCREF(tmpkey); - if (!PyText_Check(tmpkey)) { -#if PY_MAJOR_VERSION < 3 - if (PyUnicode_Check(tmpkey)) { - const char *text = PyText_AsUTF8(tmpkey); - if (text == NULL) - goto error; - Py_DECREF(tmpkey); - tmpkey = PyString_FromString(text); - if (tmpkey == NULL) - goto error; - } - else -#endif - { - PyErr_SetString(PyExc_TypeError, - "enumerators must be a list of strings"); - goto error; - } - } - if (convert_from_object((char*)&lvalue, basetd, value) < 0) - goto error; /* out-of-range or badly typed 'value' */ - if (PyDict_SetItem(dict1, tmpkey, value) < 0) - goto error; - if (PyDict_SetItem(dict2, value, tmpkey) < 0) - goto error; - Py_DECREF(tmpkey); - tmpkey = NULL; - } - - combined = PyTuple_Pack(2, dict1, dict2); - if (combined == NULL) - goto error; - - Py_CLEAR(dict2); - Py_CLEAR(dict1); - - name_size = strlen(ename) + 1; - td = ctypedescr_new(name_size); - if (td == NULL) - goto error; - - memcpy(td->ct_name, ename, name_size); - td->ct_stuff = combined; - td->ct_size = basetd->ct_size; - td->ct_length = basetd->ct_length; /* alignment */ - td->ct_extra = basetd->ct_extra; /* ffi type */ - td->ct_flags = basetd->ct_flags | CT_IS_ENUM; - td->ct_name_position = name_size - 1; - return (PyObject *)td; - - error: - Py_XDECREF(tmpkey); - Py_XDECREF(combined); - Py_XDECREF(dict2); - Py_XDECREF(dict1); - return NULL; -} - -static PyObject *b_alignof(PyObject *self, PyObject *arg) -{ - int align; - if (!CTypeDescr_Check(arg)) { - PyErr_SetString(PyExc_TypeError, "expected a 'ctype' object"); - return NULL; - } - align = get_alignment((CTypeDescrObject *)arg); - if (align < 0) - return NULL; - return PyInt_FromLong(align); -} - -static Py_ssize_t direct_sizeof_cdata(CDataObject *cd) -{ - Py_ssize_t size; - if (cd->c_type->ct_flags & CT_ARRAY) - size = get_array_length(cd) * cd->c_type->ct_itemdescr->ct_size; - else { - size = -1; - if (cd->c_type->ct_flags & (CT_STRUCT | CT_UNION)) - size = _cdata_var_byte_size(cd); - if (size < 0) - size = cd->c_type->ct_size; - } - return size; -} - -static PyObject *b_sizeof(PyObject *self, PyObject *arg) -{ - Py_ssize_t size; - - if (CData_Check(arg)) { - size = direct_sizeof_cdata((CDataObject *)arg); - } - else if (CTypeDescr_Check(arg)) { - size = ((CTypeDescrObject *)arg)->ct_size; - if (size < 0) { - PyErr_Format(PyExc_ValueError, "ctype '%s' is of unknown size", - ((CTypeDescrObject *)arg)->ct_name); - return NULL; - } - } - else { - PyErr_SetString(PyExc_TypeError, - "expected a 'cdata' or 'ctype' object"); - return NULL; - } - return PyInt_FromSsize_t(size); -} - -static PyObject *b_typeof(PyObject *self, PyObject *arg) -{ - PyObject *res; - - if (!CData_Check(arg)) { - PyErr_SetString(PyExc_TypeError, "expected a 'cdata' object"); - return NULL; - } - res = (PyObject *)((CDataObject *)arg)->c_type; - Py_INCREF(res); - return res; -} - -static CTypeDescrObject *direct_typeoffsetof(CTypeDescrObject *ct, - PyObject *fieldname, - int following, Py_ssize_t *offset) -{ - /* Does not return a new reference! */ - CTypeDescrObject *res; - CFieldObject *cf; - - if (PyTextAny_Check(fieldname)) { - if (!following && (ct->ct_flags & CT_POINTER)) - ct = ct->ct_itemdescr; - if (!(ct->ct_flags & (CT_STRUCT|CT_UNION))) { - PyErr_SetString(PyExc_TypeError, - "with a field name argument, expected a " - "struct or union ctype"); - return NULL; - } - if (force_lazy_struct(ct) <= 0) { - if (!PyErr_Occurred()) - PyErr_SetString(PyExc_TypeError, "struct/union is opaque"); - return NULL; - } - cf = (CFieldObject *)PyDict_GetItem(ct->ct_stuff, fieldname); - if (cf == NULL) { - PyErr_SetObject(PyExc_KeyError, fieldname); - return NULL; - } - if (cf->cf_bitshift >= 0) { - PyErr_SetString(PyExc_TypeError, "not supported for bitfields"); - return NULL; - } - res = cf->cf_type; - *offset = cf->cf_offset; - } - else { - Py_ssize_t index = PyInt_AsSsize_t(fieldname); - if (index < 0 && PyErr_Occurred()) { - PyErr_SetString(PyExc_TypeError, - "field name or array index expected"); - return NULL; - } - - if (!(ct->ct_flags & (CT_ARRAY|CT_POINTER)) || - ct->ct_itemdescr->ct_size < 0) { - PyErr_SetString(PyExc_TypeError, "with an integer argument, " - "expected an array ctype or a " - "pointer to non-opaque"); - return NULL; - } - res = ct->ct_itemdescr; - *offset = MUL_WRAPAROUND(index, ct->ct_itemdescr->ct_size); - if ((*offset / ct->ct_itemdescr->ct_size) != index) { - PyErr_SetString(PyExc_OverflowError, - "array offset would overflow a Py_ssize_t"); - return NULL; - } - } - return res; -} - -static PyObject *b_typeoffsetof(PyObject *self, PyObject *args) -{ - PyObject *res, *fieldname; - CTypeDescrObject *ct; - Py_ssize_t offset; - int following = 0; - - if (!PyArg_ParseTuple(args, "O!O|i:typeoffsetof", - &CTypeDescr_Type, &ct, &fieldname, &following)) - return NULL; - - res = (PyObject *)direct_typeoffsetof(ct, fieldname, following, &offset); - if (res == NULL) - return NULL; - - return Py_BuildValue("(On)", res, offset); -} - -static PyObject *b_rawaddressof(PyObject *self, PyObject *args) -{ - CTypeDescrObject *ct; - CDataObject *cd; - Py_ssize_t offset; - int accepted_flags; - - if (!PyArg_ParseTuple(args, "O!O!n:rawaddressof", - &CTypeDescr_Type, &ct, - &CData_Type, &cd, - &offset)) - return NULL; - - accepted_flags = CT_STRUCT | CT_UNION | CT_ARRAY | CT_POINTER; - if ((cd->c_type->ct_flags & accepted_flags) == 0) { - PyErr_SetString(PyExc_TypeError, - "expected a cdata struct/union/array/pointer object"); - return NULL; - } - if ((ct->ct_flags & CT_POINTER) == 0) { - PyErr_SetString(PyExc_TypeError, - "expected a pointer ctype"); - return NULL; - } - return new_simple_cdata(cd->c_data + offset, ct); -} - -static PyObject *b_getcname(PyObject *self, PyObject *args) -{ - CTypeDescrObject *ct; - char *replace_with, *p, *s; - Py_ssize_t namelen, replacelen; - - if (!PyArg_ParseTuple(args, "O!s:getcname", - &CTypeDescr_Type, &ct, &replace_with)) - return NULL; - - namelen = strlen(ct->ct_name); - replacelen = strlen(replace_with); - s = p = alloca(namelen + replacelen + 1); - memcpy(p, ct->ct_name, ct->ct_name_position); - p += ct->ct_name_position; - memcpy(p, replace_with, replacelen); - p += replacelen; - memcpy(p, ct->ct_name + ct->ct_name_position, - namelen - ct->ct_name_position); - - return PyText_FromStringAndSize(s, namelen + replacelen); -} - -static PyObject *b_string(PyObject *self, PyObject *args, PyObject *kwds) -{ - CDataObject *cd; - Py_ssize_t maxlen = -1; - static char *keywords[] = {"cdata", "maxlen", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|n:string", keywords, - &CData_Type, &cd, &maxlen)) - return NULL; - - if (cd->c_type->ct_itemdescr != NULL && - cd->c_type->ct_itemdescr->ct_flags & (CT_PRIMITIVE_CHAR | - CT_PRIMITIVE_SIGNED | - CT_PRIMITIVE_UNSIGNED) && - !(cd->c_type->ct_itemdescr->ct_flags & CT_IS_BOOL)) { - Py_ssize_t length = maxlen; - if (cd->c_data == NULL) { - PyObject *s = cdata_repr(cd); - if (s != NULL) { - PyErr_Format(PyExc_RuntimeError, - "cannot use string() on %s", - PyText_AS_UTF8(s)); - Py_DECREF(s); - } - return NULL; - } - if (length < 0 && cd->c_type->ct_flags & CT_ARRAY) { - length = get_array_length(cd); - } - if (cd->c_type->ct_itemdescr->ct_size == sizeof(char)) { - const char *start = cd->c_data; - if (length < 0) { - /*READ(start, 1)*/ - length = strlen(start); - /*READ(start, length)*/ - } - else { - const char *end; - /*READ(start, length)*/ - end = (const char *)memchr(start, 0, length); - if (end != NULL) - length = end - start; - } - return PyBytes_FromStringAndSize(start, length); - } - else if (cd->c_type->ct_itemdescr->ct_flags & CT_PRIMITIVE_CHAR) { - switch (cd->c_type->ct_itemdescr->ct_size) { - case 2: { - const cffi_char16_t *start = (cffi_char16_t *)cd->c_data; - if (length < 0) { - /*READ(start, 2)*/ - length = 0; - while (start[length]) - length++; - /*READ(start, 2 * length)*/ - } - else { - /*READ(start, 2 * length)*/ - maxlen = length; - length = 0; - while (length < maxlen && start[length]) - length++; - } - return _my_PyUnicode_FromChar16(start, length); - } - case 4: { - const cffi_char32_t *start = (cffi_char32_t *)cd->c_data; - if (length < 0) { - /*READ(start, 4)*/ - length = 0; - while (start[length]) - length++; - /*READ(start, 4 * length)*/ - } - else { - /*READ(start, 4 * length)*/ - maxlen = length; - length = 0; - while (length < maxlen && start[length]) - length++; - } - return _my_PyUnicode_FromChar32(start, length); - } - } - } - } - else if (cd->c_type->ct_flags & CT_IS_ENUM) { - return convert_cdata_to_enum_string(cd, 0); - } - else if (cd->c_type->ct_flags & CT_IS_BOOL) { - /* fall through to TypeError */ - } - else if (cd->c_type->ct_flags & (CT_PRIMITIVE_CHAR | - CT_PRIMITIVE_SIGNED | - CT_PRIMITIVE_UNSIGNED)) { - /*READ(cd->c_data, cd->c_type->ct_size)*/ - if (cd->c_type->ct_size == sizeof(char)) - return PyBytes_FromStringAndSize(cd->c_data, 1); - else if (cd->c_type->ct_flags & CT_PRIMITIVE_CHAR) { - switch (cd->c_type->ct_size) { - case 2: - return _my_PyUnicode_FromChar16((cffi_char16_t *)cd->c_data, 1); - case 4: - return _my_PyUnicode_FromChar32((cffi_char32_t *)cd->c_data, 1); - } - } - } - PyErr_Format(PyExc_TypeError, "string(): unexpected cdata '%s' argument", - cd->c_type->ct_name); - return NULL; -} - -static PyObject *b_unpack(PyObject *self, PyObject *args, PyObject *kwds) -{ - CDataObject *cd; - CTypeDescrObject *ctitem; - Py_ssize_t i, length, itemsize; - PyObject *result; - char *src; - int casenum; - static char *keywords[] = {"cdata", "length", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!n:unpack", keywords, - &CData_Type, &cd, &length)) - return NULL; - - if (!(cd->c_type->ct_flags & (CT_ARRAY|CT_POINTER))) { - PyErr_Format(PyExc_TypeError, - "expected a pointer or array, got '%s'", - cd->c_type->ct_name); - return NULL; - } - if (length < 0) { - PyErr_SetString(PyExc_ValueError, "'length' cannot be negative"); - return NULL; - } - if (cd->c_data == NULL) { - PyObject *s = cdata_repr(cd); - if (s != NULL) { - PyErr_Format(PyExc_RuntimeError, - "cannot use unpack() on %s", - PyText_AS_UTF8(s)); - Py_DECREF(s); - } - return NULL; - } - - /* byte- and unicode strings */ - ctitem = cd->c_type->ct_itemdescr; - if (ctitem->ct_flags & CT_PRIMITIVE_CHAR) { - switch (ctitem->ct_size) { - case sizeof(char): - return PyBytes_FromStringAndSize(cd->c_data, length); - case 2: - return _my_PyUnicode_FromChar16((cffi_char16_t *)cd->c_data,length); - case 4: - return _my_PyUnicode_FromChar32((cffi_char32_t *)cd->c_data,length); - } - } - - /* else, the result is a list. This implementation should be - equivalent to but much faster than '[p[i] for i in range(length)]'. - (Note that on PyPy, 'list(p[0:length])' should be equally fast, - but arguably, finding out that there *is* such an unexpected way - to write things down is the real problem.) - */ - result = PyList_New(length); - if (result == NULL) - return NULL; - - src = cd->c_data; - itemsize = ctitem->ct_size; - if (itemsize < 0) { - Py_DECREF(result); - PyErr_Format(PyExc_ValueError, "'%s' points to items of unknown size", - cd->c_type->ct_name); - return NULL; - } - - /* Determine some common fast-paths for the loop below. The case -1 - is the fall-back, which always gives the right answer. */ - -#define ALIGNMENT_CHECK(align) \ - (((align) & ((align) - 1)) == 0 && \ - (((uintptr_t)src) & ((align) - 1)) == 0) - - casenum = -1; - - if ((ctitem->ct_flags & CT_PRIMITIVE_ANY) && - ALIGNMENT_CHECK(ctitem->ct_length)) { - /* Source data is fully aligned; we can directly read without - memcpy(). The unaligned case is expected to be rare; in - this situation it is ok to fall back to the general - convert_to_object() in the loop. For now we also use this - fall-back for types that are too large. - */ - if (ctitem->ct_flags & CT_PRIMITIVE_SIGNED) { - if (itemsize == sizeof(long)) casenum = 3; - else if (itemsize == sizeof(int)) casenum = 2; - else if (itemsize == sizeof(short)) casenum = 1; - else if (itemsize == sizeof(signed char)) casenum = 0; - } - else if (ctitem->ct_flags & CT_PRIMITIVE_UNSIGNED) { - /* Note: we never pick case 6 if sizeof(int) == sizeof(long), - so that case 6 below can assume that the 'unsigned int' result - would always fit in a 'signed long'. */ - if (ctitem->ct_flags & CT_IS_BOOL) casenum = 11; - else if (itemsize == sizeof(unsigned long)) casenum = 7; - else if (itemsize == sizeof(unsigned int)) casenum = 6; - else if (itemsize == sizeof(unsigned short)) casenum = 5; - else if (itemsize == sizeof(unsigned char)) casenum = 4; - } - else if (ctitem->ct_flags & CT_PRIMITIVE_FLOAT) { - if (itemsize == sizeof(double)) casenum = 9; - else if (itemsize == sizeof(float)) casenum = 8; - } - } - else if (ctitem->ct_flags & (CT_POINTER | CT_FUNCTIONPTR)) { - casenum = 10; /* any pointer */ - } -#undef ALIGNMENT_CHECK - - for (i = 0; i < length; i++) { - PyObject *x; - switch (casenum) { - /* general case */ - default: x = convert_to_object(src, ctitem); break; - - /* special cases for performance only */ - case 0: x = PyInt_FromLong(*(signed char *)src); break; - case 1: x = PyInt_FromLong(*(short *)src); break; - case 2: x = PyInt_FromLong(*(int *)src); break; - case 3: x = PyInt_FromLong(*(long *)src); break; - case 4: x = PyInt_FromLong(*(unsigned char *)src); break; - case 5: x = PyInt_FromLong(*(unsigned short *)src); break; - case 6: x = PyInt_FromLong((long)*(unsigned int *)src); break; - case 7: x = PyLong_FromUnsignedLong(*(unsigned long *)src); break; - case 8: x = PyFloat_FromDouble(*(float *)src); break; - case 9: x = PyFloat_FromDouble(*(double *)src); break; - case 10: x = new_simple_cdata(*(char **)src, ctitem); break; - case 11: - switch (*(unsigned char *)src) { - case 0: x = Py_False; Py_INCREF(x); break; - case 1: x = Py_True; Py_INCREF(x); break; - default: x = convert_to_object(src, ctitem); /* error */ - } - break; - } - if (x == NULL) { - Py_DECREF(result); - return NULL; - } - PyList_SET_ITEM(result, i, x); - src += itemsize; - } - return result; -} - -static PyObject * -b_buffer_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - /* this is the constructor of the type implemented in minibuffer.h */ - CDataObject *cd; - Py_ssize_t size = -1; - static char *keywords[] = {"cdata", "size", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|n:buffer", keywords, - &CData_Type, &cd, &size)) - return NULL; - - if (size < 0) - size = _cdata_var_byte_size(cd); - - if (cd->c_type->ct_flags & CT_POINTER) { - if (size < 0) - size = cd->c_type->ct_itemdescr->ct_size; - } - else if (cd->c_type->ct_flags & CT_ARRAY) { - if (size < 0) - size = get_array_length(cd) * cd->c_type->ct_itemdescr->ct_size; - } - else { - PyErr_Format(PyExc_TypeError, - "expected a pointer or array cdata, got '%s'", - cd->c_type->ct_name); - return NULL; - } - if (size < 0) { - PyErr_Format(PyExc_TypeError, - "don't know the size pointed to by '%s'", - cd->c_type->ct_name); - return NULL; - } - /*WRITE(cd->c_data, size)*/ - return minibuffer_new(cd->c_data, size, (PyObject *)cd); -} - -static PyObject *b_get_errno(PyObject *self, PyObject *noarg) -{ - int err; - restore_errno_only(); - err = errno; - errno = 0; - return PyInt_FromLong(err); -} - -static PyObject *b_set_errno(PyObject *self, PyObject *arg) -{ - long ival = PyInt_AsLong(arg); - if (ival == -1 && PyErr_Occurred()) - return NULL; - else if (ival < INT_MIN || ival > INT_MAX) { - PyErr_SetString(PyExc_OverflowError, "errno value too large"); - return NULL; - } - errno = (int)ival; - save_errno_only(); - errno = 0; - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject *newp_handle(CTypeDescrObject *ct_voidp, PyObject *x) -{ - CDataObject_own_structptr *cd; - cd = (CDataObject_own_structptr *)PyObject_GC_New(CDataObject_own_structptr, - &CDataOwningGC_Type); - if (cd == NULL) - return NULL; - Py_INCREF(ct_voidp); /* must be "void *" */ - cd->head.c_type = ct_voidp; - cd->head.c_data = (char *)cd; - cd->head.c_weakreflist = NULL; - Py_INCREF(x); - cd->structobj = x; - PyObject_GC_Track(cd); - return (PyObject *)cd; -} - -static PyObject *b_newp_handle(PyObject *self, PyObject *args) -{ - CTypeDescrObject *ct; - PyObject *x; - if (!PyArg_ParseTuple(args, "O!O", &CTypeDescr_Type, &ct, &x)) - return NULL; - - if (!(ct->ct_flags & CT_IS_VOID_PTR)) { - PyErr_Format(PyExc_TypeError, "needs 'void *', got '%s'", ct->ct_name); - return NULL; - } - - return newp_handle(ct, x); -} - -static PyObject *b_from_handle(PyObject *self, PyObject *arg) -{ - CTypeDescrObject *ct; - CDataObject_own_structptr *orgcd; - PyObject *x; - if (!CData_Check(arg)) { - PyErr_SetString(PyExc_TypeError, "expected a 'cdata' object"); - return NULL; - } - ct = ((CDataObject *)arg)->c_type; - if (!(ct->ct_flags & CT_IS_VOIDCHAR_PTR)) { - PyErr_Format(PyExc_TypeError, - "expected a 'cdata' object with a 'void *' out of " - "new_handle(), got '%s'", ct->ct_name); - return NULL; - } - orgcd = (CDataObject_own_structptr *)((CDataObject *)arg)->c_data; - if (!orgcd) { - PyErr_SetString(PyExc_RuntimeError, - "cannot use from_handle() on NULL pointer"); - return NULL; - } - if (Py_REFCNT(orgcd) <= 0 || Py_TYPE(orgcd) != &CDataOwningGC_Type) { - Py_FatalError("ffi.from_handle() detected that the address passed " - "points to garbage. If it is really the result of " - "ffi.new_handle(), then the Python object has already " - "been garbage collected"); - } - x = orgcd->structobj; - Py_INCREF(x); - return x; -} - -static int _my_PyObject_GetContiguousBuffer(PyObject *x, Py_buffer *view, - int writable_only) -{ -#if PY_MAJOR_VERSION < 3 - /* Some objects only support the buffer interface and CPython doesn't - translate it into the memoryview interface, mess. Hack a very - minimal content for 'view'. Don't care if the other fields are - uninitialized: we only call PyBuffer_Release(), which only reads - 'view->obj'. */ - PyBufferProcs *pb = x->ob_type->tp_as_buffer; - if (pb && !pb->bf_releasebuffer) { - /* we used to try all three in some vaguely sensible order, - i.e. first the write. But trying to call the write on a - read-only buffer fails with TypeError. So we use a less- - sensible order now. See test_from_buffer_more_cases. - - If 'writable_only', we only try bf_getwritebuffer. - */ - readbufferproc proc = NULL; - if (!writable_only) { - proc = (readbufferproc)pb->bf_getreadbuffer; - if (!proc) - proc = (readbufferproc)pb->bf_getcharbuffer; - } - if (!proc) - proc = (readbufferproc)pb->bf_getwritebuffer; - - if (proc && pb->bf_getsegcount) { - if ((*pb->bf_getsegcount)(x, NULL) != 1) { - PyErr_SetString(PyExc_TypeError, - "expected a single-segment buffer object"); - return -1; - } - view->len = (*proc)(x, 0, &view->buf); - if (view->len < 0) - return -1; - view->obj = x; - Py_INCREF(x); - return 0; - } - } -#endif - - if (PyObject_GetBuffer(x, view, writable_only ? PyBUF_WRITABLE - : PyBUF_SIMPLE) < 0) - return -1; - - if (!PyBuffer_IsContiguous(view, 'A')) { - PyBuffer_Release(view); - PyErr_SetString(PyExc_TypeError, "contiguous buffer expected"); - return -1; - } - return 0; -} - -static PyObject *direct_from_buffer(CTypeDescrObject *ct, PyObject *x, - int require_writable) -{ - CDataObject *cd; - Py_buffer *view; - Py_ssize_t arraylength, minimumlength = 0; - - 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; - } - - /* PyPy 5.7 can obtain buffers for string (python 2) - or bytes (python 3). from_buffer(u"foo") is disallowed. - */ - if (PyUnicode_Check(x)) { - PyErr_SetString(PyExc_TypeError, - "from_buffer() cannot return the address " - "of a unicode object"); - return NULL; - } - - view = PyObject_Malloc(sizeof(Py_buffer)); - if (view == NULL) { - PyErr_NoMemory(); - return NULL; - } - if (_my_PyObject_GetContiguousBuffer(x, view, require_writable) < 0) - goto error1; - - if (ct->ct_flags & CT_POINTER) - { - arraylength = view->len; /* number of bytes, not used so far */ - } - else { - /* 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 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_frombuf, - &CDataFromBuf_Type); - if (cd == NULL) - goto error2; - - Py_INCREF(ct); - cd->c_type = ct; - cd->c_data = view->buf; - cd->c_weakreflist = NULL; - ((CDataObject_frombuf *)cd)->length = arraylength; - ((CDataObject_frombuf *)cd)->bufferview = view; - PyObject_GC_Track(cd); - return (PyObject *)cd; - - error2: - PyBuffer_Release(view); - error1: - PyObject_Free(view); - return NULL; -} - -static PyObject *b_from_buffer(PyObject *self, PyObject *args) -{ - CTypeDescrObject *ct; - PyObject *x; - int require_writable = 0; - - if (!PyArg_ParseTuple(args, "O!O|i", &CTypeDescr_Type, &ct, &x, - &require_writable)) - return NULL; - - return direct_from_buffer(ct, x, require_writable); -} - -static int _fetch_as_buffer(PyObject *x, Py_buffer *view, int writable_only) -{ - if (CData_Check(x)) { - CTypeDescrObject *ct = ((CDataObject *)x)->c_type; - if (!(ct->ct_flags & (CT_POINTER|CT_ARRAY))) { - PyErr_Format(PyExc_TypeError, - "expected a pointer or array ctype, got '%s'", - ct->ct_name); - return -1; - } - view->buf = ((CDataObject *)x)->c_data; - view->obj = NULL; - return 0; - } - else { - return _my_PyObject_GetContiguousBuffer(x, view, writable_only); - } -} - -static PyObject *b_memmove(PyObject *self, PyObject *args, PyObject *kwds) -{ - PyObject *dest_obj, *src_obj; - Py_buffer dest_view, src_view; - Py_ssize_t n; - static char *keywords[] = {"dest", "src", "n", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOn", keywords, - &dest_obj, &src_obj, &n)) - return NULL; - if (n < 0) { - PyErr_SetString(PyExc_ValueError, "negative size"); - return NULL; - } - - if (_fetch_as_buffer(src_obj, &src_view, 0) < 0) { - return NULL; - } - if (_fetch_as_buffer(dest_obj, &dest_view, 1) < 0) { - PyBuffer_Release(&src_view); - return NULL; - } - - memmove(dest_view.buf, src_view.buf, n); - - PyBuffer_Release(&dest_view); - PyBuffer_Release(&src_view); - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject *b__get_types(PyObject *self, PyObject *noarg) -{ - return PyTuple_Pack(2, (PyObject *)&CData_Type, - (PyObject *)&CTypeDescr_Type); -} - -/* forward, in commontypes.c */ -static PyObject *b__get_common_types(PyObject *self, PyObject *arg); - -static PyObject *b_gcp(PyObject *self, PyObject *args, PyObject *kwds) -{ - CDataObject *cd; - CDataObject *origobj; - PyObject *destructor; - Py_ssize_t ignored; /* for pypy */ - static char *keywords[] = {"cdata", "destructor", "size", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!O|n:gc", keywords, - &CData_Type, &origobj, &destructor, - &ignored)) - return NULL; - - if (destructor == Py_None) { - if (!PyObject_TypeCheck(origobj, &CDataGCP_Type)) { - PyErr_SetString(PyExc_TypeError, - "Can remove destructor only on a object " - "previously returned by ffi.gc()"); - return NULL; - } - Py_CLEAR(((CDataObject_gcp *)origobj)->destructor); - Py_RETURN_NONE; - } - - cd = allocate_gcp_object(origobj, origobj->c_type, destructor); - return (PyObject *)cd; -} - -static PyObject *b_release(PyObject *self, PyObject *arg) -{ - if (!CData_Check(arg)) { - PyErr_SetString(PyExc_TypeError, "expected a 'cdata' object"); - return NULL; - } - return cdata_exit(arg, NULL); -} - -/************************************************************/ - -static char _testfunc0(char a, char b) -{ - return a + b; -} -static long _testfunc1(int a, long b) -{ - return (long)a + b; -} -static PY_LONG_LONG _testfunc2(PY_LONG_LONG a, PY_LONG_LONG b) -{ - return a + b; -} -static double _testfunc3(float a, double b) -{ - return a + b; -} -static float _testfunc4(float a, double b) -{ - return (float)(a + b); -} -static void _testfunc5(void) -{ - errno = errno + 15; -} -static int *_testfunc6(int *x) -{ - static int y; - y = *x - 1000; - return &y; -} -struct _testfunc7_s { unsigned char a1; short a2; }; -static short _testfunc7(struct _testfunc7_s inlined) -{ - return inlined.a1 + inlined.a2; -} -static int _testfunc9(int num, ...) -{ - va_list vargs; - int i, total = 0; - va_start(vargs, num); - for (i=0; i<num; i++) { - int value = va_arg(vargs, int); - if (value == 0) - value = -66666666; - total += value; - } - va_end(vargs); - return total; -} - -static struct _testfunc7_s _testfunc10(int n) -{ - struct _testfunc7_s result; - result.a1 = n; - result.a2 = n * n; - return result; -} - -struct _testfunc11_s { int a1, a2; }; -static struct _testfunc11_s _testfunc11(int n) -{ - struct _testfunc11_s result; - result.a1 = n; - result.a2 = n * n; - return result; -} - -struct _testfunc12_s { double a1; }; -static struct _testfunc12_s _testfunc12(int n) -{ - struct _testfunc12_s result; - result.a1 = n; - return result; -} - -struct _testfunc13_s { int a1, a2, a3; }; -static struct _testfunc13_s _testfunc13(int n) -{ - struct _testfunc13_s result; - result.a1 = n; - result.a2 = n * n; - result.a3 = n * n * n; - return result; -} - -struct _testfunc14_s { float a1; }; -static struct _testfunc14_s _testfunc14(int n) -{ - struct _testfunc14_s result; - result.a1 = (float)n; - return result; -} - -struct _testfunc15_s { float a1; int a2; }; -static struct _testfunc15_s _testfunc15(int n) -{ - struct _testfunc15_s result; - result.a1 = (float)n; - result.a2 = n * n; - return result; -} - -struct _testfunc16_s { float a1, a2; }; -static struct _testfunc16_s _testfunc16(int n) -{ - struct _testfunc16_s result; - result.a1 = (float)n; - result.a2 = -(float)n; - return result; -} - -struct _testfunc17_s { int a1; float a2; }; -static struct _testfunc17_s _testfunc17(int n) -{ - struct _testfunc17_s result; - result.a1 = n; - result.a2 = (float)n * (float)n; - return result; -} - -static int _testfunc18(struct _testfunc17_s *ptr) -{ - return ptr->a1 + (int)ptr->a2; -} - -static long double _testfunc19(long double x, int count) -{ - int i; - for (i=0; i<count; i++) { - x = 4*x - x*x; - } - return x; -} - -static short _testfunc20(struct _testfunc7_s *ptr) -{ - return ptr->a1 + ptr->a2; -} - -struct _testfunc21_s { int a, b, c, d, e, f, g, h, i, j; }; -static int _testfunc21(struct _testfunc21_s inlined) -{ - return ((inlined.a << 0) + - (inlined.b << 1) + - (inlined.c << 2) + - (inlined.d << 3) + - (inlined.e << 4) + - (inlined.f << 5) + - (inlined.g << 6) + - (inlined.h << 7) + - (inlined.i << 8) + - (inlined.j << 9)); -} - -struct _testfunc22_s { int a[10]; }; -static struct _testfunc22_s _testfunc22(struct _testfunc22_s s1, - struct _testfunc22_s s2) -{ - struct _testfunc22_s result; - int i; - for (i=0; i<10; i++) - result.a[i] = s1.a[i] - s2.a[i]; - return result; -} - -static int _testfunc23(char *p) -{ - if (p) - return 1000 * p[0]; - return -42; -} - -#if 0 /* libffi doesn't properly support complexes currently */ - /* also, MSVC might not support _Complex... */ - /* if this is enabled one day, remember to also add _Complex - * arguments in addition to return values. */ -static float _Complex _testfunc24(float a, float b) -{ - return a + I*2.0*b; -} -static double _Complex _testfunc25(double a, double b) -{ - return a + I*2.0*b; -} -#endif - -static PyObject *b__testfunc(PyObject *self, PyObject *args) -{ - /* for testing only */ - int i; - void *f; - if (!PyArg_ParseTuple(args, "i:_testfunc", &i)) - return NULL; - switch (i) { - case 0: f = &_testfunc0; break; - case 1: f = &_testfunc1; break; - case 2: f = &_testfunc2; break; - case 3: f = &_testfunc3; break; - case 4: f = &_testfunc4; break; - case 5: f = &_testfunc5; break; - case 6: f = &_testfunc6; break; - case 7: f = &_testfunc7; break; - case 8: f = stderr; break; - case 9: f = &_testfunc9; break; - case 10: f = &_testfunc10; break; - case 11: f = &_testfunc11; break; - case 12: f = &_testfunc12; break; - case 13: f = &_testfunc13; break; - case 14: f = &_testfunc14; break; - case 15: f = &_testfunc15; break; - case 16: f = &_testfunc16; break; - case 17: f = &_testfunc17; break; - case 18: f = &_testfunc18; break; - case 19: f = &_testfunc19; break; - case 20: f = &_testfunc20; break; - case 21: f = &_testfunc21; break; - case 22: f = &_testfunc22; break; - case 23: f = &_testfunc23; break; -#if 0 - case 24: f = &_testfunc24; break; - case 25: f = &_testfunc25; break; -#endif - default: - PyErr_SetNone(PyExc_ValueError); - return NULL; - } - return PyLong_FromVoidPtr(f); -} - -#if PY_MAJOR_VERSION < 3 -static Py_ssize_t _test_segcountproc(PyObject *o, Py_ssize_t *ignored) -{ - return 1; -} -static Py_ssize_t _test_getreadbuf(PyObject *o, Py_ssize_t i, void **r) -{ - static char buf[] = "RDB"; - *r = buf; - return 3; -} -static Py_ssize_t _test_getwritebuf(PyObject *o, Py_ssize_t i, void **r) -{ - static char buf[] = "WRB"; - *r = buf; - return 3; -} -static Py_ssize_t _test_getcharbuf(PyObject *o, Py_ssize_t i, char **r) -{ - static char buf[] = "CHB"; - *r = buf; - return 3; -} -#endif -static int _test_getbuf(PyObject *self, Py_buffer *view, int flags) -{ - static char buf[] = "GTB"; - return PyBuffer_FillInfo(view, self, buf, 3, /*readonly=*/0, flags); -} -static int _test_getbuf_ro(PyObject *self, Py_buffer *view, int flags) -{ - static char buf[] = "ROB"; - return PyBuffer_FillInfo(view, self, buf, 3, /*readonly=*/1, flags); -} - - -static PyObject *b__testbuff(PyObject *self, PyObject *args) -{ - /* for testing only */ - int methods; - PyTypeObject *obj; - if (!PyArg_ParseTuple(args, "O!i|_testbuff", &PyType_Type, &obj, &methods)) - return NULL; - - assert(obj->tp_as_buffer != NULL); - -#if PY_MAJOR_VERSION < 3 - obj->tp_as_buffer->bf_getsegcount = &_test_segcountproc; - obj->tp_flags |= Py_TPFLAGS_HAVE_GETCHARBUFFER; - obj->tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER; - if (methods & 1) obj->tp_as_buffer->bf_getreadbuffer = &_test_getreadbuf; - if (methods & 2) obj->tp_as_buffer->bf_getwritebuffer = &_test_getwritebuf; - if (methods & 4) obj->tp_as_buffer->bf_getcharbuffer = &_test_getcharbuf; -#endif - if (methods & 8) obj->tp_as_buffer->bf_getbuffer = &_test_getbuf; - if (methods & 16) obj->tp_as_buffer->bf_getbuffer = &_test_getbuf_ro; - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject *b_init_cffi_1_0_external_module(PyObject *, PyObject *); -/* forward, see cffi1_module.c */ - - -static PyMethodDef FFIBackendMethods[] = { - {"load_library", b_load_library, METH_VARARGS}, - {"new_primitive_type", b_new_primitive_type, METH_VARARGS}, - {"new_pointer_type", b_new_pointer_type, METH_VARARGS}, - {"new_array_type", b_new_array_type, METH_VARARGS}, - {"new_void_type", b_new_void_type, METH_NOARGS}, - {"new_struct_type", b_new_struct_type, METH_VARARGS}, - {"new_union_type", b_new_union_type, METH_VARARGS}, - {"complete_struct_or_union", b_complete_struct_or_union, METH_VARARGS}, - {"new_function_type", b_new_function_type, METH_VARARGS}, - {"new_enum_type", b_new_enum_type, METH_VARARGS}, - {"newp", b_newp, METH_VARARGS}, - {"cast", b_cast, METH_VARARGS}, - {"callback", b_callback, METH_VARARGS}, - {"alignof", b_alignof, METH_O}, - {"sizeof", b_sizeof, METH_O}, - {"typeof", b_typeof, METH_O}, - {"typeoffsetof", b_typeoffsetof, METH_VARARGS}, - {"rawaddressof", b_rawaddressof, METH_VARARGS}, - {"getcname", b_getcname, METH_VARARGS}, - {"string", (PyCFunction)b_string, METH_VARARGS | METH_KEYWORDS}, - {"unpack", (PyCFunction)b_unpack, METH_VARARGS | METH_KEYWORDS}, - {"get_errno", b_get_errno, METH_NOARGS}, - {"set_errno", b_set_errno, METH_O}, - {"newp_handle", b_newp_handle, METH_VARARGS}, - {"from_handle", b_from_handle, METH_O}, - {"from_buffer", b_from_buffer, METH_VARARGS}, - {"memmove", (PyCFunction)b_memmove, METH_VARARGS | METH_KEYWORDS}, - {"gcp", (PyCFunction)b_gcp, METH_VARARGS | METH_KEYWORDS}, - {"release", b_release, METH_O}, -#ifdef MS_WIN32 - {"getwinerror", (PyCFunction)b_getwinerror, METH_VARARGS | METH_KEYWORDS}, -#endif - {"_get_types", b__get_types, METH_NOARGS}, - {"_get_common_types", b__get_common_types, METH_O}, - {"_testfunc", b__testfunc, METH_VARARGS}, - {"_testbuff", b__testbuff, METH_VARARGS}, - {"_init_cffi_1_0_external_module", b_init_cffi_1_0_external_module, METH_O}, - {NULL, NULL} /* Sentinel */ -}; - -/************************************************************/ -/* Functions used by '_cffi_N.so', the generated modules */ - -#define _cffi_to_c_SIGNED_FN(RETURNTYPE, SIZE) \ -static RETURNTYPE _cffi_to_c_i##SIZE(PyObject *obj) { \ - PY_LONG_LONG tmp = _my_PyLong_AsLongLong(obj); \ - if ((tmp > (PY_LONG_LONG)((1ULL<<(SIZE-1)) - 1)) || \ - (tmp < (PY_LONG_LONG)(0ULL-(1ULL<<(SIZE-1))))) \ - if (!PyErr_Occurred()) \ - return (RETURNTYPE)_convert_overflow(obj, #SIZE "-bit int"); \ - return (RETURNTYPE)tmp; \ -} - -#define _cffi_to_c_UNSIGNED_FN(RETURNTYPE, SIZE) \ -static RETURNTYPE _cffi_to_c_u##SIZE(PyObject *obj) { \ - unsigned PY_LONG_LONG tmp = _my_PyLong_AsUnsignedLongLong(obj, 1); \ - if (tmp > ~(((unsigned PY_LONG_LONG)-2) << (SIZE-1))) \ - if (!PyErr_Occurred()) \ - return (RETURNTYPE)_convert_overflow(obj, \ - #SIZE "-bit unsigned int"); \ - return (RETURNTYPE)tmp; \ -} - -_cffi_to_c_SIGNED_FN(int, 8) -_cffi_to_c_SIGNED_FN(int, 16) -_cffi_to_c_SIGNED_FN(int, 32) -_cffi_to_c_SIGNED_FN(PY_LONG_LONG, 64) -_cffi_to_c_UNSIGNED_FN(int, 8) -_cffi_to_c_UNSIGNED_FN(int, 16) -_cffi_to_c_UNSIGNED_FN(unsigned int, 32) -_cffi_to_c_UNSIGNED_FN(unsigned PY_LONG_LONG, 64) - -static PyObject *_cffi_from_c_pointer(char *ptr, CTypeDescrObject *ct) -{ - return convert_to_object((char *)&ptr, ct); -} - -static char *_cffi_to_c_pointer(PyObject *obj, CTypeDescrObject *ct) -{ - char *result; - if (convert_from_object((char *)&result, ct, obj) < 0) { - if ((ct->ct_flags & CT_POINTER) && - (ct->ct_itemdescr->ct_flags & CT_IS_FILE) && - PyFile_Check(obj)) { - PyErr_Clear(); - return (char *)PyFile_AsFile(obj); - } - return NULL; - } - return result; -} - -static long double _cffi_to_c_long_double(PyObject *obj) -{ - if (CData_Check(obj) && - (((CDataObject *)obj)->c_type->ct_flags & CT_IS_LONGDOUBLE)) { - char *data = ((CDataObject *)obj)->c_data; - /*READ(data, sizeof(long double))*/ - return read_raw_longdouble_data(data); - } - else - return PyFloat_AsDouble(obj); -} - -static _Bool _cffi_to_c__Bool(PyObject *obj) -{ - PY_LONG_LONG tmp = _my_PyLong_AsLongLong(obj); - if (tmp == 0) - return 0; - else if (tmp == 1) - return 1; - else if (PyErr_Occurred()) - return (_Bool)-1; - else - return (_Bool)_convert_overflow(obj, "_Bool"); -} - -static PyObject *_cffi_get_struct_layout(Py_ssize_t nums[]) -{ - PyObject *result; - int count = 0; - while (nums[count] >= 0) - count++; - - result = PyList_New(count); - if (result == NULL) - return NULL; - - while (--count >= 0) { - PyObject *o = PyInt_FromSsize_t(nums[count]); - if (o == NULL) { - Py_DECREF(result); - return NULL; - } - PyList_SET_ITEM(result, count, o); - } - return result; -} - -static PyObject *_cffi_from_c_char(char x) { - return PyBytes_FromStringAndSize(&x, 1); -} - -/* backward-compatibility hack: instead of _cffi_to_c_char16_t() and - * _cffi_to_c_char32_t(), we have _cffi_to_c_wchar_t() handling whatever - * size is wchar_t, and _cffi_to_c_wchar3216_t() handling the opposite. - */ -#ifdef HAVE_WCHAR_H -typedef wchar_t cffi_wchar_t; -#else -typedef uint16_t cffi_wchar_t; /* random pick... */ -#endif - -static cffi_wchar_t _cffi_to_c_wchar_t(PyObject *init) -{ - if (sizeof(cffi_wchar_t) == 2) - return (cffi_wchar_t)_convert_to_char16_t(init); - else - return (cffi_wchar_t)_convert_to_char32_t(init); -} -static PyObject *_cffi_from_c_wchar_t(cffi_wchar_t x) { - if (sizeof(cffi_wchar_t) == 2) { - cffi_char16_t input = x; - return _my_PyUnicode_FromChar16(&input, 1); - } - else { - cffi_char32_t input = x; - return _my_PyUnicode_FromChar32(&input, 1); - } -} -static int _cffi_to_c_wchar3216_t(PyObject *init) -{ - if (sizeof(cffi_wchar_t) == 4) - return (int)_convert_to_char16_t(init); - else - return (int)_convert_to_char32_t(init); -} -static PyObject *_cffi_from_c_wchar3216_t(int x) { - if (sizeof(cffi_wchar_t) == 4) { - cffi_char16_t input = x; - return _my_PyUnicode_FromChar16(&input, 1); - } - else { - cffi_char32_t input = x; - return _my_PyUnicode_FromChar32(&input, 1); - } -} - -struct _cffi_externpy_s; /* forward declaration */ -static void cffi_call_python(struct _cffi_externpy_s *, char *args); - -static void *cffi_exports[] = { - NULL, - _cffi_to_c_i8, - _cffi_to_c_u8, - _cffi_to_c_i16, - _cffi_to_c_u16, - _cffi_to_c_i32, - _cffi_to_c_u32, - _cffi_to_c_i64, - _cffi_to_c_u64, - _convert_to_char, - _cffi_from_c_pointer, - _cffi_to_c_pointer, - _cffi_get_struct_layout, - restore_errno, - save_errno, - _cffi_from_c_char, - convert_to_object, - convert_from_object, - convert_struct_to_owning_object, - _cffi_to_c_wchar_t, - _cffi_from_c_wchar_t, - _cffi_to_c_long_double, - _cffi_to_c__Bool, - _prepare_pointer_call_argument, - convert_array_from_object, - cffi_call_python, - _cffi_to_c_wchar3216_t, - _cffi_from_c_wchar3216_t, -}; - -static struct { const char *name; int value; } all_dlopen_flags[] = { - { "RTLD_LAZY", RTLD_LAZY }, - { "RTLD_NOW", RTLD_NOW }, - { "RTLD_GLOBAL", RTLD_GLOBAL }, -#ifdef RTLD_LOCAL - { "RTLD_LOCAL", RTLD_LOCAL }, -#else - { "RTLD_LOCAL", 0 }, -#endif -#ifdef RTLD_NODELETE - { "RTLD_NODELETE", RTLD_NODELETE }, -#endif -#ifdef RTLD_NOLOAD - { "RTLD_NOLOAD", RTLD_NOLOAD }, -#endif -#ifdef RTLD_DEEPBIND - { "RTLD_DEEPBIND", RTLD_DEEPBIND }, -#endif - { NULL, 0 } -}; - - -/************************************************************/ - -#include "cffi1_module.c" - -/************************************************************/ - -#if PY_MAJOR_VERSION >= 3 -static struct PyModuleDef FFIBackendModuleDef = { - PyModuleDef_HEAD_INIT, - "_cffi_backend", - NULL, - -1, - FFIBackendMethods, - NULL, NULL, NULL, NULL -}; -#define INITERROR return NULL - -PyMODINIT_FUNC -PyInit__cffi_backend(void) -#else -#define INITERROR return - -PyMODINIT_FUNC -init_cffi_backend(void) -#endif -{ - 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) || - strncmp(PyText_AS_UTF8(v), PY_VERSION, 3) != 0) { - PyErr_Format(PyExc_ImportError, - "this module was compiled for Python %c%c%c", - PY_VERSION[0], PY_VERSION[1], PY_VERSION[2]); - INITERROR; - } - -#if PY_MAJOR_VERSION >= 3 - m = PyModule_Create(&FFIBackendModuleDef); -#else - m = Py_InitModule("_cffi_backend", FFIBackendMethods); -#endif - - if (m == NULL) - INITERROR; - - if (unique_cache == NULL) { - unique_cache = PyDict_New(); - if (unique_cache == NULL) - 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"); - if (v == NULL || PyDict_SetItemString(CData_Type.tp_dict, - "__module__", v) < 0) - INITERROR; - v = PyText_FromString("<cdata>"); - if (v == NULL || PyDict_SetItemString(CData_Type.tp_dict, - "__name__", v) < 0) - INITERROR; - init_done = 1; - } - - /* this is for backward compatibility only */ - v = PyCapsule_New((void *)cffi_exports, "cffi", NULL); - if (v == NULL || PyModule_AddObject(m, "_C_API", v) < 0) - INITERROR; - - v = PyText_FromString(CFFI_VERSION); - if (v == NULL || PyModule_AddObject(m, "__version__", v) < 0) - INITERROR; - - if (PyModule_AddIntConstant(m, "FFI_DEFAULT_ABI", FFI_DEFAULT_ABI) < 0 || -#if defined(MS_WIN32) && !defined(_WIN64) - PyModule_AddIntConstant(m, "FFI_STDCALL", FFI_STDCALL) < 0 || -#endif - PyModule_AddIntConstant(m, "FFI_CDECL", FFI_DEFAULT_ABI) < 0 || - -#ifdef MS_WIN32 -# ifdef _WIN64 - PyModule_AddIntConstant(m, "_WIN", 64) < 0 || /* win64 */ -# else - PyModule_AddIntConstant(m, "_WIN", 32) < 0 || /* win32 */ -# endif -#endif - 0) - INITERROR; - - for (i = 0; all_dlopen_flags[i].name != NULL; i++) { - if (PyModule_AddIntConstant(m, - all_dlopen_flags[i].name, - all_dlopen_flags[i].value) < 0) - INITERROR; - } - - init_cffi_tls(); - if (PyErr_Occurred()) - INITERROR; - init_cffi_tls_zombie(); - if (PyErr_Occurred()) - INITERROR; - - if (init_ffi_lib(m) < 0) - INITERROR; - -#if PY_MAJOR_VERSION >= 3 - if (init_file_emulator() < 0) - INITERROR; - return m; -#endif -} diff --git a/c/_cffi_backend.so b/c/_cffi_backend.so Binary files differdeleted file mode 100755 index 31f7528..0000000 --- a/c/_cffi_backend.so +++ /dev/null diff --git a/c/_dummy_file_cffi_backend.py b/c/_dummy_file_cffi_backend.py deleted file mode 100644 index e69de29..0000000 --- a/c/_dummy_file_cffi_backend.py +++ /dev/null diff --git a/c/_dummy_file_libffi.py b/c/_dummy_file_libffi.py deleted file mode 100644 index e69de29..0000000 --- a/c/_dummy_file_libffi.py +++ /dev/null diff --git a/c/call_python.c b/c/call_python.c deleted file mode 100644 index d3d2e17..0000000 --- a/c/call_python.c +++ /dev/null @@ -1,292 +0,0 @@ -#if PY_VERSION_HEX >= 0x03080000 -# 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. - Does not return a new reference. Returns NULL in case of - error, but without setting any exception. (If called late - during shutdown, we *can't* set an exception!) - */ - static PyObject *attr_name = NULL; - PyThreadState *tstate; - PyObject *d, *interpdict; - int err; - PyInterpreterState *interp; - - tstate = PyThreadState_GET(); - if (tstate == NULL) { - /* no thread state! */ - return 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; - } - - /* from there on, we know the (sub-)interpreter is still valid */ - - if (attr_name == NULL) { - attr_name = PyText_InternFromString("__cffi_backend_extern_py"); - if (attr_name == NULL) - goto error; - } - - d = PyDict_GetItem(interpdict, attr_name); - if (d == NULL) { - d = PyDict_New(); - if (d == NULL) - goto error; - err = PyDict_SetItem(interpdict, attr_name, d); - Py_DECREF(d); /* if successful, there is one ref left in interpdict */ - if (err < 0) - goto error; - } - return d; - - error: - PyErr_Clear(); /* typically a MemoryError */ - return NULL; -} - -static PyObject *_ffi_def_extern_decorator(PyObject *outer_args, PyObject *fn) -{ - const char *s; - PyObject *error, *onerror, *infotuple, *old1; - int index, err; - const struct _cffi_global_s *g; - struct _cffi_externpy_s *externpy; - CTypeDescrObject *ct; - FFIObject *ffi; - builder_c_t *types_builder; - PyObject *name = NULL; - PyObject *interpstate_dict; - PyObject *interpstate_key; - - if (!PyArg_ParseTuple(outer_args, "OzOO", &ffi, &s, &error, &onerror)) - return NULL; - - if (s == NULL) { - name = PyObject_GetAttrString(fn, "__name__"); - if (name == NULL) - return NULL; - s = PyText_AsUTF8(name); - if (s == NULL) { - Py_DECREF(name); - return NULL; - } - } - - types_builder = &ffi->types_builder; - index = search_in_globals(&types_builder->ctx, s, strlen(s)); - if (index < 0) - goto not_found; - g = &types_builder->ctx.globals[index]; - if (_CFFI_GETOP(g->type_op) != _CFFI_OP_EXTERN_PYTHON) - goto not_found; - Py_XDECREF(name); - - ct = realize_c_type(types_builder, types_builder->ctx.types, - _CFFI_GETARG(g->type_op)); - if (ct == NULL) - return NULL; - - infotuple = prepare_callback_info_tuple(ct, fn, error, onerror, 0); - Py_DECREF(ct); - if (infotuple == NULL) - return NULL; - - /* don't directly attach infotuple to externpy: in the presence of - subinterpreters, each time we switch to a different - subinterpreter and call the C function, it will notice the - change and look up infotuple from the interpstate_dict. - */ - interpstate_dict = _get_interpstate_dict(); - if (interpstate_dict == NULL) { - Py_DECREF(infotuple); - return PyErr_NoMemory(); - } - - externpy = (struct _cffi_externpy_s *)g->address; - interpstate_key = PyLong_FromVoidPtr((void *)externpy); - if (interpstate_key == NULL) { - Py_DECREF(infotuple); - return NULL; - } - - err = PyDict_SetItem(interpstate_dict, interpstate_key, infotuple); - Py_DECREF(interpstate_key); - Py_DECREF(infotuple); /* interpstate_dict owns the last ref */ - if (err < 0) - return NULL; - - /* force _update_cache_to_call_python() to be called the next time - the C function invokes cffi_call_python, to update the cache */ - old1 = externpy->reserved1; - externpy->reserved1 = Py_None; /* a non-NULL value */ - Py_INCREF(Py_None); - Py_XDECREF(old1); - - /* return the function object unmodified */ - Py_INCREF(fn); - return fn; - - not_found: - PyErr_Format(FFIError, "ffi.def_extern('%s'): no 'extern \"Python\"' " - "function with this name", s); - Py_XDECREF(name); - return NULL; -} - - -static int _update_cache_to_call_python(struct _cffi_externpy_s *externpy) -{ - PyObject *interpstate_dict, *interpstate_key, *infotuple, *old1, *new1; - PyObject *old2; - - interpstate_dict = _get_interpstate_dict(); - if (interpstate_dict == NULL) - return 4; /* oops, shutdown issue? */ - - interpstate_key = PyLong_FromVoidPtr((void *)externpy); - if (interpstate_key == NULL) - goto error; - - infotuple = PyDict_GetItem(interpstate_dict, interpstate_key); - Py_DECREF(interpstate_key); - if (infotuple == NULL) - return 3; /* no ffi.def_extern() from this subinterpreter */ - - new1 = _current_interp_key(); - Py_INCREF(new1); - Py_INCREF(infotuple); - old1 = (PyObject *)externpy->reserved1; - old2 = (PyObject *)externpy->reserved2; - externpy->reserved1 = new1; /* holds a reference */ - externpy->reserved2 = infotuple; /* holds a reference (issue #246) */ - Py_XDECREF(old1); - Py_XDECREF(old2); - - return 0; /* no error */ - - error: - PyErr_Clear(); - return 2; /* out of memory? */ -} - -#if (defined(WITH_THREAD) && !defined(_MSC_VER) && \ - !defined(__amd64__) && !defined(__x86_64__) && \ - !defined(__i386__) && !defined(__i386)) -# if defined(HAVE_SYNC_SYNCHRONIZE) -# define read_barrier() __sync_synchronize() -# elif defined(_AIX) -# define read_barrier() __lwsync() -# elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) -# include <mbarrier.h> -# define read_barrier() __compiler_barrier() -# elif defined(__hpux) -# define read_barrier() _Asm_mf() -# else -# define read_barrier() /* missing */ -# warning "no definition for read_barrier(), missing synchronization for\ - multi-thread initialization in embedded mode" -# endif -#else -# define read_barrier() (void)0 -#endif - -static void cffi_call_python(struct _cffi_externpy_s *externpy, char *args) -{ - /* Invoked by the helpers generated from extern "Python" in the cdef. - - 'externpy' is a static structure that describes which of the - extern "Python" functions is called. It has got fields 'name' and - 'type_index' describing the function, and more reserved fields - that are initially zero. These reserved fields are set up by - ffi.def_extern(), which invokes _ffi_def_extern_decorator() above. - - 'args' is a pointer to an array of 8-byte entries. Each entry - contains an argument. If an argument is less than 8 bytes, only - the part at the beginning of the entry is initialized. If an - argument is 'long double' or a struct/union, then it is passed - by reference. - - 'args' is also used as the place to write the result to - (directly, even if more than 8 bytes). In all cases, 'args' is - at least 8 bytes in size. - */ - int err = 0; - - /* This read barrier is needed for _embedding.h. It is paired - with the write_barrier() there. Without this barrier, we can - in theory see the following situation: the Python - initialization code already ran (in another thread), and the - '_cffi_call_python' function pointer directed execution here; - but any number of other data could still be seen as - uninitialized below. For example, 'externpy' would still - contain NULLs even though it was correctly set up, or - 'interpreter_lock' (the GIL inside CPython) would still be seen - as NULL, or 'autoInterpreterState' (used by - PyGILState_Ensure()) would be NULL or contain bogus fields. - */ - read_barrier(); - - save_errno(); - - /* We need the infotuple here. We could always go through - _update_cache_to_call_python(), but to avoid the extra dict - lookups, we cache in (reserved1, reserved2) the last seen pair - (interp->modules, infotuple). The first item in this tuple is - a random PyObject that identifies the subinterpreter. - */ - if (externpy->reserved1 == NULL) { - /* Not initialized! We didn't call @ffi.def_extern() on this - externpy object from any subinterpreter at all. */ - err = 1; - } - else { - PyGILState_STATE state = gil_ensure(); - 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. */ - err = _update_cache_to_call_python(externpy); - } - if (!err) { - general_invoke_callback(0, args, args, externpy->reserved2); - } - gil_release(state); - } - if (err) { - static const char *msg[] = { - "no code was attached to it yet with @ffi.def_extern()", - "got internal exception (out of memory?)", - "@ffi.def_extern() was not called in the current subinterpreter", - "got internal exception (shutdown issue?)", - }; - fprintf(stderr, "extern \"Python\": function %s() called, " - "but %s. Returning 0.\n", externpy->name, msg[err-1]); - memset(args, 0, externpy->size_of_result); - } - restore_errno(); -} diff --git a/c/cdlopen.c b/c/cdlopen.c deleted file mode 100644 index 0ed319b..0000000 --- a/c/cdlopen.c +++ /dev/null @@ -1,362 +0,0 @@ -/* ffi.dlopen() interface with dlopen()/dlsym()/dlclose() */ - -static void *cdlopen_fetch(PyObject *libname, void *libhandle, - const char *symbol) -{ - void *address; - - if (libhandle == NULL) { - PyErr_Format(FFIError, "library '%s' has been closed", - PyText_AS_UTF8(libname)); - return NULL; - } - - dlerror(); /* clear error condition */ - address = dlsym(libhandle, symbol); - if (address == NULL) { - const char *error = dlerror(); - PyErr_Format(FFIError, "symbol '%s' not found in library '%s': %s", - symbol, PyText_AS_UTF8(libname), error); - } - return address; -} - -static void cdlopen_close_ignore_errors(void *libhandle) -{ - if (libhandle != NULL) - dlclose(libhandle); -} - -static int cdlopen_close(PyObject *libname, void *libhandle) -{ - if (libhandle != NULL && dlclose(libhandle) != 0) { - const char *error = dlerror(); - PyErr_Format(FFIError, "closing library '%s': %s", - PyText_AS_UTF8(libname), error); - return -1; - } - return 0; -} - -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, &auto_close); - if (handle != NULL) - { - result = (PyObject *)lib_internal_new((FFIObject *)self, - modname, handle, auto_close); - } - Py_XDECREF(temp); - return result; -} - -static PyObject *ffi_dlclose(PyObject *self, PyObject *args) -{ - LibObject *lib; - void *libhandle; - if (!PyArg_ParseTuple(args, "O!", &Lib_Type, &lib)) - return NULL; - - libhandle = lib->l_libhandle; - if (libhandle != NULL) - { - lib->l_libhandle = NULL; - - /* Clear the dict to force further accesses to do cdlopen_fetch() - again, and fail because the library was closed. */ - PyDict_Clear(lib->l_dict); - - if (cdlopen_close(lib->l_libname, libhandle) < 0) - return NULL; - } - Py_INCREF(Py_None); - return Py_None; -} - - -static Py_ssize_t cdl_4bytes(char *src) -{ - /* read 4 bytes in little-endian order; return it as a signed integer */ - signed char *ssrc = (signed char *)src; - unsigned char *usrc = (unsigned char *)src; - return (ssrc[0] << 24) | (usrc[1] << 16) | (usrc[2] << 8) | usrc[3]; -} - -static _cffi_opcode_t cdl_opcode(char *src) -{ - return (_cffi_opcode_t)cdl_4bytes(src); -} - -typedef struct { - unsigned long long value; - int neg; -} cdl_intconst_t; - -static int _cdl_realize_global_int(struct _cffi_getconst_s *gc) -{ - /* The 'address' field of 'struct _cffi_global_s' is set to point - to this function in case ffiobj_init() sees constant integers. - This fishes around after the 'ctx->globals' array, which is - initialized to contain another array, this time of - 'cdl_intconst_t' structures. We get the nth one and it tells - us what to return. - */ - cdl_intconst_t *ic; - ic = (cdl_intconst_t *)(gc->ctx->globals + gc->ctx->num_globals); - ic += gc->gindex; - gc->value = ic->value; - return ic->neg; -} - -static int ffiobj_init(PyObject *self, PyObject *args, PyObject *kwds) -{ - FFIObject *ffi; - static char *keywords[] = {"module_name", "_version", "_types", - "_globals", "_struct_unions", "_enums", - "_typenames", "_includes", NULL}; - char *ffiname = "?", *types = NULL, *building = NULL; - Py_ssize_t version = -1; - Py_ssize_t types_len = 0; - PyObject *globals = NULL, *struct_unions = NULL, *enums = NULL; - PyObject *typenames = NULL, *includes = NULL; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, - "|sns#O!O!O!O!O!:FFI", keywords, - &ffiname, &version, &types, &types_len, - &PyTuple_Type, &globals, - &PyTuple_Type, &struct_unions, - &PyTuple_Type, &enums, - &PyTuple_Type, &typenames, - &PyTuple_Type, &includes)) - return -1; - - ffi = (FFIObject *)self; - if (ffi->ctx_is_nonempty) { - PyErr_SetString(PyExc_ValueError, - "cannot call FFI.__init__() more than once"); - return -1; - } - ffi->ctx_is_nonempty = 1; - - if (version == -1 && types_len == 0) - return 0; - if (version < CFFI_VERSION_MIN || version > CFFI_VERSION_MAX) { - PyErr_Format(PyExc_ImportError, - "cffi out-of-line Python module '%s' has unknown " - "version %p", ffiname, (void *)version); - return -1; - } - - if (types_len > 0) { - /* unpack a string of 4-byte entries into an array of _cffi_opcode_t */ - _cffi_opcode_t *ntypes; - Py_ssize_t i, n = types_len / 4; - - building = PyMem_Malloc(n * sizeof(_cffi_opcode_t)); - if (building == NULL) - goto error; - ntypes = (_cffi_opcode_t *)building; - - for (i = 0; i < n; i++) { - ntypes[i] = cdl_opcode(types); - types += 4; - } - ffi->types_builder.ctx.types = ntypes; - ffi->types_builder.ctx.num_types = n; - building = NULL; - } - - if (globals != NULL) { - /* unpack a tuple alternating strings and ints, each two together - describing one global_s entry with no specified address or size. - The int is only used with integer constants. */ - struct _cffi_global_s *nglobs; - cdl_intconst_t *nintconsts; - Py_ssize_t i, n = PyTuple_GET_SIZE(globals) / 2; - - i = n * (sizeof(struct _cffi_global_s) + sizeof(cdl_intconst_t)); - building = PyMem_Malloc(i); - if (building == NULL) - goto error; - memset(building, 0, i); - nglobs = (struct _cffi_global_s *)building; - nintconsts = (cdl_intconst_t *)(nglobs + n); - - for (i = 0; i < n; i++) { - char *g = PyBytes_AS_STRING(PyTuple_GET_ITEM(globals, i * 2)); - nglobs[i].type_op = cdl_opcode(g); g += 4; - nglobs[i].name = g; - if (_CFFI_GETOP(nglobs[i].type_op) == _CFFI_OP_CONSTANT_INT || - _CFFI_GETOP(nglobs[i].type_op) == _CFFI_OP_ENUM) { - PyObject *o = PyTuple_GET_ITEM(globals, i * 2 + 1); - nglobs[i].address = &_cdl_realize_global_int; -#if PY_MAJOR_VERSION < 3 - if (PyInt_Check(o)) { - nintconsts[i].neg = PyInt_AS_LONG(o) <= 0; - nintconsts[i].value = (long long)PyInt_AS_LONG(o); - } - else -#endif - { - nintconsts[i].neg = PyObject_RichCompareBool(o, Py_False, - Py_LE); - nintconsts[i].value = PyLong_AsUnsignedLongLongMask(o); - if (PyErr_Occurred()) - goto error; - } - } - } - ffi->types_builder.ctx.globals = nglobs; - ffi->types_builder.ctx.num_globals = n; - building = NULL; - } - - if (struct_unions != NULL) { - /* unpack a tuple of struct/unions, each described as a sub-tuple; - the item 0 of each sub-tuple describes the struct/union, and - the items 1..N-1 describe the fields, if any */ - struct _cffi_struct_union_s *nstructs; - struct _cffi_field_s *nfields; - Py_ssize_t i, n = PyTuple_GET_SIZE(struct_unions); - Py_ssize_t nf = 0; /* total number of fields */ - - for (i = 0; i < n; i++) { - nf += PyTuple_GET_SIZE(PyTuple_GET_ITEM(struct_unions, i)) - 1; - } - i = (n * sizeof(struct _cffi_struct_union_s) + - nf * sizeof(struct _cffi_field_s)); - building = PyMem_Malloc(i); - if (building == NULL) - goto error; - memset(building, 0, i); - nstructs = (struct _cffi_struct_union_s *)building; - nfields = (struct _cffi_field_s *)(nstructs + n); - nf = 0; - - for (i = 0; i < n; i++) { - /* 'desc' is the tuple of strings (desc_struct, desc_field_1, ..) */ - PyObject *desc = PyTuple_GET_ITEM(struct_unions, i); - Py_ssize_t j, nf1 = PyTuple_GET_SIZE(desc) - 1; - char *s = PyBytes_AS_STRING(PyTuple_GET_ITEM(desc, 0)); - /* 's' is the first string, describing the struct/union */ - nstructs[i].type_index = cdl_4bytes(s); s += 4; - nstructs[i].flags = cdl_4bytes(s); s += 4; - nstructs[i].name = s; - if (nstructs[i].flags & (_CFFI_F_OPAQUE | _CFFI_F_EXTERNAL)) { - nstructs[i].size = (size_t)-1; - nstructs[i].alignment = -1; - nstructs[i].first_field_index = -1; - nstructs[i].num_fields = 0; - assert(nf1 == 0); - } - else { - nstructs[i].size = (size_t)-2; - nstructs[i].alignment = -2; - nstructs[i].first_field_index = nf; - nstructs[i].num_fields = nf1; - } - for (j = 0; j < nf1; j++) { - char *f = PyBytes_AS_STRING(PyTuple_GET_ITEM(desc, j + 1)); - /* 'f' is one of the other strings beyond the first one, - describing one field each */ - nfields[nf].field_type_op = cdl_opcode(f); f += 4; - nfields[nf].field_offset = (size_t)-1; - if (_CFFI_GETOP(nfields[nf].field_type_op) != _CFFI_OP_NOOP) { - nfields[nf].field_size = cdl_4bytes(f); f += 4; - } - else { - nfields[nf].field_size = (size_t)-1; - } - nfields[nf].name = f; - nf++; - } - } - ffi->types_builder.ctx.struct_unions = nstructs; - ffi->types_builder.ctx.fields = nfields; - ffi->types_builder.ctx.num_struct_unions = n; - building = NULL; - } - - if (enums != NULL) { - /* unpack a tuple of strings, each of which describes one enum_s - entry */ - struct _cffi_enum_s *nenums; - Py_ssize_t i, n = PyTuple_GET_SIZE(enums); - - i = n * sizeof(struct _cffi_enum_s); - building = PyMem_Malloc(i); - if (building == NULL) - goto error; - memset(building, 0, i); - nenums = (struct _cffi_enum_s *)building; - - for (i = 0; i < n; i++) { - char *e = PyBytes_AS_STRING(PyTuple_GET_ITEM(enums, i)); - /* 'e' is a string describing the enum */ - nenums[i].type_index = cdl_4bytes(e); e += 4; - nenums[i].type_prim = cdl_4bytes(e); e += 4; - nenums[i].name = e; e += strlen(e) + 1; - nenums[i].enumerators = e; - } - ffi->types_builder.ctx.enums = nenums; - ffi->types_builder.ctx.num_enums = n; - building = NULL; - } - - if (typenames != NULL) { - /* unpack a tuple of strings, each of which describes one typename_s - entry */ - struct _cffi_typename_s *ntypenames; - Py_ssize_t i, n = PyTuple_GET_SIZE(typenames); - - i = n * sizeof(struct _cffi_typename_s); - building = PyMem_Malloc(i); - if (building == NULL) - goto error; - memset(building, 0, i); - ntypenames = (struct _cffi_typename_s *)building; - - for (i = 0; i < n; i++) { - char *t = PyBytes_AS_STRING(PyTuple_GET_ITEM(typenames, i)); - /* 't' is a string describing the typename */ - ntypenames[i].type_index = cdl_4bytes(t); t += 4; - ntypenames[i].name = t; - } - ffi->types_builder.ctx.typenames = ntypenames; - ffi->types_builder.ctx.num_typenames = n; - building = NULL; - } - - if (includes != NULL) { - PyObject *included_libs; - - included_libs = PyTuple_New(PyTuple_GET_SIZE(includes)); - if (included_libs == NULL) - return -1; - - Py_INCREF(includes); - ffi->types_builder.included_ffis = includes; - ffi->types_builder.included_libs = included_libs; - } - - /* Above, we took directly some "char *" strings out of the strings, - typically from somewhere inside tuples. Keep them alive by - incref'ing the whole input arguments. */ - Py_INCREF(args); - Py_XINCREF(kwds); - ffi->types_builder._keepalive1 = args; - ffi->types_builder._keepalive2 = kwds; - return 0; - - error: - if (building != NULL) - PyMem_Free(building); - if (!PyErr_Occurred()) - PyErr_NoMemory(); - return -1; -} diff --git a/c/cffi1_module.c b/c/cffi1_module.c deleted file mode 100644 index 06a84fe..0000000 --- a/c/cffi1_module.c +++ /dev/null @@ -1,216 +0,0 @@ - -#include "parse_c_type.c" -#include "realize_c_type.c" - -#define CFFI_VERSION_MIN 0x2601 -#define CFFI_VERSION_CHAR16CHAR32 0x2801 -#define CFFI_VERSION_MAX 0x28FF - -typedef struct FFIObject_s FFIObject; -typedef struct LibObject_s LibObject; - -static PyTypeObject FFI_Type; /* forward */ -static PyTypeObject Lib_Type; /* forward */ - -#include "ffi_obj.c" -#include "cglob.c" -#include "lib_obj.c" -#include "cdlopen.c" -#include "commontypes.c" -#include "call_python.c" - - -static int init_ffi_lib(PyObject *m) -{ - PyObject *x; - int i, res; - static char init_done = 0; - - if (!init_done) { - if (init_global_types_dict(FFI_Type.tp_dict) < 0) - return -1; - - FFIError = PyErr_NewException("ffi.error", NULL, NULL); - if (FFIError == NULL) - return -1; - if (PyDict_SetItemString(FFI_Type.tp_dict, "error", FFIError) < 0) - return -1; - if (PyDict_SetItemString(FFI_Type.tp_dict, "CType", - (PyObject *)&CTypeDescr_Type) < 0) - return -1; - if (PyDict_SetItemString(FFI_Type.tp_dict, "CData", - (PyObject *)&CData_Type) < 0) - return -1; - if (PyDict_SetItemString(FFI_Type.tp_dict, "buffer", - (PyObject *)&MiniBuffer_Type) < 0) - return -1; - - for (i = 0; all_dlopen_flags[i].name != NULL; i++) { - x = PyInt_FromLong(all_dlopen_flags[i].value); - if (x == NULL) - return -1; - res = PyDict_SetItemString(FFI_Type.tp_dict, - all_dlopen_flags[i].name, x); - Py_DECREF(x); - if (res < 0) - return -1; - } - init_done = 1; - } - return 0; -} - -static int make_included_tuples(char *module_name, - const char *const *ctx_includes, - PyObject **included_ffis, - PyObject **included_libs) -{ - Py_ssize_t num = 0; - const char *const *p_include; - - if (ctx_includes == NULL) - return 0; - - for (p_include = ctx_includes; *p_include; p_include++) { - num++; - } - *included_ffis = PyTuple_New(num); - *included_libs = PyTuple_New(num); - if (*included_ffis == NULL || *included_libs == NULL) - goto error; - - num = 0; - for (p_include = ctx_includes; *p_include; p_include++) { - PyObject *included_ffi, *included_lib; - PyObject *m = PyImport_ImportModule(*p_include); - if (m == NULL) - goto import_error; - - included_ffi = PyObject_GetAttrString(m, "ffi"); - PyTuple_SET_ITEM(*included_ffis, num, included_ffi); - - included_lib = (included_ffi == NULL) ? NULL : - PyObject_GetAttrString(m, "lib"); - PyTuple_SET_ITEM(*included_libs, num, included_lib); - - Py_DECREF(m); - if (included_lib == NULL) - goto import_error; - - if (!FFIObject_Check(included_ffi) || - !LibObject_Check(included_lib)) - goto import_error; - num++; - } - return 0; - - import_error: - PyErr_Format(PyExc_ImportError, - "while loading %.200s: failed to import ffi, lib from %.200s", - module_name, *p_include); - error: - Py_XDECREF(*included_ffis); *included_ffis = NULL; - Py_XDECREF(*included_libs); *included_libs = NULL; - return -1; -} - -static PyObject *_my_Py_InitModule(char *module_name) -{ -#if PY_MAJOR_VERSION >= 3 - struct PyModuleDef *module_def, local_module_def = { - PyModuleDef_HEAD_INIT, - module_name, - NULL, - -1, - NULL, NULL, NULL, NULL, NULL - }; - /* note: the 'module_def' is allocated dynamically and leaks, - but anyway the C extension module can never be unloaded */ - module_def = PyMem_Malloc(sizeof(struct PyModuleDef)); - if (module_def == NULL) - return PyErr_NoMemory(); - *module_def = local_module_def; - return PyModule_Create(module_def); -#else - return Py_InitModule(module_name, NULL); -#endif -} - -static PyObject *b_init_cffi_1_0_external_module(PyObject *self, PyObject *arg) -{ - PyObject *m, *modules_dict; - FFIObject *ffi; - LibObject *lib; - Py_ssize_t version, num_exports; - char *module_name, *exports, *module_name_with_lib; - void **raw; - const struct _cffi_type_context_s *ctx; - - raw = (void **)PyLong_AsVoidPtr(arg); - if (raw == NULL) - return NULL; - - module_name = (char *)raw[0]; - version = (Py_ssize_t)raw[1]; - exports = (char *)raw[2]; - ctx = (const struct _cffi_type_context_s *)raw[3]; - - if (version < CFFI_VERSION_MIN || version > CFFI_VERSION_MAX) { - if (!PyErr_Occurred()) - PyErr_Format(PyExc_ImportError, - "cffi extension module '%s' uses an unknown version tag %p. " - "This module might need a more recent version of cffi " - "than the one currently installed, which is %s", - module_name, (void *)version, CFFI_VERSION); - return NULL; - } - - /* initialize the exports array */ - num_exports = 25; - if (ctx->flags & 1) /* set to mean that 'extern "Python"' is used */ - num_exports = 26; - if (version >= CFFI_VERSION_CHAR16CHAR32) - num_exports = 28; - memcpy(exports, (char *)cffi_exports, num_exports * sizeof(void *)); - - /* make the module object */ - m = _my_Py_InitModule(module_name); - if (m == NULL) - return NULL; - - /* build the FFI and Lib object inside this new module */ - ffi = ffi_internal_new(&FFI_Type, ctx); - Py_XINCREF(ffi); /* make the ffi object really immortal */ - if (ffi == NULL || PyModule_AddObject(m, "ffi", (PyObject *)ffi) < 0) - return NULL; - - lib = lib_internal_new(ffi, module_name, NULL, 0); - if (lib == NULL || PyModule_AddObject(m, "lib", (PyObject *)lib) < 0) - return NULL; - - if (make_included_tuples(module_name, ctx->includes, - &ffi->types_builder.included_ffis, - &lib->l_types_builder->included_libs) < 0) - return NULL; - - /* add manually 'module_name.lib' in sys.modules: - see test_import_from_lib */ - modules_dict = PySys_GetObject("modules"); - if (!modules_dict) - return NULL; - module_name_with_lib = alloca(strlen(module_name) + 5); - strcpy(module_name_with_lib, module_name); - strcat(module_name_with_lib, ".lib"); - if (PyDict_SetItemString(modules_dict, module_name_with_lib, - (PyObject *)lib) < 0) - return NULL; - -#if PY_MAJOR_VERSION >= 3 - /* add manually 'module_name' in sys.modules: it seems that - Py_InitModule() is not enough to do that */ - if (PyDict_SetItemString(modules_dict, module_name, m) < 0) - return NULL; -#endif - - return m; -} diff --git a/c/cglob.c b/c/cglob.c deleted file mode 100644 index e97767c..0000000 --- a/c/cglob.c +++ /dev/null @@ -1,113 +0,0 @@ - -typedef void *(*gs_fetch_addr_fn)(void); - -typedef struct { - PyObject_HEAD - - PyObject *gs_name; - CTypeDescrObject *gs_type; - char *gs_data; - gs_fetch_addr_fn gs_fetch_addr; - -} GlobSupportObject; - -static void glob_support_dealloc(GlobSupportObject *gs) -{ - Py_DECREF(gs->gs_name); - Py_DECREF(gs->gs_type); - PyObject_Del(gs); -} - -static PyTypeObject GlobSupport_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_cffi_backend.__FFIGlobSupport", - sizeof(GlobSupportObject), - 0, - (destructor)glob_support_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ -}; - -#define GlobSupport_Check(ob) (Py_TYPE(ob) == &GlobSupport_Type) - -static PyObject *make_global_var(PyObject *name, CTypeDescrObject *type, - char *addr, gs_fetch_addr_fn fetch_addr) -{ - GlobSupportObject *gs = PyObject_New(GlobSupportObject, &GlobSupport_Type); - if (gs == NULL) - return NULL; - - Py_INCREF(name); - Py_INCREF(type); - gs->gs_name = name; - gs->gs_type = type; - gs->gs_data = addr; - gs->gs_fetch_addr = fetch_addr; - return (PyObject *)gs; -} - -static void *fetch_global_var_addr(GlobSupportObject *gs) -{ - void *data; - if (gs->gs_data != NULL) { - data = gs->gs_data; - } - else { - Py_BEGIN_ALLOW_THREADS - restore_errno(); - data = gs->gs_fetch_addr(); - save_errno(); - Py_END_ALLOW_THREADS - } - if (data == NULL) { - PyErr_Format(FFIError, "global variable '%s' is at address NULL", - PyText_AS_UTF8(gs->gs_name)); - return NULL; - } - return data; -} - -static PyObject *read_global_var(GlobSupportObject *gs) -{ - void *data = fetch_global_var_addr(gs); - if (data == NULL) - return NULL; - return convert_to_object(data, gs->gs_type); -} - -static int write_global_var(GlobSupportObject *gs, PyObject *obj) -{ - void *data = fetch_global_var_addr(gs); - if (data == NULL) - return -1; - return convert_from_object(data, gs->gs_type, obj); -} - -static PyObject *cg_addressof_global_var(GlobSupportObject *gs) -{ - void *data; - PyObject *x, *ptrtype = new_pointer_type(gs->gs_type); - if (ptrtype == NULL) - return NULL; - - data = fetch_global_var_addr(gs); - if (data != NULL) - x = new_simple_cdata(data, (CTypeDescrObject *)ptrtype); - else - x = NULL; - Py_DECREF(ptrtype); - return x; -} diff --git a/c/commontypes.c b/c/commontypes.c deleted file mode 100644 index a41c2fd..0000000 --- a/c/commontypes.c +++ /dev/null @@ -1,216 +0,0 @@ -/* This file must be kept in alphabetical order. See test_commontypes.py */ - -#define EQ(key, value) key "\0" value /* string concatenation */ -#ifdef _WIN64 -# define W32_64(X,Y) Y -# else -# define W32_64(X,Y) X -# endif - - -static const char *common_simple_types[] = { - -#ifdef MS_WIN32 /* Windows types */ - EQ("ATOM", "WORD"), - EQ("BOOL", "int"), - EQ("BOOLEAN", "BYTE"), - EQ("BYTE", "unsigned char"), - EQ("CCHAR", "char"), - EQ("CHAR", "char"), - EQ("COLORREF", "DWORD"), - EQ("DWORD", "unsigned long"), - EQ("DWORD32", "unsigned int"), - EQ("DWORD64", "unsigned long long"), - EQ("DWORDLONG", "ULONGLONG"), - EQ("DWORD_PTR", "ULONG_PTR"), -#endif - - EQ("FILE", "struct _IO_FILE"), - -#ifdef MS_WIN32 /* more Windows types */ - EQ("FLOAT", "float"), - EQ("HACCEL", "HANDLE"), - EQ("HALF_PTR", W32_64("short","int")), - EQ("HANDLE", "PVOID"), - EQ("HBITMAP", "HANDLE"), - EQ("HBRUSH", "HANDLE"), - EQ("HCOLORSPACE", "HANDLE"), - EQ("HCONV", "HANDLE"), - EQ("HCONVLIST", "HANDLE"), - EQ("HCURSOR", "HICON"), - EQ("HDC", "HANDLE"), - EQ("HDDEDATA", "HANDLE"), - EQ("HDESK", "HANDLE"), - EQ("HDROP", "HANDLE"), - EQ("HDWP", "HANDLE"), - EQ("HENHMETAFILE", "HANDLE"), - EQ("HFILE", "int"), - EQ("HFONT", "HANDLE"), - EQ("HGDIOBJ", "HANDLE"), - EQ("HGLOBAL", "HANDLE"), - EQ("HHOOK", "HANDLE"), - EQ("HICON", "HANDLE"), - EQ("HINSTANCE", "HANDLE"), - EQ("HKEY", "HANDLE"), - EQ("HKL", "HANDLE"), - EQ("HLOCAL", "HANDLE"), - EQ("HMENU", "HANDLE"), - EQ("HMETAFILE", "HANDLE"), - EQ("HMODULE", "HINSTANCE"), - EQ("HMONITOR", "HANDLE"), - EQ("HPALETTE", "HANDLE"), - EQ("HPEN", "HANDLE"), - EQ("HRESULT", "LONG"), - EQ("HRGN", "HANDLE"), - EQ("HRSRC", "HANDLE"), - EQ("HSZ", "HANDLE"), - EQ("HWND", "HANDLE"), - EQ("INT", "int"), - EQ("INT16", "short"), - EQ("INT32", "int"), - EQ("INT64", "long long"), - EQ("INT8", "signed char"), - EQ("INT_PTR", W32_64("int","long long")), - EQ("LANGID", "WORD"), - EQ("LCID", "DWORD"), - EQ("LCTYPE", "DWORD"), - EQ("LGRPID", "DWORD"), - EQ("LONG", "long"), - EQ("LONG32", "int"), - EQ("LONG64", "long long"), - EQ("LONGLONG", "long long"), - EQ("LONG_PTR", W32_64("long","long long")), - EQ("LPARAM", "LONG_PTR"), - EQ("LPBOOL", "BOOL *"), - EQ("LPBYTE", "BYTE *"), - EQ("LPCOLORREF", "DWORD *"), - EQ("LPCSTR", "const char *"), - EQ("LPCVOID", "const void *"), - EQ("LPCWSTR", "const WCHAR *"), - EQ("LPDWORD", "DWORD *"), - EQ("LPHANDLE", "HANDLE *"), - EQ("LPINT", "int *"), - EQ("LPLONG", "long *"), - EQ("LPSTR", "CHAR *"), - EQ("LPVOID", "void *"), - EQ("LPWORD", "WORD *"), - EQ("LPWSTR", "WCHAR *"), - EQ("LRESULT", "LONG_PTR"), - EQ("PBOOL", "BOOL *"), - EQ("PBOOLEAN", "BOOLEAN *"), - EQ("PBYTE", "BYTE *"), - EQ("PCHAR", "CHAR *"), - EQ("PCSTR", "const CHAR *"), - EQ("PCWSTR", "const WCHAR *"), - EQ("PDWORD", "DWORD *"), - EQ("PDWORD32", "DWORD32 *"), - EQ("PDWORD64", "DWORD64 *"), - EQ("PDWORDLONG", "DWORDLONG *"), - EQ("PDWORD_PTR", "DWORD_PTR *"), - EQ("PFLOAT", "FLOAT *"), - EQ("PHALF_PTR", "HALF_PTR *"), - EQ("PHANDLE", "HANDLE *"), - EQ("PHKEY", "HKEY *"), - EQ("PINT", "int *"), - EQ("PINT16", "INT16 *"), - EQ("PINT32", "INT32 *"), - EQ("PINT64", "INT64 *"), - EQ("PINT8", "INT8 *"), - EQ("PINT_PTR", "INT_PTR *"), - EQ("PLCID", "PDWORD"), - EQ("PLONG", "LONG *"), - EQ("PLONG32", "LONG32 *"), - EQ("PLONG64", "LONG64 *"), - EQ("PLONGLONG", "LONGLONG *"), - EQ("PLONG_PTR", "LONG_PTR *"), - EQ("PSHORT", "SHORT *"), - EQ("PSIZE_T", "SIZE_T *"), - EQ("PSSIZE_T", "SSIZE_T *"), - EQ("PSTR", "CHAR *"), - EQ("PUCHAR", "UCHAR *"), - EQ("PUHALF_PTR", "UHALF_PTR *"), - EQ("PUINT", "UINT *"), - EQ("PUINT16", "UINT16 *"), - EQ("PUINT32", "UINT32 *"), - EQ("PUINT64", "UINT64 *"), - EQ("PUINT8", "UINT8 *"), - EQ("PUINT_PTR", "UINT_PTR *"), - EQ("PULONG", "ULONG *"), - EQ("PULONG32", "ULONG32 *"), - EQ("PULONG64", "ULONG64 *"), - EQ("PULONGLONG", "ULONGLONG *"), - EQ("PULONG_PTR", "ULONG_PTR *"), - EQ("PUSHORT", "USHORT *"), - EQ("PVOID", "void *"), - EQ("PWCHAR", "WCHAR *"), - EQ("PWORD", "WORD *"), - EQ("PWSTR", "WCHAR *"), - EQ("QWORD", "unsigned long long"), - EQ("SC_HANDLE", "HANDLE"), - EQ("SC_LOCK", "LPVOID"), - EQ("SERVICE_STATUS_HANDLE", "HANDLE"), - EQ("SHORT", "short"), - EQ("SIZE_T", "ULONG_PTR"), - EQ("SSIZE_T", "LONG_PTR"), - EQ("UCHAR", "unsigned char"), - EQ("UHALF_PTR", W32_64("unsigned short","unsigned int")), - EQ("UINT", "unsigned int"), - EQ("UINT16", "unsigned short"), - EQ("UINT32", "unsigned int"), - EQ("UINT64", "unsigned long long"), - EQ("UINT8", "unsigned char"), - EQ("UINT_PTR", W32_64("unsigned int","unsigned long long")), - EQ("ULONG", "unsigned long"), - EQ("ULONG32", "unsigned int"), - EQ("ULONG64", "unsigned long long"), - EQ("ULONGLONG", "unsigned long long"), - EQ("ULONG_PTR", W32_64("unsigned long","unsigned long long")), - EQ("USHORT", "unsigned short"), - EQ("USN", "LONGLONG"), - EQ("VOID", "void"), - EQ("WCHAR", "wchar_t"), - EQ("WINSTA", "HANDLE"), - EQ("WORD", "unsigned short"), - EQ("WPARAM", "UINT_PTR"), -#endif - - EQ("bool", "_Bool"), -}; - - -#undef EQ -#undef W32_64 - -#define num_common_simple_types \ - (sizeof(common_simple_types) / sizeof(common_simple_types[0])) - - -static const char *get_common_type(const char *search, size_t search_len) -{ - const char *entry; - int index = search_sorted(common_simple_types, sizeof(const char *), - num_common_simple_types, search, search_len); - if (index < 0) - return NULL; - - entry = common_simple_types[index]; - return entry + strlen(entry) + 1; -} - -static PyObject *b__get_common_types(PyObject *self, PyObject *arg) -{ - int err; - size_t i; - for (i = 0; i < num_common_simple_types; i++) { - const char *s = common_simple_types[i]; - PyObject *o = PyText_FromString(s + strlen(s) + 1); - if (o == NULL) - return NULL; - err = PyDict_SetItemString(arg, s, o); - Py_DECREF(o); - if (err < 0) - return NULL; - } - Py_INCREF(Py_None); - return Py_None; -} diff --git a/c/ffi_obj.c b/c/ffi_obj.c deleted file mode 100644 index f154146..0000000 --- a/c/ffi_obj.c +++ /dev/null @@ -1,1221 +0,0 @@ - -/* An FFI object has methods like ffi.new(). It is also a container - for the type declarations (typedefs and structs) that you can use, - say in ffi.new(). - - CTypeDescrObjects are internally stored in the dict 'types_dict'. - The types_dict is lazily filled with CTypeDescrObjects made from - reading a _cffi_type_context_s structure. - - In "modern" mode, the FFI instance is made by the C extension - module originally created by recompile(). The _cffi_type_context_s - structure comes from global data in the C extension module. - - In "compatibility" mode, an FFI instance is created explicitly by - the user, and its _cffi_type_context_s is initially empty. You - need to call ffi.cdef() to add more information to it. -*/ - -#define FFI_COMPLEXITY_OUTPUT 1200 /* xxx should grow as needed */ - -#define FFIObject_Check(op) PyObject_TypeCheck(op, &FFI_Type) -#define LibObject_Check(ob) ((Py_TYPE(ob) == &Lib_Type)) - -struct FFIObject_s { - PyObject_HEAD - PyObject *gc_wrefs, *gc_wrefs_freelist; - PyObject *init_once_cache; - struct _cffi_parse_info_s info; - char ctx_is_static, ctx_is_nonempty; - builder_c_t types_builder; -}; - -static FFIObject *ffi_internal_new(PyTypeObject *ffitype, - const struct _cffi_type_context_s *static_ctx) -{ - static _cffi_opcode_t internal_output[FFI_COMPLEXITY_OUTPUT]; - - FFIObject *ffi; - if (static_ctx != NULL) { - ffi = (FFIObject *)PyObject_GC_New(FFIObject, ffitype); - /* we don't call PyObject_GC_Track() here: from _cffi_init_module() - it is not needed, because in this case the ffi object is immortal */ - } - else { - ffi = (FFIObject *)ffitype->tp_alloc(ffitype, 0); - } - if (ffi == NULL) - return NULL; - - if (init_builder_c(&ffi->types_builder, static_ctx) < 0) { - Py_DECREF(ffi); - return NULL; - } - ffi->gc_wrefs = NULL; - ffi->gc_wrefs_freelist = NULL; - ffi->init_once_cache = NULL; - ffi->info.ctx = &ffi->types_builder.ctx; - ffi->info.output = internal_output; - ffi->info.output_size = FFI_COMPLEXITY_OUTPUT; - ffi->ctx_is_static = (static_ctx != NULL); - ffi->ctx_is_nonempty = (static_ctx != NULL); - return ffi; -} - -static void ffi_dealloc(FFIObject *ffi) -{ - PyObject_GC_UnTrack(ffi); - Py_XDECREF(ffi->gc_wrefs); - Py_XDECREF(ffi->gc_wrefs_freelist); - Py_XDECREF(ffi->init_once_cache); - - free_builder_c(&ffi->types_builder, ffi->ctx_is_static); - - Py_TYPE(ffi)->tp_free((PyObject *)ffi); -} - -static int ffi_traverse(FFIObject *ffi, visitproc visit, void *arg) -{ - Py_VISIT(ffi->types_builder.types_dict); - Py_VISIT(ffi->types_builder.included_ffis); - Py_VISIT(ffi->types_builder.included_libs); - Py_VISIT(ffi->gc_wrefs); - return 0; -} - -static PyObject *ffiobj_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - /* user-facing initialization code, for explicit FFI() calls */ - return (PyObject *)ffi_internal_new(type, NULL); -} - -/* forward, declared in cdlopen.c because it's mostly useful for this case */ -static int ffiobj_init(PyObject *self, PyObject *args, PyObject *kwds); - -static PyObject *ffi_fetch_int_constant(FFIObject *ffi, const char *name, - int recursion) -{ - int index; - - index = search_in_globals(&ffi->types_builder.ctx, name, strlen(name)); - if (index >= 0) { - const struct _cffi_global_s *g; - g = &ffi->types_builder.ctx.globals[index]; - - switch (_CFFI_GETOP(g->type_op)) { - case _CFFI_OP_CONSTANT_INT: - case _CFFI_OP_ENUM: - return realize_global_int(&ffi->types_builder, index); - - default: - PyErr_Format(FFIError, - "function, global variable or non-integer constant " - "'%.200s' must be fetched from its original 'lib' " - "object", name); - return NULL; - } - } - - if (ffi->types_builder.included_ffis != NULL) { - Py_ssize_t i; - PyObject *included_ffis = ffi->types_builder.included_ffis; - - if (recursion > 100) { - PyErr_SetString(PyExc_RuntimeError, - "recursion overflow in ffi.include() delegations"); - return NULL; - } - - for (i = 0; i < PyTuple_GET_SIZE(included_ffis); i++) { - FFIObject *ffi1; - PyObject *x; - - ffi1 = (FFIObject *)PyTuple_GET_ITEM(included_ffis, i); - x = ffi_fetch_int_constant(ffi1, name, recursion + 1); - if (x != NULL || PyErr_Occurred()) - return x; - } - } - return NULL; /* no exception set, means "not found" */ -} - -#define ACCEPT_STRING 1 -#define ACCEPT_CTYPE 2 -#define ACCEPT_CDATA 4 -#define ACCEPT_ALL (ACCEPT_STRING | ACCEPT_CTYPE | ACCEPT_CDATA) -#define CONSIDER_FN_AS_FNPTR 8 - -static CTypeDescrObject *_ffi_bad_type(FFIObject *ffi, const char *input_text) -{ - size_t length = strlen(input_text); - char *extra; - - if (length > 500) { - extra = ""; - } - else { - char *p; - size_t i, num_spaces = ffi->info.error_location; - extra = alloca(length + num_spaces + 4); - p = extra; - *p++ = '\n'; - for (i = 0; i < length; i++) { - if (' ' <= input_text[i] && input_text[i] < 0x7f) - *p++ = input_text[i]; - else if (input_text[i] == '\t' || input_text[i] == '\n') - *p++ = ' '; - else - *p++ = '?'; - } - *p++ = '\n'; - memset(p, ' ', num_spaces); - p += num_spaces; - *p++ = '^'; - *p++ = 0; - } - PyErr_Format(FFIError, "%s%s", ffi->info.error_message, extra); - return NULL; -} - -static CTypeDescrObject *_ffi_type(FFIObject *ffi, PyObject *arg, - int accept) -{ - /* Returns the CTypeDescrObject from the user-supplied 'arg'. - Does not return a new reference! - */ - if ((accept & ACCEPT_STRING) && PyText_Check(arg)) { - PyObject *types_dict = ffi->types_builder.types_dict; - PyObject *x = PyDict_GetItem(types_dict, arg); - - if (x == NULL) { - const char *input_text = PyText_AS_UTF8(arg); - int err, index = parse_c_type(&ffi->info, input_text); - if (index < 0) - return _ffi_bad_type(ffi, input_text); - - x = realize_c_type_or_func(&ffi->types_builder, - ffi->info.output, index); - if (x == NULL) - return NULL; - - /* Cache under the name given by 'arg', in addition to the - fact that the same ct is probably already cached under - its standardized name. In a few cases, it is not, e.g. - if it is a primitive; for the purpose of this function, - the important point is the following line, which makes - sure that in any case the next _ffi_type() with the same - 'arg' will succeed early, in PyDict_GetItem() above. - */ - err = PyDict_SetItem(types_dict, arg, x); - Py_DECREF(x); /* we know it was written in types_dict (unless out - of mem), so there is at least that ref left */ - if (err < 0) - return NULL; - } - - if (CTypeDescr_Check(x)) - return (CTypeDescrObject *)x; - else if (accept & CONSIDER_FN_AS_FNPTR) - return unwrap_fn_as_fnptr(x); - else - return unexpected_fn_type(x); - } - else if ((accept & ACCEPT_CTYPE) && CTypeDescr_Check(arg)) { - return (CTypeDescrObject *)arg; - } - else if ((accept & ACCEPT_CDATA) && CData_Check(arg)) { - return ((CDataObject *)arg)->c_type; - } -#if PY_MAJOR_VERSION < 3 - else if (PyUnicode_Check(arg)) { - CTypeDescrObject *result; - arg = PyUnicode_AsASCIIString(arg); - if (arg == NULL) - return NULL; - result = _ffi_type(ffi, arg, accept); - Py_DECREF(arg); - return result; - } -#endif - else { - const char *m1 = (accept & ACCEPT_STRING) ? "string" : ""; - const char *m2 = (accept & ACCEPT_CTYPE) ? "ctype object" : ""; - const char *m3 = (accept & ACCEPT_CDATA) ? "cdata object" : ""; - const char *s12 = (*m1 && (*m2 || *m3)) ? " or " : ""; - const char *s23 = (*m2 && *m3) ? " or " : ""; - PyErr_Format(PyExc_TypeError, "expected a %s%s%s%s%s, got '%.200s'", - m1, s12, m2, s23, m3, - Py_TYPE(arg)->tp_name); - return NULL; - } -} - -PyDoc_STRVAR(ffi_sizeof_doc, -"Return the size in bytes of the argument.\n" -"It can be a string naming a C type, or a 'cdata' instance."); - -static PyObject *ffi_sizeof(FFIObject *self, PyObject *arg) -{ - Py_ssize_t size; - - if (CData_Check(arg)) { - size = direct_sizeof_cdata((CDataObject *)arg); - } - else { - CTypeDescrObject *ct = _ffi_type(self, arg, ACCEPT_ALL); - if (ct == NULL) - return NULL; - size = ct->ct_size; - if (size < 0) { - PyErr_Format(FFIError, "don't know the size of ctype '%s'", - ct->ct_name); - return NULL; - } - } - return PyInt_FromSsize_t(size); -} - -PyDoc_STRVAR(ffi_alignof_doc, -"Return the natural alignment size in bytes of the argument.\n" -"It can be a string naming a C type, or a 'cdata' instance."); - -static PyObject *ffi_alignof(FFIObject *self, PyObject *arg) -{ - int align; - CTypeDescrObject *ct = _ffi_type(self, arg, ACCEPT_ALL); - if (ct == NULL) - return NULL; - - align = get_alignment(ct); - if (align < 0) - return NULL; - return PyInt_FromLong(align); -} - -PyDoc_STRVAR(ffi_typeof_doc, -"Parse the C type given as a string and return the\n" -"corresponding <ctype> object.\n" -"It can also be used on 'cdata' instance to get its C type."); - -static PyObject *_cpyextfunc_type_index(PyObject *x); /* forward */ - -static PyObject *ffi_typeof(FFIObject *self, PyObject *arg) -{ - PyObject *x = (PyObject *)_ffi_type(self, arg, ACCEPT_STRING|ACCEPT_CDATA); - if (x != NULL) { - Py_INCREF(x); - } - else { - x = _cpyextfunc_type_index(arg); - } - return x; -} - -PyDoc_STRVAR(ffi_new_doc, -"Allocate an instance according to the specified C type and return a\n" -"pointer to it. The specified C type must be either a pointer or an\n" -"array: ``new('X *')`` allocates an X and returns a pointer to it,\n" -"whereas ``new('X[n]')`` allocates an array of n X'es and returns an\n" -"array referencing it (which works mostly like a pointer, like in C).\n" -"You can also use ``new('X[]', n)`` to allocate an array of a\n" -"non-constant length n.\n" -"\n" -"The memory is initialized following the rules of declaring a global\n" -"variable in C: by default it is zero-initialized, but an explicit\n" -"initializer can be given which can be used to fill all or part of the\n" -"memory.\n" -"\n" -"When the returned <cdata> object goes out of scope, the memory is\n" -"freed. In other words the returned <cdata> object has ownership of\n" -"the value of type 'cdecl' that it points to. This means that the raw\n" -"data can be used as long as this object is kept alive, but must not be\n" -"used for a longer time. Be careful about that when copying the\n" -"pointer to the memory somewhere else, e.g. into another structure."); - -static PyObject *_ffi_new(FFIObject *self, PyObject *args, PyObject *kwds, - const cffi_allocator_t *allocator) -{ - CTypeDescrObject *ct; - PyObject *arg, *init = Py_None; - static char *keywords[] = {"cdecl", "init", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:new", keywords, - &arg, &init)) - return NULL; - - ct = _ffi_type(self, arg, ACCEPT_STRING|ACCEPT_CTYPE); - if (ct == NULL) - return NULL; - - return direct_newp(ct, init, allocator); -} - -static PyObject *ffi_new(FFIObject *self, PyObject *args, PyObject *kwds) -{ - return _ffi_new(self, args, kwds, &default_allocator); -} - -static PyObject *_ffi_new_with_allocator(PyObject *allocator, PyObject *args, - PyObject *kwds) -{ - cffi_allocator_t alloc1; - PyObject *my_alloc, *my_free; - my_alloc = PyTuple_GET_ITEM(allocator, 1); - my_free = PyTuple_GET_ITEM(allocator, 2); - alloc1.ca_alloc = (my_alloc == Py_None ? NULL : my_alloc); - alloc1.ca_free = (my_free == Py_None ? NULL : my_free); - alloc1.ca_dont_clear = (PyTuple_GET_ITEM(allocator, 3) == Py_False); - - return _ffi_new((FFIObject *)PyTuple_GET_ITEM(allocator, 0), - args, kwds, &alloc1); -} - -PyDoc_STRVAR(ffi_new_allocator_doc, -"Return a new allocator, i.e. a function that behaves like ffi.new()\n" -"but uses the provided low-level 'alloc' and 'free' functions.\n" -"\n" -"'alloc' is called with the size as argument. If it returns NULL, a\n" -"MemoryError is raised. 'free' is called with the result of 'alloc'\n" -"as argument. Both can be either Python functions or directly C\n" -"functions. If 'free' is None, then no free function is called.\n" -"If both 'alloc' and 'free' are None, the default is used.\n" -"\n" -"If 'should_clear_after_alloc' is set to False, then the memory\n" -"returned by 'alloc' is assumed to be already cleared (or you are\n" -"fine with garbage); otherwise CFFI will clear it."); - -static PyObject *ffi_new_allocator(FFIObject *self, PyObject *args, - PyObject *kwds) -{ - PyObject *allocator, *result; - PyObject *my_alloc = Py_None, *my_free = Py_None; - int should_clear_after_alloc = 1; - static char *keywords[] = {"alloc", "free", "should_clear_after_alloc", - NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOi:new_allocator", keywords, - &my_alloc, &my_free, - &should_clear_after_alloc)) - return NULL; - - if (my_alloc == Py_None && my_free != Py_None) { - PyErr_SetString(PyExc_TypeError, "cannot pass 'free' without 'alloc'"); - return NULL; - } - - allocator = PyTuple_Pack(4, - (PyObject *)self, - my_alloc, - my_free, - PyBool_FromLong(should_clear_after_alloc)); - if (allocator == NULL) - return NULL; - - { - static PyMethodDef md = {"allocator", - (PyCFunction)_ffi_new_with_allocator, - METH_VARARGS | METH_KEYWORDS}; - result = PyCFunction_New(&md, allocator); - } - Py_DECREF(allocator); - return result; -} - -PyDoc_STRVAR(ffi_cast_doc, -"Similar to a C cast: returns an instance of the named C\n" -"type initialized with the given 'source'. The source is\n" -"casted between integers or pointers of any type."); - -static PyObject *ffi_cast(FFIObject *self, PyObject *args) -{ - CTypeDescrObject *ct; - PyObject *ob, *arg; - if (!PyArg_ParseTuple(args, "OO:cast", &arg, &ob)) - return NULL; - - ct = _ffi_type(self, arg, ACCEPT_STRING|ACCEPT_CTYPE); - if (ct == NULL) - return NULL; - - return do_cast(ct, ob); -} - -PyDoc_STRVAR(ffi_string_doc, -"Return a Python string (or unicode string) from the 'cdata'. If\n" -"'cdata' is a pointer or array of characters or bytes, returns the\n" -"null-terminated string. The returned string extends until the first\n" -"null character, or at most 'maxlen' characters. If 'cdata' is an\n" -"array then 'maxlen' defaults to its length.\n" -"\n" -"If 'cdata' is a pointer or array of wchar_t, returns a unicode string\n" -"following the same rules.\n" -"\n" -"If 'cdata' is a single character or byte or a wchar_t, returns it as a\n" -"string or unicode string.\n" -"\n" -"If 'cdata' is an enum, returns the value of the enumerator as a\n" -"string, or 'NUMBER' if the value is out of range."); - -#define ffi_string b_string /* ffi_string() => b_string() - from _cffi_backend.c */ - -PyDoc_STRVAR(ffi_unpack_doc, -"Unpack an array of C data of the given length,\n" -"returning a Python string/unicode/list.\n" -"\n" -"If 'cdata' is a pointer to 'char', returns a byte string.\n" -"It does not stop at the first null. This is equivalent to:\n" -"ffi.buffer(cdata, length)[:]\n" -"\n" -"If 'cdata' is a pointer to 'wchar_t', returns a unicode string.\n" -"'length' is measured in wchar_t's; it is not the size in bytes.\n" -"\n" -"If 'cdata' is a pointer to anything else, returns a list of\n" -"'length' items. This is a faster equivalent to:\n" -"[cdata[i] for i in range(length)]"); - -#define ffi_unpack b_unpack /* ffi_unpack() => b_unpack() - from _cffi_backend.c */ - - -PyDoc_STRVAR(ffi_offsetof_doc, -"Return the offset of the named field inside the given structure or\n" -"array, which must be given as a C type name. You can give several\n" -"field names in case of nested structures. You can also give numeric\n" -"values which correspond to array items, in case of an array type."); - -static PyObject *ffi_offsetof(FFIObject *self, PyObject *args) -{ - PyObject *arg; - CTypeDescrObject *ct; - Py_ssize_t i, offset; - - if (PyTuple_Size(args) < 2) { - PyErr_SetString(PyExc_TypeError, - "offsetof() expects at least 2 arguments"); - return NULL; - } - - arg = PyTuple_GET_ITEM(args, 0); - ct = _ffi_type(self, arg, ACCEPT_STRING|ACCEPT_CTYPE); - if (ct == NULL) - return NULL; - - offset = 0; - for (i = 1; i < PyTuple_GET_SIZE(args); i++) { - Py_ssize_t ofs1; - ct = direct_typeoffsetof(ct, PyTuple_GET_ITEM(args, i), i > 1, &ofs1); - if (ct == NULL) - return NULL; - offset += ofs1; - } - return PyInt_FromSsize_t(offset); -} - -PyDoc_STRVAR(ffi_addressof_doc, -"Limited equivalent to the '&' operator in C:\n" -"\n" -"1. ffi.addressof(<cdata 'struct-or-union'>) returns a cdata that is a\n" -"pointer to this struct or union.\n" -"\n" -"2. ffi.addressof(<cdata>, field-or-index...) returns the address of a\n" -"field or array item inside the given structure or array, recursively\n" -"in case of nested structures or arrays.\n" -"\n" -"3. ffi.addressof(<library>, \"name\") returns the address of the named\n" -"function or global variable."); - -static PyObject *address_of_global_var(PyObject *args); /* forward */ - -static PyObject *ffi_addressof(FFIObject *self, PyObject *args) -{ - PyObject *arg, *z, *result; - CTypeDescrObject *ct; - Py_ssize_t i, offset = 0; - int accepted_flags; - - if (PyTuple_Size(args) < 1) { - PyErr_SetString(PyExc_TypeError, - "addressof() expects at least 1 argument"); - return NULL; - } - - arg = PyTuple_GET_ITEM(args, 0); - if (LibObject_Check(arg)) { - /* case 3 in the docstring */ - return address_of_global_var(args); - } - - ct = _ffi_type(self, arg, ACCEPT_CDATA); - if (ct == NULL) - return NULL; - - if (PyTuple_GET_SIZE(args) == 1) { - /* case 1 in the docstring */ - accepted_flags = CT_STRUCT | CT_UNION | CT_ARRAY; - if ((ct->ct_flags & accepted_flags) == 0) { - PyErr_SetString(PyExc_TypeError, - "expected a cdata struct/union/array object"); - return NULL; - } - } - else { - /* case 2 in the docstring */ - accepted_flags = CT_STRUCT | CT_UNION | CT_ARRAY | CT_POINTER; - if ((ct->ct_flags & accepted_flags) == 0) { - PyErr_SetString(PyExc_TypeError, - "expected a cdata struct/union/array/pointer object"); - return NULL; - } - for (i = 1; i < PyTuple_GET_SIZE(args); i++) { - Py_ssize_t ofs1; - ct = direct_typeoffsetof(ct, PyTuple_GET_ITEM(args, i), - i > 1, &ofs1); - if (ct == NULL) - return NULL; - offset += ofs1; - } - } - - z = new_pointer_type(ct); - if (z == NULL) - return NULL; - - result = new_simple_cdata(((CDataObject *)arg)->c_data + offset, - (CTypeDescrObject *)z); - Py_DECREF(z); - return result; -} - -static PyObject *_combine_type_name_l(CTypeDescrObject *ct, - size_t extra_text_len) -{ - size_t base_name_len; - PyObject *result; - char *p; - - base_name_len = strlen(ct->ct_name); - result = PyBytes_FromStringAndSize(NULL, base_name_len + extra_text_len); - if (result == NULL) - return NULL; - - p = PyBytes_AS_STRING(result); - memcpy(p, ct->ct_name, ct->ct_name_position); - p += ct->ct_name_position; - p += extra_text_len; - memcpy(p, ct->ct_name + ct->ct_name_position, - base_name_len - ct->ct_name_position); - return result; -} - -PyDoc_STRVAR(ffi_getctype_doc, -"Return a string giving the C type 'cdecl', which may be itself a\n" -"string or a <ctype> object. If 'replace_with' is given, it gives\n" -"extra text to append (or insert for more complicated C types), like a\n" -"variable name, or '*' to get actually the C type 'pointer-to-cdecl'."); - -static PyObject *ffi_getctype(FFIObject *self, PyObject *args, PyObject *kwds) -{ - PyObject *c_decl, *res; - char *p, *replace_with = ""; - int add_paren, add_space; - CTypeDescrObject *ct; - size_t replace_with_len; - static char *keywords[] = {"cdecl", "replace_with", NULL}; -#if PY_MAJOR_VERSION >= 3 - PyObject *u; -#endif - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|s:getctype", keywords, - &c_decl, &replace_with)) - return NULL; - - ct = _ffi_type(self, c_decl, ACCEPT_STRING|ACCEPT_CTYPE); - if (ct == NULL) - return NULL; - - while (replace_with[0] != 0 && isspace(replace_with[0])) - replace_with++; - replace_with_len = strlen(replace_with); - while (replace_with_len > 0 && isspace(replace_with[replace_with_len - 1])) - replace_with_len--; - - add_paren = (replace_with[0] == '*' && - ((ct->ct_flags & CT_ARRAY) != 0)); - add_space = (!add_paren && replace_with_len > 0 && - replace_with[0] != '[' && replace_with[0] != '('); - - res = _combine_type_name_l(ct, replace_with_len + add_space + 2*add_paren); - if (res == NULL) - return NULL; - - p = PyBytes_AS_STRING(res) + ct->ct_name_position; - if (add_paren) - *p++ = '('; - if (add_space) - *p++ = ' '; - memcpy(p, replace_with, replace_with_len); - if (add_paren) - p[replace_with_len] = ')'; - -#if PY_MAJOR_VERSION >= 3 - /* bytes -> unicode string */ - u = PyUnicode_DecodeLatin1(PyBytes_AS_STRING(res), - PyBytes_GET_SIZE(res), - NULL); - Py_DECREF(res); - res = u; -#endif - - return res; -} - -PyDoc_STRVAR(ffi_new_handle_doc, -"Return a non-NULL cdata of type 'void *' that contains an opaque\n" -"reference to the argument, which can be any Python object. To cast it\n" -"back to the original object, use from_handle(). You must keep alive\n" -"the cdata object returned by new_handle()!"); - -static PyObject *ffi_new_handle(FFIObject *self, PyObject *arg) -{ - /* g_ct_voidp is equal to <ctype 'void *'> */ - return newp_handle(g_ct_voidp, arg); -} - -PyDoc_STRVAR(ffi_from_handle_doc, -"Cast a 'void *' back to a Python object. Must be used *only* on the\n" -"pointers returned by new_handle(), and *only* as long as the exact\n" -"cdata object returned by new_handle() is still alive (somewhere else\n" -"in the program). Failure to follow these rules will crash."); - -#define ffi_from_handle b_from_handle /* ffi_from_handle => b_from_handle - from _cffi_backend.c */ - -PyDoc_STRVAR(ffi_from_buffer_doc, -"Return a <cdata 'char[]'> that points to the data of the given Python\n" -"object, which must support the buffer interface. Note that this is\n" -"not meant to be used on the built-in types str or unicode\n" -"(you can build 'char[]' arrays explicitly) but only on objects\n" -"containing large quantities of raw data in some other format, like\n" -"'array.array' or numpy arrays."); - -static PyObject *ffi_from_buffer(FFIObject *self, PyObject *args, - PyObject *kwds) -{ - PyObject *cdecl1, *python_buf = NULL; - CTypeDescrObject *ct; - int require_writable = 0; - static char *keywords[] = {"cdecl", "python_buffer", - "require_writable", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|Oi:from_buffer", keywords, - &cdecl1, &python_buf, &require_writable)) - return NULL; - - if (python_buf == NULL) { - python_buf = cdecl1; - ct = g_ct_chararray; - } - else { - ct = _ffi_type(self, cdecl1, ACCEPT_STRING|ACCEPT_CTYPE); - if (ct == NULL) - return NULL; - } - return direct_from_buffer(ct, python_buf, require_writable); -} - -PyDoc_STRVAR(ffi_gc_doc, -"Return a new cdata object that points to the same data.\n" -"Later, when this new cdata object is garbage-collected,\n" -"'destructor(old_cdata_object)' will be called.\n" -"\n" -"The optional 'size' gives an estimate of the size, used to\n" -"trigger the garbage collection more eagerly. So far only used\n" -"on PyPy. It tells the GC that the returned object keeps alive\n" -"roughly 'size' bytes of external memory."); - -#define ffi_gc b_gcp /* ffi_gc() => b_gcp() - from _cffi_backend.c */ - -PyDoc_STRVAR(ffi_def_extern_doc, -"A decorator. Attaches the decorated Python function to the C code\n" -"generated for the 'extern \"Python\"' function of the same name.\n" -"Calling the C function will then invoke the Python function.\n" -"\n" -"Optional arguments: 'name' is the name of the C function, if\n" -"different from the Python function; and 'error' and 'onerror'\n" -"handle what occurs if the Python function raises an exception\n" -"(see the docs for details)."); - -/* forward; see call_python.c */ -static PyObject *_ffi_def_extern_decorator(PyObject *, PyObject *); - -static PyObject *ffi_def_extern(FFIObject *self, PyObject *args, - PyObject *kwds) -{ - static PyMethodDef md = {"def_extern_decorator", - (PyCFunction)_ffi_def_extern_decorator, METH_O}; - PyObject *name = Py_None, *error = Py_None; - PyObject *res, *onerror = Py_None; - static char *keywords[] = {"name", "error", "onerror", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOO", keywords, - &name, &error, &onerror)) - return NULL; - - args = Py_BuildValue("(OOOO)", (PyObject *)self, name, error, onerror); - if (args == NULL) - return NULL; - - res = PyCFunction_New(&md, args); - Py_DECREF(args); - return res; -} - -PyDoc_STRVAR(ffi_callback_doc, -"Return a callback object or a decorator making such a callback object.\n" -"'cdecl' must name a C function pointer type. The callback invokes the\n" -"specified 'python_callable' (which may be provided either directly or\n" -"via a decorator). Important: the callback object must be manually\n" -"kept alive for as long as the callback may be invoked from the C code."); - -static PyObject *_ffi_callback_decorator(PyObject *outer_args, PyObject *fn) -{ - PyObject *res, *old; - - old = PyTuple_GET_ITEM(outer_args, 1); - PyTuple_SET_ITEM(outer_args, 1, fn); - res = b_callback(NULL, outer_args); - PyTuple_SET_ITEM(outer_args, 1, old); - return res; -} - -static PyObject *ffi_callback(FFIObject *self, PyObject *args, PyObject *kwds) -{ - PyObject *c_decl, *python_callable = Py_None, *error = Py_None; - PyObject *res, *onerror = Py_None; - static char *keywords[] = {"cdecl", "python_callable", "error", - "onerror", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|OOO", keywords, - &c_decl, &python_callable, &error, - &onerror)) - return NULL; - - c_decl = (PyObject *)_ffi_type(self, c_decl, ACCEPT_STRING | ACCEPT_CTYPE | - CONSIDER_FN_AS_FNPTR); - if (c_decl == NULL) - return NULL; - - args = Py_BuildValue("(OOOO)", c_decl, python_callable, error, onerror); - if (args == NULL) - return NULL; - - if (python_callable != Py_None) { - res = b_callback(NULL, args); - } - else { - static PyMethodDef md = {"callback_decorator", - (PyCFunction)_ffi_callback_decorator, METH_O}; - res = PyCFunction_New(&md, args); - } - Py_DECREF(args); - return res; -} - -#ifdef MS_WIN32 -PyDoc_STRVAR(ffi_getwinerror_doc, -"Return either the GetLastError() or the error number given by the\n" -"optional 'code' argument, as a tuple '(code, message)'."); - -#define ffi_getwinerror b_getwinerror /* ffi_getwinerror() => b_getwinerror() - from misc_win32.h */ -#endif - -PyDoc_STRVAR(ffi_errno_doc, "the value of 'errno' from/to the C calls"); - -static PyObject *ffi_get_errno(PyObject *self, void *closure) -{ - /* xxx maybe think about how to make the saved errno local - to an ffi instance */ - return b_get_errno(NULL, NULL); -} - -static int ffi_set_errno(PyObject *self, PyObject *newval, void *closure) -{ - PyObject *x = b_set_errno(NULL, newval); - if (x == NULL) - return -1; - Py_DECREF(x); - return 0; -} - -PyDoc_STRVAR(ffi_dlopen_doc, -"Load and return a dynamic library identified by 'name'. The standard\n" -"C library can be loaded by passing None.\n" -"\n" -"Note that functions and types declared with 'ffi.cdef()' are not\n" -"linked to a particular library, just like C headers. In the library\n" -"we only look for the actual (untyped) symbols at the time of their\n" -"first access."); - -PyDoc_STRVAR(ffi_dlclose_doc, -"Close a library obtained with ffi.dlopen(). After this call, access to\n" -"functions or variables from the library will fail (possibly with a\n" -"segmentation fault)."); - -static PyObject *ffi_dlopen(PyObject *self, PyObject *args); /* forward */ -static PyObject *ffi_dlclose(PyObject *self, PyObject *args); /* forward */ - -PyDoc_STRVAR(ffi_int_const_doc, -"Get the value of an integer constant.\n" -"\n" -"'ffi.integer_const(\"xxx\")' is equivalent to 'lib.xxx' if xxx names an\n" -"integer constant. The point of this function is limited to use cases\n" -"where you have an 'ffi' object but not any associated 'lib' object."); - -static PyObject *ffi_int_const(FFIObject *self, PyObject *args, PyObject *kwds) -{ - char *name; - PyObject *x; - static char *keywords[] = {"name", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", keywords, &name)) - return NULL; - - x = ffi_fetch_int_constant(self, name, 0); - - if (x == NULL && !PyErr_Occurred()) { - PyErr_Format(PyExc_AttributeError, - "integer constant '%.200s' not found", name); - } - return x; -} - -PyDoc_STRVAR(ffi_list_types_doc, -"Returns the user type names known to this FFI instance.\n" -"This returns a tuple containing three lists of names:\n" -"(typedef_names, names_of_structs, names_of_unions)"); - -static PyObject *ffi_list_types(FFIObject *self, PyObject *noargs) -{ - Py_ssize_t i, n1 = self->types_builder.ctx.num_typenames; - Py_ssize_t n23 = self->types_builder.ctx.num_struct_unions; - PyObject *o, *lst[3] = {NULL, NULL, NULL}, *result = NULL; - - lst[0] = PyList_New(n1); - if (lst[0] == NULL) - goto error; - lst[1] = PyList_New(0); - if (lst[1] == NULL) - goto error; - lst[2] = PyList_New(0); - if (lst[2] == NULL) - goto error; - - for (i = 0; i < n1; i++) { - o = PyText_FromString(self->types_builder.ctx.typenames[i].name); - if (o == NULL) - goto error; - PyList_SET_ITEM(lst[0], i, o); - } - - for (i = 0; i < n23; i++) { - const struct _cffi_struct_union_s *s; - int err, index; - - s = &self->types_builder.ctx.struct_unions[i]; - if (s->name[0] == '$') - continue; - - o = PyText_FromString(s->name); - if (o == NULL) - goto error; - index = (s->flags & _CFFI_F_UNION) ? 2 : 1; - err = PyList_Append(lst[index], o); - Py_DECREF(o); - if (err < 0) - goto error; - } - result = PyTuple_Pack(3, lst[0], lst[1], lst[2]); - /* fall-through */ - error: - Py_XDECREF(lst[2]); - Py_XDECREF(lst[1]); - Py_XDECREF(lst[0]); - return result; -} - -PyDoc_STRVAR(ffi_memmove_doc, -"ffi.memmove(dest, src, n) copies n bytes of memory from src to dest.\n" -"\n" -"Like the C function memmove(), the memory areas may overlap;\n" -"apart from that it behaves like the C function memcpy().\n" -"\n" -"'src' can be any cdata ptr or array, or any Python buffer object.\n" -"'dest' can be any cdata ptr or array, or a writable Python buffer\n" -"object. The size to copy, 'n', is always measured in bytes.\n" -"\n" -"Unlike other methods, this one supports all Python buffer including\n" -"byte strings and bytearrays---but it still does not support\n" -"non-contiguous buffers."); - -#define ffi_memmove b_memmove /* ffi_memmove() => b_memmove() - from _cffi_backend.c */ - -PyDoc_STRVAR(ffi_init_once_doc, -"init_once(function, tag): run function() once. More precisely,\n" -"'function()' is called the first time we see a given 'tag'.\n" -"\n" -"The return value of function() is remembered and returned by the current\n" -"and all future init_once() with the same tag. If init_once() is called\n" -"from multiple threads in parallel, all calls block until the execution\n" -"of function() is done. If function() raises an exception, it is\n" -"propagated and nothing is cached."); - -#if PY_MAJOR_VERSION < 3 -/* PyCapsule_New is redefined to be PyCObject_FromVoidPtr in _cffi_backend, - which gives 2.6 compatibility; but the destructor signature is different */ -static void _free_init_once_lock(void *lock) -{ - PyThread_free_lock((PyThread_type_lock)lock); -} -#else -static void _free_init_once_lock(PyObject *capsule) -{ - PyThread_type_lock lock; - lock = PyCapsule_GetPointer(capsule, "cffi_init_once_lock"); - if (lock != NULL) - PyThread_free_lock(lock); -} -#endif - -static PyObject *ffi_init_once(FFIObject *self, PyObject *args, PyObject *kwds) -{ - static char *keywords[] = {"func", "tag", NULL}; - PyObject *cache, *func, *tag, *tup, *res, *x, *lockobj; - PyThread_type_lock lock; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO", keywords, &func, &tag)) - return NULL; - - /* a lot of fun with reference counting and error checking - in this function */ - - /* atomically get or create a new dict (no GIL release) */ - cache = self->init_once_cache; - if (cache == NULL) { - cache = PyDict_New(); - if (cache == NULL) - return NULL; - self->init_once_cache = cache; - } - - /* get the tuple from cache[tag], or make a new one: (False, lock) */ - tup = PyDict_GetItem(cache, tag); - if (tup == NULL) { - lock = PyThread_allocate_lock(); - if (lock == NULL) - return NULL; - x = PyCapsule_New(lock, "cffi_init_once_lock", _free_init_once_lock); - if (x == NULL) { - PyThread_free_lock(lock); - return NULL; - } - tup = PyTuple_Pack(2, Py_False, x); - Py_DECREF(x); - if (tup == NULL) - return NULL; - x = tup; - - /* Possible corner case if 'tag' is an object overriding __eq__ - in pure Python: the GIL may be released when we are running it. - We really need to call dict.setdefault(). */ - tup = PyObject_CallMethod(cache, "setdefault", "OO", tag, x); - Py_DECREF(x); - if (tup == NULL) - return NULL; - - Py_DECREF(tup); /* there is still a ref inside the dict */ - } - - res = PyTuple_GET_ITEM(tup, 1); - Py_INCREF(res); - - if (PyTuple_GET_ITEM(tup, 0) == Py_True) { - /* tup == (True, result): return the result. */ - return res; - } - - /* tup == (False, lock) */ - lockobj = res; - lock = (PyThread_type_lock)PyCapsule_GetPointer(lockobj, - "cffi_init_once_lock"); - if (lock == NULL) { - Py_DECREF(lockobj); - return NULL; - } - - Py_BEGIN_ALLOW_THREADS - PyThread_acquire_lock(lock, WAIT_LOCK); - Py_END_ALLOW_THREADS - - x = PyDict_GetItem(cache, tag); - if (x != NULL && PyTuple_GET_ITEM(x, 0) == Py_True) { - /* the real result was put in the dict while we were waiting - for PyThread_acquire_lock() above */ - res = PyTuple_GET_ITEM(x, 1); - Py_INCREF(res); - } - else { - res = PyObject_CallFunction(func, ""); - if (res != NULL) { - tup = PyTuple_Pack(2, Py_True, res); - if (tup == NULL || PyDict_SetItem(cache, tag, tup) < 0) { - Py_DECREF(res); - res = NULL; - } - Py_XDECREF(tup); - } - } - - PyThread_release_lock(lock); - Py_DECREF(lockobj); - return res; -} - -PyDoc_STRVAR(ffi_release_doc, -"Release now the resources held by a 'cdata' object from ffi.new(),\n" -"ffi.gc() or ffi.from_buffer(). The cdata object must not be used\n" -"afterwards.\n" -"\n" -"'ffi.release(cdata)' is equivalent to 'cdata.__exit__()'.\n" -"\n" -"Note that on CPython this method has no effect (so far) on objects\n" -"returned by ffi.new(), because the memory is allocated inline with the\n" -"cdata object and cannot be freed independently. It might be fixed in\n" -"future releases of cffi."); - -#define ffi_release b_release /* ffi_release() => b_release() - from _cffi_backend.c */ - - -#define METH_VKW (METH_VARARGS | METH_KEYWORDS) -static PyMethodDef ffi_methods[] = { - {"addressof", (PyCFunction)ffi_addressof, METH_VARARGS, ffi_addressof_doc}, - {"alignof", (PyCFunction)ffi_alignof, METH_O, ffi_alignof_doc}, - {"def_extern", (PyCFunction)ffi_def_extern, METH_VKW, ffi_def_extern_doc}, - {"callback", (PyCFunction)ffi_callback, METH_VKW, ffi_callback_doc}, - {"cast", (PyCFunction)ffi_cast, METH_VARARGS, ffi_cast_doc}, - {"dlclose", (PyCFunction)ffi_dlclose, METH_VARARGS, ffi_dlclose_doc}, - {"dlopen", (PyCFunction)ffi_dlopen, METH_VARARGS, ffi_dlopen_doc}, - {"from_buffer",(PyCFunction)ffi_from_buffer,METH_VKW, ffi_from_buffer_doc}, - {"from_handle",(PyCFunction)ffi_from_handle,METH_O, ffi_from_handle_doc}, - {"gc", (PyCFunction)ffi_gc, METH_VKW, ffi_gc_doc}, - {"getctype", (PyCFunction)ffi_getctype, METH_VKW, ffi_getctype_doc}, -#ifdef MS_WIN32 - {"getwinerror",(PyCFunction)ffi_getwinerror,METH_VKW, ffi_getwinerror_doc}, -#endif - {"init_once", (PyCFunction)ffi_init_once, METH_VKW, ffi_init_once_doc}, - {"integer_const",(PyCFunction)ffi_int_const,METH_VKW, ffi_int_const_doc}, - {"list_types", (PyCFunction)ffi_list_types, METH_NOARGS, ffi_list_types_doc}, - {"memmove", (PyCFunction)ffi_memmove, METH_VKW, ffi_memmove_doc}, - {"new", (PyCFunction)ffi_new, METH_VKW, ffi_new_doc}, -{"new_allocator",(PyCFunction)ffi_new_allocator,METH_VKW,ffi_new_allocator_doc}, - {"new_handle", (PyCFunction)ffi_new_handle, METH_O, ffi_new_handle_doc}, - {"offsetof", (PyCFunction)ffi_offsetof, METH_VARARGS, ffi_offsetof_doc}, - {"release", (PyCFunction)ffi_release, METH_O, ffi_release_doc}, - {"sizeof", (PyCFunction)ffi_sizeof, METH_O, ffi_sizeof_doc}, - {"string", (PyCFunction)ffi_string, METH_VKW, ffi_string_doc}, - {"typeof", (PyCFunction)ffi_typeof, METH_O, ffi_typeof_doc}, - {"unpack", (PyCFunction)ffi_unpack, METH_VKW, ffi_unpack_doc}, - {NULL} -}; - -static PyGetSetDef ffi_getsets[] = { - {"errno", ffi_get_errno, ffi_set_errno, ffi_errno_doc}, - {NULL} -}; - -static PyTypeObject FFI_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_cffi_backend.FFI", - sizeof(FFIObject), - 0, - (destructor)ffi_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - 0, /* tp_doc */ - (traverseproc)ffi_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - ffi_methods, /* tp_methods */ - 0, /* tp_members */ - ffi_getsets, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - ffiobj_init, /* tp_init */ - 0, /* tp_alloc */ - ffiobj_new, /* tp_new */ - PyObject_GC_Del, /* tp_free */ -}; - - -static PyObject * -_fetch_external_struct_or_union(const struct _cffi_struct_union_s *s, - PyObject *included_ffis, int recursion) -{ - Py_ssize_t i; - - if (included_ffis == NULL) - return NULL; - - if (recursion > 100) { - PyErr_SetString(PyExc_RuntimeError, - "recursion overflow in ffi.include() delegations"); - return NULL; - } - - for (i = 0; i < PyTuple_GET_SIZE(included_ffis); i++) { - FFIObject *ffi1; - const struct _cffi_struct_union_s *s1; - int sindex; - PyObject *x; - - ffi1 = (FFIObject *)PyTuple_GET_ITEM(included_ffis, i); - sindex = search_in_struct_unions(&ffi1->types_builder.ctx, s->name, - strlen(s->name)); - if (sindex < 0) /* not found at all */ - continue; - s1 = &ffi1->types_builder.ctx.struct_unions[sindex]; - if ((s1->flags & (_CFFI_F_EXTERNAL | _CFFI_F_UNION)) - == (s->flags & _CFFI_F_UNION)) { - /* s1 is not external, and the same kind (struct or union) as s */ - return _realize_c_struct_or_union(&ffi1->types_builder, sindex); - } - /* not found, look more recursively */ - x = _fetch_external_struct_or_union( - s, ffi1->types_builder.included_ffis, recursion + 1); - if (x != NULL || PyErr_Occurred()) - return x; /* either found, or got an error */ - } - return NULL; /* not found at all, leave without an error */ -} diff --git a/c/file_emulator.h b/c/file_emulator.h deleted file mode 100644 index 82a34c0..0000000 --- a/c/file_emulator.h +++ /dev/null @@ -1,93 +0,0 @@ - -/* Emulation of PyFile_Check() and PyFile_AsFile() for Python 3. */ - -static PyObject *PyIOBase_TypeObj; - -static int init_file_emulator(void) -{ - if (PyIOBase_TypeObj == NULL) { - PyObject *io = PyImport_ImportModule("_io"); - if (io == NULL) - return -1; - PyIOBase_TypeObj = PyObject_GetAttrString(io, "_IOBase"); - if (PyIOBase_TypeObj == NULL) - return -1; - } - return 0; -} - - -#define PyFile_Check(p) PyObject_IsInstance(p, PyIOBase_TypeObj) - - -static void _close_file_capsule(PyObject *ob_capsule) -{ - FILE *f = (FILE *)PyCapsule_GetPointer(ob_capsule, "FILE"); - if (f != NULL) - fclose(f); -} - - -static FILE *PyFile_AsFile(PyObject *ob_file) -{ - PyObject *ob, *ob_capsule = NULL, *ob_mode = NULL; - FILE *f; - int fd; - const char *mode; - - ob = PyObject_CallMethod(ob_file, "flush", NULL); - if (ob == NULL) - goto fail; - Py_DECREF(ob); - - ob_capsule = PyObject_GetAttrString(ob_file, "__cffi_FILE"); - if (ob_capsule == NULL) { - PyErr_Clear(); - - fd = PyObject_AsFileDescriptor(ob_file); - if (fd < 0) - goto fail; - - ob_mode = PyObject_GetAttrString(ob_file, "mode"); - if (ob_mode == NULL) - goto fail; - mode = PyText_AsUTF8(ob_mode); - if (mode == NULL) - goto fail; - - fd = dup(fd); - if (fd < 0) { - PyErr_SetFromErrno(PyExc_OSError); - goto fail; - } - - f = fdopen(fd, mode); - if (f == NULL) { - close(fd); - PyErr_SetFromErrno(PyExc_OSError); - goto fail; - } - setbuf(f, NULL); /* non-buffered */ - Py_DECREF(ob_mode); - ob_mode = NULL; - - ob_capsule = PyCapsule_New(f, "FILE", _close_file_capsule); - if (ob_capsule == NULL) { - fclose(f); - goto fail; - } - - if (PyObject_SetAttrString(ob_file, "__cffi_FILE", ob_capsule) < 0) - goto fail; - } - else { - f = PyCapsule_GetPointer(ob_capsule, "FILE"); - } - Py_DECREF(ob_capsule); /* assumes still at least one reference */ - return f; - - fail: - Py_XDECREF(ob_mode); - Py_XDECREF(ob_capsule); - return NULL; -} diff --git a/c/lib_obj.c b/c/lib_obj.c deleted file mode 100644 index 38bf3d5..0000000 --- a/c/lib_obj.c +++ /dev/null @@ -1,716 +0,0 @@ - -/* A Lib object is what is in the "lib" attribute of a C extension - module originally created by recompile(). - - A Lib object is special in the sense that it has a custom - __getattr__ which returns C globals, functions and constants. The - original idea was to raise AttributeError for anything else, even - attrs like '__class__', but it breaks various things; now, standard - attrs are returned, but in the unlikely case where a user cdef()s - the same name, then the standard attr is hidden (and the various - things like introspection might break). - - A Lib object has got a reference to the _cffi_type_context_s - structure, which is used to create lazily the objects returned by - __getattr__. -*/ - -struct CPyExtFunc_s { - PyMethodDef md; - void *direct_fn; - int type_index; - char doc[1]; -}; - -struct LibObject_s { - PyObject_HEAD - builder_c_t *l_types_builder; /* same as the one on the ffi object */ - PyObject *l_dict; /* content, built lazily */ - 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) -{ - PyObject *y; - LibObject *lo; - PyCFunctionObject *fo; - - if (!PyCFunction_Check(x)) - return NULL; - y = PyCFunction_GET_SELF(x); - if (!LibObject_Check(y)) - return NULL; - - fo = (PyCFunctionObject *)x; - lo = (LibObject *)y; - if (lo->l_libname != fo->m_module) - return NULL; - - return (struct CPyExtFunc_s *)(fo->m_ml); -} - -static PyObject *_cpyextfunc_type(LibObject *lib, struct CPyExtFunc_s *exf) -{ - PyObject *tuple, *result; - tuple = realize_c_type_or_func(lib->l_types_builder, - lib->l_types_builder->ctx.types, - exf->type_index); - if (tuple == NULL) - return NULL; - - /* 'tuple' is a tuple of length 1 containing the real CT_FUNCTIONPTR - object */ - result = PyTuple_GetItem(tuple, 0); - Py_XINCREF(result); - Py_DECREF(tuple); - return result; -} - -static PyObject *_cpyextfunc_type_index(PyObject *x) -{ - struct CPyExtFunc_s *exf; - LibObject *lib; - - assert(PyErr_Occurred()); - exf = _cpyextfunc_get(x); - if (exf == NULL) - return NULL; /* still the same exception is set */ - - PyErr_Clear(); - - lib = (LibObject *)PyCFunction_GET_SELF(x); - return _cpyextfunc_type(lib, exf); -} - -static void cdlopen_close_ignore_errors(void *libhandle); /* forward */ -static void *cdlopen_fetch(PyObject *libname, void *libhandle, - const char *symbol); - -static void lib_dealloc(LibObject *lib) -{ - PyObject_GC_UnTrack(lib); - 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); - PyObject_GC_Del(lib); -} - -static int lib_traverse(LibObject *lib, visitproc visit, void *arg) -{ - Py_VISIT(lib->l_dict); - Py_VISIT(lib->l_libname); - Py_VISIT(lib->l_ffi); - return 0; -} - -static PyObject *lib_repr(LibObject *lib) -{ - return PyText_FromFormat("<Lib object for '%.200s'>", - PyText_AS_UTF8(lib->l_libname)); -} - -static PyObject *lib_build_cpython_func(LibObject *lib, - const struct _cffi_global_s *g, - const char *s, int flags) -{ - /* First make sure the argument types and return type are really - built. The C extension code can then assume that they are, - by calling _cffi_type(). - */ - PyObject *result = NULL; - CTypeDescrObject **pfargs = NULL; - CTypeDescrObject *fresult; - Py_ssize_t nargs = 0; - struct CPyExtFunc_s *xfunc; - int i, type_index = _CFFI_GETARG(g->type_op); - _cffi_opcode_t *opcodes = lib->l_types_builder->ctx.types; - static const char *const format = ";\n\nCFFI C function from %s.lib"; - const char *libname = PyText_AS_UTF8(lib->l_libname); - struct funcbuilder_s funcbuilder; - - /* return type: */ - fresult = realize_c_func_return_type(lib->l_types_builder, opcodes, - type_index); - if (fresult == NULL) - goto error; - - /* argument types: */ - /* note that if the arguments are already built, they have a - pointer in the 'opcodes' array, and GETOP() returns a - random even value. But OP_FUNCTION_END is odd, so the - condition below still works correctly. */ - i = type_index + 1; - while (_CFFI_GETOP(opcodes[i]) != _CFFI_OP_FUNCTION_END) - i++; - pfargs = alloca(sizeof(CTypeDescrObject *) * (i - type_index - 1)); - i = type_index + 1; - while (_CFFI_GETOP(opcodes[i]) != _CFFI_OP_FUNCTION_END) { - CTypeDescrObject *ct = realize_c_type(lib->l_types_builder, opcodes, i); - if (ct == NULL) - goto error; - pfargs[nargs++] = ct; - i++; - } - - memset(&funcbuilder, 0, sizeof(funcbuilder)); - if (fb_build_name(&funcbuilder, g->name, pfargs, nargs, fresult, 0) < 0) - goto error; - - /* The few bytes of memory we allocate here appear to leak, but - this is not a real leak. Indeed, CPython never unloads its C - extension modules. There is only one PyMem_Malloc() per real - C function in a CFFI C extension module. That means that this - PyMem_Malloc() could also have been written with a static - global variable generated for each CPYTHON_BLTN defined in the - C extension, and the effect would be the same (but a bit more - complicated). - */ - xfunc = PyMem_Malloc(sizeof(struct CPyExtFunc_s) + - funcbuilder.nb_bytes + - strlen(format) + strlen(libname)); - if (xfunc == NULL) { - PyErr_NoMemory(); - goto error; - } - memset((char *)xfunc, 0, sizeof(struct CPyExtFunc_s)); - assert(g->address); - xfunc->md.ml_meth = (PyCFunction)g->address; - xfunc->md.ml_flags = flags; - xfunc->md.ml_name = g->name; - xfunc->md.ml_doc = xfunc->doc; - xfunc->direct_fn = g->size_or_direct_fn; - xfunc->type_index = type_index; - - /* build the docstring */ - funcbuilder.bufferp = xfunc->doc; - if (fb_build_name(&funcbuilder, g->name, pfargs, nargs, fresult, 0) < 0) - goto error; - sprintf(funcbuilder.bufferp - 1, format, libname); - /* done building the docstring */ - - result = PyCFunction_NewEx(&xfunc->md, (PyObject *)lib, lib->l_libname); - /* fall-through */ - error: - Py_XDECREF(fresult); - while (nargs > 0) { - --nargs; - Py_DECREF(pfargs[nargs]); - } - return result; -} - -static PyObject *lib_build_and_cache_attr(LibObject *lib, PyObject *name, - int recursion) -{ - /* does not return a new reference! */ - PyObject *x; - int index; - const struct _cffi_global_s *g; - CTypeDescrObject *ct; - builder_c_t *types_builder = lib->l_types_builder; - const char *s = PyText_AsUTF8(name); - if (s == NULL) - return NULL; - - index = search_in_globals(&types_builder->ctx, s, strlen(s)); - if (index < 0) { - - if (types_builder->included_libs != NULL) { - Py_ssize_t i; - PyObject *included_ffis = types_builder->included_ffis; - PyObject *included_libs = types_builder->included_libs; - - if (recursion > 100) { - PyErr_SetString(PyExc_RuntimeError, - "recursion overflow in ffi.include() delegations"); - return NULL; - } - - for (i = 0; i < PyTuple_GET_SIZE(included_libs); i++) { - LibObject *lib1; - - lib1 = (LibObject *)PyTuple_GET_ITEM(included_libs, i); - if (lib1 != NULL) { - x = PyDict_GetItem(lib1->l_dict, name); - if (x != NULL) { - Py_INCREF(x); - goto found; - } - x = lib_build_and_cache_attr(lib1, name, recursion + 1); - if (x != NULL) { - Py_INCREF(x); - goto found; - } - } - else { - FFIObject *ffi1; - - ffi1 = (FFIObject *)PyTuple_GetItem(included_ffis, i); - if (ffi1 == NULL) - return NULL; - x = ffi_fetch_int_constant(ffi1, s, recursion + 1); - if (x != NULL) - goto found; - } - if (PyErr_Occurred()) - return NULL; - } - } - - if (recursion > 0) - return NULL; /* no error set, continue looking elsewhere */ - - PyErr_Format(PyExc_AttributeError, - "cffi library '%.200s' has no function, constant " - "or global variable named '%.200s'", - PyText_AS_UTF8(lib->l_libname), s); - return NULL; - } - - g = &types_builder->ctx.globals[index]; - - switch (_CFFI_GETOP(g->type_op)) { - - case _CFFI_OP_CPYTHON_BLTN_V: - x = lib_build_cpython_func(lib, g, s, METH_VARARGS); - break; - - case _CFFI_OP_CPYTHON_BLTN_N: - x = lib_build_cpython_func(lib, g, s, METH_NOARGS); - break; - - case _CFFI_OP_CPYTHON_BLTN_O: - x = lib_build_cpython_func(lib, g, s, METH_O); - break; - - case _CFFI_OP_CONSTANT_INT: - case _CFFI_OP_ENUM: - { - /* a constant integer whose value, in an "unsigned long long", - is obtained by calling the function at g->address */ - x = realize_global_int(types_builder, index); - break; - } - - case _CFFI_OP_CONSTANT: - case _CFFI_OP_DLOPEN_CONST: - { - /* a constant which is not of integer type */ - char *data; - ct = realize_c_type(types_builder, types_builder->ctx.types, - _CFFI_GETARG(g->type_op)); - if (ct == NULL) - return NULL; - - if (ct->ct_size <= 0) { - PyErr_Format(FFIError, "constant '%s' is of type '%s', " - "whose size is not known", s, ct->ct_name); - return NULL; - } - if (g->address == NULL) { - /* for dlopen() style */ - assert(_CFFI_GETOP(g->type_op) == _CFFI_OP_DLOPEN_CONST); - data = cdlopen_fetch(lib->l_libname, lib->l_libhandle, s); - if (data == NULL) - return NULL; - } - else { - /* The few bytes of memory we allocate here appear to leak, but - this is not a real leak. Indeed, CPython never unloads its C - extension modules. There is only one PyMem_Malloc() per real - non-integer C constant in a CFFI C extension module. That - means that this PyMem_Malloc() could also have been written - with a static global variable generated for each OP_CONSTANT - defined in the C extension, and the effect would be the same - (but a bit more complicated). - - Note that we used to do alloca(), but see issue #198. We - could still do alloca(), or explicit PyMem_Free(), in some - cases; but there is no point and it only makes the remaining - less-common cases more suspicious. - */ - assert(_CFFI_GETOP(g->type_op) == _CFFI_OP_CONSTANT); - data = PyMem_Malloc(ct->ct_size); - if (data == NULL) { - PyErr_NoMemory(); - return NULL; - } - ((void(*)(char*))g->address)(data); - } - x = convert_to_object(data, ct); - Py_DECREF(ct); - break; - } - - case _CFFI_OP_GLOBAL_VAR: - { - /* global variable of the exact type specified here - (nowadays, only used by the ABI mode or backward - compatibility; see _CFFI_OP_GLOBAL_VAR_F for the API mode) - */ - Py_ssize_t g_size = (Py_ssize_t)g->size_or_direct_fn; - ct = realize_c_type(types_builder, types_builder->ctx.types, - _CFFI_GETARG(g->type_op)); - if (ct == NULL) - return NULL; - if (g_size != ct->ct_size && g_size != 0 && ct->ct_size > 0) { - PyErr_Format(FFIError, - "global variable '%.200s' should be %zd bytes " - "according to the cdef, but is actually %zd", - s, ct->ct_size, g_size); - x = NULL; - } - else { - void *address = g->address; - if (address == NULL) { - /* for dlopen() style */ - address = cdlopen_fetch(lib->l_libname, lib->l_libhandle, s); - if (address == NULL) - return NULL; - } - x = make_global_var(name, ct, address, NULL); - } - Py_DECREF(ct); - break; - } - - case _CFFI_OP_GLOBAL_VAR_F: - ct = realize_c_type(types_builder, types_builder->ctx.types, - _CFFI_GETARG(g->type_op)); - if (ct == NULL) - return NULL; - x = make_global_var(name, ct, NULL, (gs_fetch_addr_fn)g->address); - Py_DECREF(ct); - break; - - case _CFFI_OP_DLOPEN_FUNC: - { - /* For dlopen(): the function of the given 'name'. We use - dlsym() to get the address of something in the dynamic - library, which we interpret as being exactly a function of - the specified type. - */ - PyObject *ct1; - void *address = cdlopen_fetch(lib->l_libname, lib->l_libhandle, s); - if (address == NULL) - return NULL; - - ct1 = realize_c_type_or_func(types_builder, - types_builder->ctx.types, - _CFFI_GETARG(g->type_op)); - if (ct1 == NULL) - return NULL; - - assert(!CTypeDescr_Check(ct1)); /* must be a function */ - x = new_simple_cdata(address, unwrap_fn_as_fnptr(ct1)); - - Py_DECREF(ct1); - break; - } - - case _CFFI_OP_EXTERN_PYTHON: - /* for reading 'lib.bar' where bar is declared with extern "Python" */ - ct = realize_c_type(types_builder, types_builder->ctx.types, - _CFFI_GETARG(g->type_op)); - if (ct == NULL) - return NULL; - x = convert_to_object((char *)&g->size_or_direct_fn, ct); - Py_DECREF(ct); - break; - - default: - PyErr_Format(PyExc_NotImplementedError, "in lib_build_attr: op=%d", - (int)_CFFI_GETOP(g->type_op)); - return NULL; - } - - found: - if (x != NULL) { - int err = PyDict_SetItem(lib->l_dict, name, x); - Py_DECREF(x); - if (err < 0) /* else there is still one ref left in the dict */ - return NULL; - } - return x; -} - -#define LIB_GET_OR_CACHE_ADDR(x, lib, name, error) \ - do { \ - x = PyDict_GetItem(lib->l_dict, name); \ - if (x == NULL) { \ - x = lib_build_and_cache_attr(lib, name, 0); \ - if (x == NULL) { \ - error; \ - } \ - } \ - } while (0) - -static PyObject *_lib_dir1(LibObject *lib, int ignore_global_vars) -{ - const struct _cffi_global_s *g = lib->l_types_builder->ctx.globals; - int i, count = 0, total = lib->l_types_builder->ctx.num_globals; - PyObject *s, *lst = PyList_New(total); - if (lst == NULL) - return NULL; - - for (i = 0; i < total; i++) { - if (ignore_global_vars) { - int op = _CFFI_GETOP(g[i].type_op); - if (op == _CFFI_OP_GLOBAL_VAR || op == _CFFI_OP_GLOBAL_VAR_F) - continue; - } - s = PyText_FromString(g[i].name); - if (s == NULL) - goto error; - PyList_SET_ITEM(lst, count, s); - count++; - } - if (PyList_SetSlice(lst, count, total, NULL) < 0) - goto error; - return lst; - - error: - Py_DECREF(lst); - return NULL; -} - -static PyObject *_lib_dict(LibObject *lib) -{ - const struct _cffi_global_s *g = lib->l_types_builder->ctx.globals; - int i, total = lib->l_types_builder->ctx.num_globals; - PyObject *name, *x, *d = PyDict_New(); - if (d == NULL) - return NULL; - - for (i = 0; i < total; i++) { - name = PyText_FromString(g[i].name); - if (name == NULL) - goto error; - - LIB_GET_OR_CACHE_ADDR(x, lib, name, goto error); - - if (PyDict_SetItem(d, name, x) < 0) - goto error; - Py_DECREF(name); - } - return d; - - error: - Py_XDECREF(name); - Py_DECREF(d); - return NULL; -} - -static PyObject *lib_getattr(LibObject *lib, PyObject *name) -{ - const char *p; - PyObject *x; - LIB_GET_OR_CACHE_ADDR(x, lib, name, goto missing); - - if (GlobSupport_Check(x)) { - return read_global_var((GlobSupportObject *)x); - } - Py_INCREF(x); - return x; - - missing: - /*** ATTRIBUTEERROR IS SET HERE ***/ - p = PyText_AsUTF8(name); - if (p == NULL) - return NULL; - if (strcmp(p, "__all__") == 0) { - PyErr_Clear(); - return _lib_dir1(lib, 1); - } - if (strcmp(p, "__dict__") == 0) { - PyErr_Clear(); - return _lib_dict(lib); - } - if (strcmp(p, "__class__") == 0) { - PyErr_Clear(); - x = (PyObject *)&PyModule_Type; - /* ^^^ used to be Py_TYPE(lib). But HAAAAAACK! That makes - help() behave correctly. I couldn't find a more reasonable - way. Urgh. */ - Py_INCREF(x); - return x; - } - /* this hack is for Python 3.5, and also to give a more - module-like behavior */ - if (strcmp(p, "__name__") == 0) { - PyErr_Clear(); - return PyText_FromFormat("%s.lib", PyText_AS_UTF8(lib->l_libname)); - } -#if PY_MAJOR_VERSION >= 3 - if (strcmp(p, "__loader__") == 0 || strcmp(p, "__spec__") == 0) { - /* some more module-like behavior hacks */ - PyErr_Clear(); - Py_INCREF(Py_None); - return Py_None; - } -#endif - return NULL; -} - -static int lib_setattr(LibObject *lib, PyObject *name, PyObject *val) -{ - PyObject *x; - LIB_GET_OR_CACHE_ADDR(x, lib, name, return -1); - - if (val == NULL) { - PyErr_SetString(PyExc_AttributeError, "C attribute cannot be deleted"); - return -1; - } - - if (GlobSupport_Check(x)) { - return write_global_var((GlobSupportObject *)x, val); - } - - PyErr_Format(PyExc_AttributeError, - "cannot write to function or constant '%.200s'", - PyText_Check(name) ? PyText_AS_UTF8(name) : "?"); - return -1; -} - -static PyObject *lib_dir(PyObject *self, PyObject *noarg) -{ - return _lib_dir1((LibObject *)self, 0); -} - -static PyMethodDef lib_methods[] = { - {"__dir__", lib_dir, METH_NOARGS}, - {NULL, NULL} /* sentinel */ -}; - -static PyTypeObject Lib_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_cffi_backend.Lib", - sizeof(LibObject), - 0, - (destructor)lib_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - (reprfunc)lib_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - (getattrofunc)lib_getattr, /* tp_getattro */ - (setattrofunc)lib_setattr, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - 0, /* tp_doc */ - (traverseproc)lib_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - lib_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - offsetof(LibObject, l_dict), /* tp_dictoffset */ -}; - -static LibObject *lib_internal_new(FFIObject *ffi, const char *module_name, - void *dlopen_libhandle, int auto_close) -{ - LibObject *lib; - PyObject *libname, *dict; - - libname = PyText_FromString(module_name); - if (libname == NULL) - goto err1; - - dict = PyDict_New(); - if (dict == NULL) - goto err2; - - lib = (LibObject *)PyType_GenericAlloc(&Lib_Type, 0); - if (lib == NULL) - goto err3; - - lib->l_types_builder = &ffi->types_builder; - lib->l_dict = dict; - lib->l_libname = libname; - Py_INCREF(ffi); - lib->l_ffi = ffi; - lib->l_libhandle = dlopen_libhandle; - lib->l_auto_close = auto_close; - return lib; - - err3: - Py_DECREF(dict); - err2: - Py_DECREF(libname); - err1: - if (auto_close) - cdlopen_close_ignore_errors(dlopen_libhandle); - return NULL; -} - -static PyObject *address_of_global_var(PyObject *args) -{ - LibObject *lib; - PyObject *x, *o_varname; - char *varname; - - if (!PyArg_ParseTuple(args, "O!s", &Lib_Type, &lib, &varname)) - return NULL; - - /* rebuild a string from 'varname', to do typechecks and to force - a unicode back to a plain string (on python 2) */ - o_varname = PyText_FromString(varname); - if (o_varname == NULL) - return NULL; - - LIB_GET_OR_CACHE_ADDR(x, lib, o_varname, goto error); - Py_DECREF(o_varname); - if (GlobSupport_Check(x)) { - return cg_addressof_global_var((GlobSupportObject *)x); - } - else { - struct CPyExtFunc_s *exf = _cpyextfunc_get(x); - if (exf != NULL) { /* an OP_CPYTHON_BLTN: '&func' returns a cdata */ - PyObject *ct; - if (exf->direct_fn == NULL) { - Py_INCREF(x); /* backward compatibility */ - return x; - } - ct = _cpyextfunc_type(lib, exf); - if (ct == NULL) - return NULL; - x = new_simple_cdata(exf->direct_fn, (CTypeDescrObject *)ct); - Py_DECREF(ct); - return x; - } - if (CData_Check(x) && /* a constant functionptr cdata: 'f == &f' */ - (((CDataObject *)x)->c_type->ct_flags & CT_FUNCTIONPTR) != 0) { - Py_INCREF(x); - return x; - } - else { - PyErr_Format(PyExc_AttributeError, - "cannot take the address of the constant '%.200s'", - varname); - return NULL; - } - } - - error: - Py_DECREF(o_varname); - return NULL; -} diff --git a/c/libffi_arm64/README b/c/libffi_arm64/README deleted file mode 100644 index 3b8f133..0000000 --- a/c/libffi_arm64/README +++ /dev/null @@ -1,5 +0,0 @@ -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 Binary files differdeleted file mode 100644 index 4a8b84b..0000000 --- a/c/libffi_arm64/ffi.lib +++ /dev/null diff --git a/c/libffi_arm64/include/ffi.h b/c/libffi_arm64/include/ffi.h deleted file mode 100644 index d91c3e1..0000000 --- a/c/libffi_arm64/include/ffi.h +++ /dev/null @@ -1,515 +0,0 @@ -/* -----------------------------------------------------------------*-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 deleted file mode 100644 index 5768c29..0000000 --- a/c/libffi_arm64/include/fficonfig.h +++ /dev/null @@ -1,215 +0,0 @@ -/* 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 deleted file mode 100644 index ecb6d2d..0000000 --- a/c/libffi_arm64/include/ffitarget.h +++ /dev/null @@ -1,92 +0,0 @@ -/* 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_x86_x64/LICENSE b/c/libffi_x86_x64/LICENSE deleted file mode 100644 index f591795..0000000 --- a/c/libffi_x86_x64/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -libffi - Copyright (c) 1996-2003 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 CYGNUS SOLUTIONS 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. diff --git a/c/libffi_x86_x64/README b/c/libffi_x86_x64/README deleted file mode 100644 index 97a12cf..0000000 --- a/c/libffi_x86_x64/README +++ /dev/null @@ -1,502 +0,0 @@ -This directory contains the libffi package, which is not part of GCC but -shipped with GCC as convenience. - -Copied without changes from CPython 2.7 head (e04e1f253ed8). - -Status -====== - -libffi-2.00 has not been released yet! This is a development snapshot! - -libffi-1.20 was released on October 5, 1998. Check the libffi web -page for updates: <URL:http://sources.redhat.com/libffi/>. - - -What is libffi? -=============== - -Compilers for high level languages generate code that follow certain -conventions. These conventions are necessary, in part, for separate -compilation to work. One such convention is the "calling -convention". The "calling convention" is essentially a set of -assumptions made by the compiler about where function arguments will -be found on entry to a function. A "calling convention" also specifies -where the return value for a function is found. - -Some programs may not know at the time of compilation what arguments -are to be passed to a function. For instance, an interpreter may be -told at run-time about the number and types of arguments used to call -a given function. Libffi can be used in such programs to provide a -bridge from the interpreter program to compiled code. - -The libffi library provides a portable, high level programming -interface to various calling conventions. This allows a programmer to -call any function specified by a call interface description at run -time. - -Ffi stands for Foreign Function Interface. A foreign function -interface is the popular name for the interface that allows code -written in one language to call code written in another language. The -libffi library really only provides the lowest, machine dependent -layer of a fully featured foreign function interface. A layer must -exist above libffi that handles type conversions for values passed -between the two languages. - - -Supported Platforms and Prerequisites -===================================== - -Libffi has been ported to: - - SunOS 4.1.3 & Solaris 2.x (SPARC-V8, SPARC-V9) - - Irix 5.3 & 6.2 (System V/o32 & n32) - - Intel x86 - Linux (System V ABI) - - Alpha - Linux and OSF/1 - - m68k - Linux (System V ABI) - - PowerPC - Linux (System V ABI, Darwin, AIX) - - ARM - Linux (System V ABI) - -Libffi has been tested with the egcs 1.0.2 gcc compiler. Chances are -that other versions will work. Libffi has also been built and tested -with the SGI compiler tools. - -On PowerPC, the tests failed (see the note below). - -You must use GNU make to build libffi. SGI's make will not work. -Sun's probably won't either. - -If you port libffi to another platform, please let me know! I assume -that some will be easy (x86 NetBSD), and others will be more difficult -(HP). - - -Installing libffi -================= - -[Note: before actually performing any of these installation steps, - you may wish to read the "Platform Specific Notes" below.] - -First you must configure the distribution for your particular -system. Go to the directory you wish to build libffi in and run the -"configure" program found in the root directory of the libffi source -distribution. - -You may want to tell configure where to install the libffi library and -header files. To do that, use the --prefix configure switch. Libffi -will install under /usr/local by default. - -If you want to enable extra run-time debugging checks use the the ---enable-debug configure switch. This is useful when your program dies -mysteriously while using libffi. - -Another useful configure switch is --enable-purify-safety. Using this -will add some extra code which will suppress certain warnings when you -are using Purify with libffi. Only use this switch when using -Purify, as it will slow down the library. - -Configure has many other options. Use "configure --help" to see them all. - -Once configure has finished, type "make". Note that you must be using -GNU make. SGI's make will not work. Sun's probably won't either. -You can ftp GNU make from prep.ai.mit.edu:/pub/gnu. - -To ensure that libffi is working as advertised, type "make test". - -To install the library and header files, type "make install". - - -Using libffi -============ - - The Basics - ---------- - -Libffi assumes that you have a pointer to the function you wish to -call and that you know the number and types of arguments to pass it, -as well as the return type of the function. - -The first thing you must do is create an ffi_cif object that matches -the signature of the function you wish to call. The cif in ffi_cif -stands for Call InterFace. To prepare a call interface object, use the -following function: - -ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi abi, - unsigned int nargs, - ffi_type *rtype, ffi_type **atypes); - - CIF is a pointer to the call interface object you wish - to initialize. - - ABI is an enum that specifies the calling convention - to use for the call. FFI_DEFAULT_ABI defaults - to the system's native calling convention. Other - ABI's may be used with care. They are system - specific. - - NARGS is the number of arguments this function accepts. - libffi does not yet support vararg functions. - - RTYPE is a pointer to an ffi_type structure that represents - the return type of the function. Ffi_type objects - describe the types of values. libffi provides - ffi_type objects for many of the native C types: - signed int, unsigned int, signed char, unsigned char, - etc. There is also a pointer ffi_type object and - a void ffi_type. Use &ffi_type_void for functions that - don't return values. - - ATYPES is a vector of ffi_type pointers. ARGS must be NARGS long. - If NARGS is 0, this is ignored. - - -ffi_prep_cif will return a status code that you are responsible -for checking. It will be one of the following: - - FFI_OK - All is good. - - FFI_BAD_TYPEDEF - One of the ffi_type objects that ffi_prep_cif - came across is bad. - - -Before making the call, the VALUES vector should be initialized -with pointers to the appropriate argument values. - -To call the the function using the initialized ffi_cif, use the -ffi_call function: - -void ffi_call(ffi_cif *cif, void *fn, void *rvalue, void **avalues); - - CIF is a pointer to the ffi_cif initialized specifically - for this function. - - FN is a pointer to the function you want to call. - - RVALUE is a pointer to a chunk of memory that is to hold the - result of the function call. Currently, it must be - at least one word in size (except for the n32 version - under Irix 6.x, which must be a pointer to an 8 byte - aligned value (a long long). It must also be at least - word aligned (depending on the return type, and the - system's alignment requirements). If RTYPE is - &ffi_type_void, this is ignored. If RVALUE is NULL, - the return value is discarded. - - AVALUES is a vector of void* that point to the memory locations - holding the argument values for a call. - If NARGS is 0, this is ignored. - - -If you are expecting a return value from FN it will have been stored -at RVALUE. - - - - An Example - ---------- - -Here is a trivial example that calls puts() a few times. - - #include <stdio.h> - #include <ffi.h> - - int main() - { - ffi_cif cif; - ffi_type *args[1]; - void *values[1]; - char *s; - int rc; - - /* Initialize the argument info vectors */ - args[0] = &ffi_type_uint; - values[0] = &s; - - /* Initialize the cif */ - if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, - &ffi_type_uint, args) == FFI_OK) - { - s = "Hello World!"; - ffi_call(&cif, puts, &rc, values); - /* rc now holds the result of the call to puts */ - - /* values holds a pointer to the function's arg, so to - call puts() again all we need to do is change the - value of s */ - s = "This is cool!"; - ffi_call(&cif, puts, &rc, values); - } - - return 0; - } - - - - Aggregate Types - --------------- - -Although libffi has no special support for unions or bit-fields, it is -perfectly happy passing structures back and forth. You must first -describe the structure to libffi by creating a new ffi_type object -for it. Here is the definition of ffi_type: - - typedef struct _ffi_type - { - unsigned size; - short alignment; - short type; - struct _ffi_type **elements; - } ffi_type; - -All structures must have type set to FFI_TYPE_STRUCT. You may set -size and alignment to 0. These will be calculated and reset to the -appropriate values by ffi_prep_cif(). - -elements is a NULL terminated array of pointers to ffi_type objects -that describe the type of the structure elements. These may, in turn, -be structure elements. - -The following example initializes a ffi_type object representing the -tm struct from Linux's time.h: - - struct tm { - int tm_sec; - int tm_min; - int tm_hour; - int tm_mday; - int tm_mon; - int tm_year; - int tm_wday; - int tm_yday; - int tm_isdst; - /* Those are for future use. */ - long int __tm_gmtoff__; - __const char *__tm_zone__; - }; - - { - ffi_type tm_type; - ffi_type *tm_type_elements[12]; - int i; - - tm_type.size = tm_type.alignment = 0; - tm_type.elements = &tm_type_elements; - - for (i = 0; i < 9; i++) - tm_type_elements[i] = &ffi_type_sint; - - tm_type_elements[9] = &ffi_type_slong; - tm_type_elements[10] = &ffi_type_pointer; - tm_type_elements[11] = NULL; - - /* tm_type can now be used to represent tm argument types and - return types for ffi_prep_cif() */ - } - - - -Platform Specific Notes -======================= - - Intel x86 - --------- - -There are no known problems with the x86 port. - - Sun SPARC - SunOS 4.1.3 & Solaris 2.x - ------------------------------------- - -You must use GNU Make to build libffi on Sun platforms. - - MIPS - Irix 5.3 & 6.x - --------------------- - -Irix 6.2 and better supports three different calling conventions: o32, -n32 and n64. Currently, libffi only supports both o32 and n32 under -Irix 6.x, but only o32 under Irix 5.3. Libffi will automatically be -configured for whichever calling convention it was built for. - -By default, the configure script will try to build libffi with the GNU -development tools. To build libffi with the SGI development tools, set -the environment variable CC to either "cc -32" or "cc -n32" before -running configure under Irix 6.x (depending on whether you want an o32 -or n32 library), or just "cc" for Irix 5.3. - -With the n32 calling convention, when returning structures smaller -than 16 bytes, be sure to provide an RVALUE that is 8 byte aligned. -Here's one way of forcing this: - - double struct_storage[2]; - my_small_struct *s = (my_small_struct *) struct_storage; - /* Use s for RVALUE */ - -If you don't do this you are liable to get spurious bus errors. - -"long long" values are not supported yet. - -You must use GNU Make to build libffi on SGI platforms. - - ARM - System V ABI - ------------------ - -The ARM port was performed on a NetWinder running ARM Linux ELF -(2.0.31) and gcc 2.8.1. - - - - PowerPC System V ABI - -------------------- - -There are two `System V ABI's which libffi implements for PowerPC. -They differ only in how small structures are returned from functions. - -In the FFI_SYSV version, structures that are 8 bytes or smaller are -returned in registers. This is what GCC does when it is configured -for solaris, and is what the System V ABI I have (dated September -1995) says. - -In the FFI_GCC_SYSV version, all structures are returned the same way: -by passing a pointer as the first argument to the function. This is -what GCC does when it is configured for linux or a generic sysv -target. - -EGCS 1.0.1 (and probably other versions of EGCS/GCC) also has a -inconsistency with the SysV ABI: When a procedure is called with many -floating-point arguments, some of them get put on the stack. They are -all supposed to be stored in double-precision format, even if they are -only single-precision, but EGCS stores single-precision arguments as -single-precision anyway. This causes one test to fail (the `many -arguments' test). - - -What's With The Crazy Comments? -=============================== - -You might notice a number of cryptic comments in the code, delimited -by /*@ and @*/. These are annotations read by the program LCLint, a -tool for statically checking C programs. You can read all about it at -<http://larch-www.lcs.mit.edu:8001/larch/lclint/index.html>. - - -History -======= - -1.20 Oct-5-98 - Raffaele Sena produces ARM port. - -1.19 Oct-5-98 - Fixed x86 long double and long long return support. - m68k bug fixes from Andreas Schwab. - Patch for DU assembler compatibility for the Alpha from Richard - Henderson. - -1.18 Apr-17-98 - Bug fixes and MIPS configuration changes. - -1.17 Feb-24-98 - Bug fixes and m68k port from Andreas Schwab. PowerPC port from - Geoffrey Keating. Various bug x86, Sparc and MIPS bug fixes. - -1.16 Feb-11-98 - Richard Henderson produces Alpha port. - -1.15 Dec-4-97 - Fixed an n32 ABI bug. New libtool, auto* support. - -1.14 May-13-97 - libtool is now used to generate shared and static libraries. - Fixed a minor portability problem reported by Russ McManus - <mcmanr@eq.gs.com>. - -1.13 Dec-2-96 - Added --enable-purify-safety to keep Purify from complaining - about certain low level code. - Sparc fix for calling functions with < 6 args. - Linux x86 a.out fix. - -1.12 Nov-22-96 - Added missing ffi_type_void, needed for supporting void return - types. Fixed test case for non MIPS machines. Cygnus Support - is now Cygnus Solutions. - -1.11 Oct-30-96 - Added notes about GNU make. - -1.10 Oct-29-96 - Added configuration fix for non GNU compilers. - -1.09 Oct-29-96 - Added --enable-debug configure switch. Clean-ups based on LCLint - feedback. ffi_mips.h is always installed. Many configuration - fixes. Fixed ffitest.c for sparc builds. - -1.08 Oct-15-96 - Fixed n32 problem. Many clean-ups. - -1.07 Oct-14-96 - Gordon Irlam rewrites v8.S again. Bug fixes. - -1.06 Oct-14-96 - Gordon Irlam improved the sparc port. - -1.05 Oct-14-96 - Interface changes based on feedback. - -1.04 Oct-11-96 - Sparc port complete (modulo struct passing bug). - -1.03 Oct-10-96 - Passing struct args, and returning struct values works for - all architectures/calling conventions. Expanded tests. - -1.02 Oct-9-96 - Added SGI n32 support. Fixed bugs in both o32 and Linux support. - Added "make test". - -1.01 Oct-8-96 - Fixed float passing bug in mips version. Restructured some - of the code. Builds cleanly with SGI tools. - -1.00 Oct-7-96 - First release. No public announcement. - - -Authors & Credits -================= - -libffi was written by Anthony Green <green@cygnus.com>. - -Portions of libffi were derived from Gianni Mariani's free gencall -library for Silicon Graphics machines. - -The closure mechanism was designed and implemented by Kresten Krab -Thorup. - -The Sparc port was derived from code contributed by the fine folks at -Visible Decisions Inc <http://www.vdi.com>. Further enhancements were -made by Gordon Irlam at Cygnus Solutions <http://www.cygnus.com>. - -The Alpha port was written by Richard Henderson at Cygnus Solutions. - -Andreas Schwab ported libffi to m68k Linux and provided a number of -bug fixes. - -Geoffrey Keating ported libffi to the PowerPC. - -Raffaele Sena ported libffi to the ARM. - -Jesper Skov and Andrew Haley both did more than their fair share of -stepping through the code and tracking down bugs. - -Thanks also to Tom Tromey for bug fixes and configuration help. - -Thanks to Jim Blandy, who provided some useful feedback on the libffi -interface. - -If you have a problem, or have found a bug, please send a note to -green@cygnus.com. diff --git a/c/libffi_x86_x64/README.ctypes b/c/libffi_x86_x64/README.ctypes deleted file mode 100644 index 17e8a40..0000000 --- a/c/libffi_x86_x64/README.ctypes +++ /dev/null @@ -1,7 +0,0 @@ -The purpose is to hack the libffi sources so that they can be compiled -with MSVC, and to extend them so that they have the features I need -for ctypes. - -I retrieved the libffi sources from the gcc cvs repository on -2004-01-27. Then I did 'configure' in a 'build' subdirectory on a x86 -linux system, and copied the files I found useful. diff --git a/c/libffi_x86_x64/ffi.c b/c/libffi_x86_x64/ffi.c deleted file mode 100644 index b9e324f..0000000 --- a/c/libffi_x86_x64/ffi.c +++ /dev/null @@ -1,495 +0,0 @@ -/* ----------------------------------------------------------------------- - ffi.c - Copyright (c) 1996, 1998, 1999, 2001 Red Hat, Inc. - Copyright (c) 2002 Ranjit Mathew - Copyright (c) 2002 Bo Thorsen - Copyright (c) 2002 Roger Sayle - - x86 Foreign Function Interface - - 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 CYGNUS SOLUTIONS 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. - ----------------------------------------------------------------------- */ - -#include <ffi.h> -#include <ffi_common.h> - -#include <stdlib.h> - -/* ffi_prep_args is called by the assembly routine once stack space - has been allocated for the function's arguments */ - -extern void Py_FatalError(const char *msg); - -/*@-exportheader@*/ -void ffi_prep_args(char *stack, extended_cif *ecif) -/*@=exportheader@*/ -{ - register unsigned int i; - register void **p_argv; - register char *argp; - register ffi_type **p_arg; - - argp = stack; - if (ecif->cif->flags == FFI_TYPE_STRUCT) - { - *(void **) argp = ecif->rvalue; - argp += sizeof(void *); - } - - p_argv = ecif->avalue; - - for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; - i != 0; - i--, p_arg++) - { - size_t z; - - /* Align if necessary */ - if ((sizeof(void *) - 1) & (size_t) argp) - argp = (char *) ALIGN(argp, sizeof(void *)); - - z = (*p_arg)->size; - if (z < sizeof(int)) - { - z = sizeof(int); - switch ((*p_arg)->type) - { - case FFI_TYPE_SINT8: - *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv); - break; - - case FFI_TYPE_UINT8: - *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv); - break; - - case FFI_TYPE_SINT16: - *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv); - break; - - case FFI_TYPE_UINT16: - *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv); - break; - - case FFI_TYPE_SINT32: - *(signed int *) argp = (signed int)*(SINT32 *)(* p_argv); - break; - - case FFI_TYPE_UINT32: - *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); - break; - - case FFI_TYPE_STRUCT: - *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); - break; - - default: - FFI_ASSERT(0); - } - } -#ifdef _WIN64 - 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. */ - *(void **)argp = *p_argv; - z = 8; - } -#endif - else - { - memcpy(argp, *p_argv, z); - } - p_argv++; - argp += z; - } - - if (argp - stack > (long)ecif->cif->bytes) - { - Py_FatalError("FFI BUG: not enough stack space for arguments"); - } - return; -} - -/* Perform machine dependent cif processing */ -ffi_status ffi_prep_cif_machdep(ffi_cif *cif) -{ - /* Set the return type flag */ - switch (cif->rtype->type) - { - case FFI_TYPE_VOID: - case FFI_TYPE_SINT64: - case FFI_TYPE_FLOAT: - case FFI_TYPE_DOUBLE: - case FFI_TYPE_LONGDOUBLE: - cif->flags = (unsigned) cif->rtype->type; - break; - - case FFI_TYPE_STRUCT: - /* 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 == 1 || - cif->rtype->size == 2 || - cif->rtype->size == 4) - cif->flags = FFI_TYPE_INT; - else if (cif->rtype->size == 8) - cif->flags = FFI_TYPE_SINT64; - else - cif->flags = FFI_TYPE_STRUCT; - break; - - case FFI_TYPE_UINT64: -#ifdef _WIN64 - case FFI_TYPE_POINTER: -#endif - cif->flags = FFI_TYPE_SINT64; - break; - - default: - cif->flags = FFI_TYPE_INT; - break; - } - - return FFI_OK; -} - -#ifdef _WIN32 -extern int -ffi_call_x86(void (*)(char *, extended_cif *), - /*@out@*/ extended_cif *, - unsigned, unsigned, - /*@out@*/ unsigned *, - void (*fn)()); -#endif - -#ifdef _WIN64 -extern int -ffi_call_AMD64(void (*)(char *, extended_cif *), - /*@out@*/ extended_cif *, - unsigned, unsigned, - /*@out@*/ unsigned *, - void (*fn)()); -#endif - -int -ffi_call(/*@dependent@*/ ffi_cif *cif, - void (*fn)(), - /*@out@*/ void *rvalue, - /*@dependent@*/ void **avalue) -{ - extended_cif ecif; - - ecif.cif = cif; - ecif.avalue = avalue; - - /* If the return value is a struct and we don't have a return */ - /* value address then we need to make one */ - - if ((rvalue == NULL) && - (cif->flags == FFI_TYPE_STRUCT)) - { - /*@-sysunrecog@*/ - ecif.rvalue = alloca(cif->rtype->size); - /*@=sysunrecog@*/ - } - else - ecif.rvalue = rvalue; - - - switch (cif->abi) - { -#if !defined(_WIN64) - case FFI_SYSV: - case FFI_STDCALL: - return ffi_call_x86(ffi_prep_args, &ecif, cif->bytes, - cif->flags, ecif.rvalue, fn); - break; -#else - case FFI_SYSV: - /*@-usedef@*/ - return ffi_call_AMD64(ffi_prep_args, &ecif, cif->bytes, - cif->flags, ecif.rvalue, fn); - /*@=usedef@*/ - break; -#endif - - default: - FFI_ASSERT(0); - break; - } - return -1; /* theller: Hrm. */ -} - - -/** private members **/ - -static void ffi_prep_incoming_args_SYSV (char *stack, void **ret, - void** args, ffi_cif* cif); -/* This function is jumped to by the trampoline */ - -#ifdef _WIN64 -void * -#else -static void __fastcall -#endif -ffi_closure_SYSV (ffi_closure *closure, char *argp) -{ - // this is our return value storage - long double res; - - // our various things... - ffi_cif *cif; - void **arg_area; - unsigned short rtype; - void *resp = (void*)&res; - void *args = argp + sizeof(void *); - - cif = closure->cif; - arg_area = (void**) alloca (cif->nargs * sizeof (void*)); - - /* this call will initialize ARG_AREA, such that each - * element in that array points to the corresponding - * value on the stack; and if the function returns - * a structure, it will re-set RESP to point to the - * structure return address. */ - - ffi_prep_incoming_args_SYSV(args, (void**)&resp, arg_area, cif); - - (closure->fun) (cif, resp, arg_area, closure->user_data); - - rtype = cif->flags; - -#if defined(_WIN32) && !defined(_WIN64) -#ifdef _MSC_VER - /* now, do a generic return based on the value of rtype */ - if (rtype == FFI_TYPE_INT) - { - _asm mov eax, resp ; - _asm mov eax, [eax] ; - } - else if (rtype == FFI_TYPE_FLOAT) - { - _asm mov eax, resp ; - _asm fld DWORD PTR [eax] ; -// asm ("flds (%0)" : : "r" (resp) : "st" ); - } - 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_SINT64) - { - _asm mov edx, resp ; - _asm mov eax, [edx] ; - _asm mov edx, [edx + 4] ; -// asm ("movl 0(%0),%%eax;" -// "movl 4(%0),%%edx" -// : : "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) - { - asm ("movl (%0),%%eax" : : "r" (resp) : "eax"); - } - else if (rtype == FFI_TYPE_FLOAT) - { - asm ("flds (%0)" : : "r" (resp) : "st" ); - } - else if (rtype == FFI_TYPE_DOUBLE || rtype == FFI_TYPE_LONGDOUBLE) - { - asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" ); - } - else if (rtype == FFI_TYPE_SINT64) - { - asm ("movl 0(%0),%%eax;" - "movl 4(%0),%%edx" - : : "r"(resp) - : "eax", "edx"); - } - else if (rtype == FFI_TYPE_STRUCT) - { - asm ("movl %0,%%eax" : : "r" (resp) : "eax"); - } -#endif -#endif - -#ifdef _WIN64 - /* The result is returned in rax. This does the right thing for - 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 -} - -/*@-exportheader@*/ -static void -ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, - void **avalue, ffi_cif *cif) -/*@=exportheader@*/ -{ - register unsigned int i; - register void **p_argv; - register char *argp; - register ffi_type **p_arg; - - argp = stack; - - if ( cif->flags == FFI_TYPE_STRUCT ) { - *rvalue = *(void **) argp; - argp += 4; - } - - p_argv = avalue; - - for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++) - { - size_t z; - - /* Align if necessary */ - if ((sizeof(char *) - 1) & (size_t) argp) { - argp = (char *) ALIGN(argp, sizeof(char*)); - } - - z = (*p_arg)->size; - - /* because we're little endian, this is what it turns into. */ - -#ifdef _WIN64 - 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. */ - *p_argv = *((void**) argp); - z = 8; - } - else -#endif - *p_argv = (void*) argp; - - p_argv++; - argp += z; - } - - return; -} - -/* the cif must already be prep'ed */ -extern void ffi_closure_OUTER(); - -ffi_status -ffi_prep_closure_loc (ffi_closure* closure, - ffi_cif* cif, - void (*fun)(ffi_cif*,void*,void**,void*), - void *user_data, - void *codeloc) -{ - short bytes; - char *tramp; -#ifdef _WIN64 - int mask = 0; -#endif - FFI_ASSERT (cif->abi == FFI_SYSV); - - if (cif->abi == FFI_SYSV) - bytes = 0; -#if !defined(_WIN64) - else if (cif->abi == FFI_STDCALL) - bytes = cif->bytes; -#endif - else - return FFI_BAD_ABI; - - tramp = &closure->tramp[0]; - -#define BYTES(text) memcpy(tramp, text, sizeof(text)), tramp += sizeof(text)-1 -#define POINTER(x) *(void**)tramp = (void*)(x), tramp += sizeof(void*) -#define SHORT(x) *(short*)tramp = x, tramp += sizeof(short) -#define INT(x) *(int*)tramp = x, tramp += sizeof(int) - -#ifdef _WIN64 - if (cif->nargs >= 1 && - (cif->arg_types[0]->type == FFI_TYPE_FLOAT - || cif->arg_types[0]->type == FFI_TYPE_DOUBLE)) - mask |= 1; - if (cif->nargs >= 2 && - (cif->arg_types[1]->type == FFI_TYPE_FLOAT - || cif->arg_types[1]->type == FFI_TYPE_DOUBLE)) - mask |= 2; - if (cif->nargs >= 3 && - (cif->arg_types[2]->type == FFI_TYPE_FLOAT - || cif->arg_types[2]->type == FFI_TYPE_DOUBLE)) - mask |= 4; - if (cif->nargs >= 4 && - (cif->arg_types[3]->type == FFI_TYPE_FLOAT - || 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); - - /* 48 B8 -------- mov rax, closure */ - BYTES("\x48\xB8"); POINTER(closure); - - /* 49 BA -------- mov r10, ffi_closure_OUTER */ - BYTES("\x49\xBA"); POINTER(ffi_closure_OUTER); - - /* 41 FF E2 jmp r10 */ - BYTES("\x41\xFF\xE2"); - -#else - - /* mov ecx, closure */ - BYTES("\xb9"); POINTER(closure); - - /* mov edx, esp */ - BYTES("\x8b\xd4"); - - /* call ffi_closure_SYSV */ - BYTES("\xe8"); POINTER((char*)&ffi_closure_SYSV - (tramp + 4)); - - /* ret bytes */ - BYTES("\xc2"); - SHORT(bytes); - -#endif - - if (tramp - &closure->tramp[0] > FFI_TRAMPOLINE_SIZE) - Py_FatalError("FFI_TRAMPOLINE_SIZE too small in " __FILE__); - - closure->cif = cif; - closure->user_data = user_data; - closure->fun = fun; - return FFI_OK; -} diff --git a/c/libffi_x86_x64/ffi.h b/c/libffi_x86_x64/ffi.h deleted file mode 100644 index 97cdb59..0000000 --- a/c/libffi_x86_x64/ffi.h +++ /dev/null @@ -1,322 +0,0 @@ -/* -----------------------------------------------------------------*-C-*- - libffi 2.00-beta - Copyright (c) 1996-2003 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 CYGNUS SOLUTIONS 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. - - ----------------------------------------------------------------------- */ - -/* ------------------------------------------------------------------- - The basic API is described in the README file. - - The raw API is designed to bypass some of the argument packing - and unpacking on architectures for which it can be avoided. - - The closure API allows interpreted functions to be packaged up - inside a C function pointer, so that they can be called as C functions, - with no understanding on the client side that they are interpreted. - It can also be used in other cases in which it is necessary to package - up a user specified parameter and a function pointer as a single - function pointer. - - The closure API must be implemented in order to get its functionality, - e.g. for use by gij. Routines are provided to emulate the raw API - if the underlying platform doesn't allow faster implementation. - - More details on the raw and cloure 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. */ -//XXX #define X86 - -/* ---- System configuration information --------------------------------- */ - -#include <ffitarget.h> - -#ifndef LIBFFI_ASM - -#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. */ -#ifdef LONG_LONG_MAX -# define FFI_LONG_LONG_MAX LONG_LONG_MAX -#else -# ifdef LLONG_MAX -# define FFI_LONG_LONG_MAX LLONG_MAX -# else -# ifdef __GNUC__ -# define FFI_LONG_LONG_MAX __LONG_LONG_MAX__ -# endif -# ifdef _MSC_VER -# define FFI_LONG_LONG_MAX _I64_MAX -# endif -# endif -#endif - -#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 - -#define ffi_type_ulong ffi_type_uint64 -#define ffi_type_slong ffi_type_sint64 -#if LONG_MAX == 2147483647 -# if FFI_LONG_LONG_MAX != 9223372036854775807 - #error "no 64-bit data type supported" -# endif -#elif LONG_MAX != 9223372036854775807 - #error "long size not supported" -#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; - /*@null@*/ struct _ffi_type **elements; -} ffi_type; - -/* These are defined in types.c */ -extern ffi_type ffi_type_void; -extern ffi_type ffi_type_uint8; -extern ffi_type ffi_type_sint8; -extern ffi_type ffi_type_uint16; -extern ffi_type ffi_type_sint16; -extern ffi_type ffi_type_uint32; -extern ffi_type ffi_type_sint32; -extern ffi_type ffi_type_uint64; -extern ffi_type ffi_type_sint64; -extern ffi_type ffi_type_float; -extern ffi_type ffi_type_double; -extern ffi_type ffi_type_longdouble; -extern ffi_type ffi_type_pointer; - - -typedef enum { - FFI_OK = 0, - FFI_BAD_TYPEDEF, - FFI_BAD_ABI -} ffi_status; - -typedef unsigned FFI_TYPE; - -typedef struct { - ffi_abi abi; - unsigned nargs; - /*@dependent@*/ ffi_type **arg_types; - /*@dependent@*/ ffi_type *rtype; - unsigned bytes; - unsigned flags; -#ifdef FFI_EXTRA_CIF_FIELDS - FFI_EXTRA_CIF_FIELDS; -#endif -} ffi_cif; - -/* ---- Definitions for the raw API -------------------------------------- */ - -#ifdef _WIN64 -#define FFI_SIZEOF_ARG 8 -#else -#define FFI_SIZEOF_ARG 4 -#endif - -typedef union { - ffi_sarg sint; - ffi_arg uint; - float flt; - char data[FFI_SIZEOF_ARG]; - void* ptr; -} ffi_raw; - -void ffi_raw_call (/*@dependent@*/ ffi_cif *cif, - void (*fn)(), - /*@out@*/ void *rvalue, - /*@dependent@*/ ffi_raw *avalue); - -void ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw); -void ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args); -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. */ - -void ffi_java_raw_call (/*@dependent@*/ ffi_cif *cif, - void (*fn)(), - /*@out@*/ void *rvalue, - /*@dependent@*/ ffi_raw *avalue); - -void ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw); -void ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args); -size_t ffi_java_raw_size (ffi_cif *cif); - -/* ---- Definitions for closures ----------------------------------------- */ - -#if FFI_CLOSURES - -typedef struct { - char tramp[FFI_TRAMPOLINE_SIZE]; - ffi_cif *cif; - void (*fun)(ffi_cif*,void*,void**,void*); - void *user_data; -} ffi_closure; - -void ffi_closure_free(void *); -void *ffi_closure_alloc (size_t size, void **code); - -ffi_status -ffi_prep_closure_loc (ffi_closure*, - ffi_cif *, - void (*fun)(ffi_cif*,void*,void**,void*), - void *user_data, - void *codeloc); - -/* AR: for cffi we need the following API, and not the _loc version */ -#define ffi_prep_closure(a,b,c,d) ffi_prep_closure_loc(a,b,c,d,a) - -typedef struct { - char tramp[FFI_TRAMPOLINE_SIZE]; - - 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; - -ffi_status -ffi_prep_raw_closure (ffi_raw_closure*, - ffi_cif *cif, - void (*fun)(ffi_cif*,void*,ffi_raw*,void*), - void *user_data); - -ffi_status -ffi_prep_java_raw_closure (ffi_raw_closure*, - ffi_cif *cif, - void (*fun)(ffi_cif*,void*,ffi_raw*,void*), - void *user_data); - -#endif /* FFI_CLOSURES */ - -/* ---- Public interface definition -------------------------------------- */ - -ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif, - ffi_abi abi, - unsigned int nargs, - /*@dependent@*/ /*@out@*/ /*@partial@*/ ffi_type *rtype, - /*@dependent@*/ ffi_type **atypes); - -int -ffi_call(/*@dependent@*/ ffi_cif *cif, - void (*fn)(), - /*@out@*/ void *rvalue, - /*@dependent@*/ void **avalue); - -/* Useful for eliminating compiler warnings */ -#define FFI_FN(f) ((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 1 -#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 - -/* This should always refer to the last type code (for sanity checks) */ -#define FFI_TYPE_LAST FFI_TYPE_POINTER - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/c/libffi_x86_x64/ffi_common.h b/c/libffi_x86_x64/ffi_common.h deleted file mode 100644 index 43fb83b..0000000 --- a/c/libffi_x86_x64/ffi_common.h +++ /dev/null @@ -1,77 +0,0 @@ -/* ----------------------------------------------------------------------- - ffi_common.h - Copyright (c) 1996 Red Hat, Inc. - - Common internal definitions and macros. Only necessary for building - libffi. - ----------------------------------------------------------------------- */ - -#ifndef FFI_COMMON_H -#define FFI_COMMON_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include <fficonfig.h> -#include <malloc.h> - -/* Check for the existence of memcpy. */ -#if STDC_HEADERS -# include <string.h> -#else -# ifndef HAVE_MEMCPY -# define memcpy(d, s, n) bcopy ((s), (d), (n)) -# endif -#endif - -#if defined(FFI_DEBUG) -#include <stdio.h> -#endif - -#ifdef FFI_DEBUG -/*@exits@*/ void ffi_assert(/*@temp@*/ char *expr, /*@temp@*/ char *file, int line); -void ffi_stop_here(void); -void ffi_type_test(/*@temp@*/ /*@out@*/ ffi_type *a, /*@temp@*/ char *file, int line); - -#define FFI_ASSERT(x) ((x) ? (void)0 : ffi_assert(#x, __FILE__,__LINE__)) -#define FFI_ASSERT_AT(x, f, l) ((x) ? 0 : ffi_assert(#x, (f), (l))) -#define FFI_ASSERT_VALID_TYPE(x) ffi_type_test (x, __FILE__, __LINE__) -#else -#define FFI_ASSERT(x) -#define FFI_ASSERT_AT(x, f, l) -#define FFI_ASSERT_VALID_TYPE(x) -#endif - -#define ALIGN(v, a) (((((size_t) (v))-1) | ((a)-1))+1) - -/* Perform machine dependent cif processing */ -ffi_status ffi_prep_cif_machdep(ffi_cif *cif); - -/* Extended cif, used in callback from assembly routine */ -typedef struct -{ - /*@dependent@*/ ffi_cif *cif; - /*@dependent@*/ void *rvalue; - /*@dependent@*/ void **avalue; -} extended_cif; - -/* Terse sized type definitions. */ -typedef unsigned int UINT8 __attribute__((__mode__(__QI__))); -typedef signed int SINT8 __attribute__((__mode__(__QI__))); -typedef unsigned int UINT16 __attribute__((__mode__(__HI__))); -typedef signed int SINT16 __attribute__((__mode__(__HI__))); -typedef unsigned int UINT32 __attribute__((__mode__(__SI__))); -typedef signed int SINT32 __attribute__((__mode__(__SI__))); -typedef unsigned int UINT64 __attribute__((__mode__(__DI__))); -typedef signed int SINT64 __attribute__((__mode__(__DI__))); - -typedef float FLOAT32; - - -#ifdef __cplusplus -} -#endif - -#endif - - diff --git a/c/libffi_x86_x64/fficonfig.h b/c/libffi_x86_x64/fficonfig.h deleted file mode 100644 index c14f653..0000000 --- a/c/libffi_x86_x64/fficonfig.h +++ /dev/null @@ -1,96 +0,0 @@ -/* fficonfig.h. Originally created by configure, now hand_maintained for MSVC. */ - -/* fficonfig.h. Generated automatically by configure. */ -/* fficonfig.h.in. Generated automatically from configure.in by autoheader. */ - -/* Define this for MSVC, but not for mingw32! */ -#ifdef _MSC_VER -#define __attribute__(x) /* */ -#endif -#define alloca _alloca - -/*----------------------------------------------------------------*/ - -/* Define if using alloca.c. */ -/* #undef C_ALLOCA */ - -/* 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 if you have alloca, as a function or macro. */ -#define HAVE_ALLOCA 1 - -/* Define if you have <alloca.h> and it should be used (not on Ultrix). */ -/* #define HAVE_ALLOCA_H 1 */ - -/* 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 run-time. - 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 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Define if you have the memcpy function. */ -#define HAVE_MEMCPY 1 - -/* Define if read-only mmap of a plain file works. */ -//#define HAVE_MMAP_FILE 1 - -/* Define if mmap of /dev/zero works. */ -//#define HAVE_MMAP_DEV_ZERO 1 - -/* Define if mmap with MAP_ANON(YMOUS) works. */ -//#define HAVE_MMAP_ANON 1 - -/* The number of bytes in type double */ -#define SIZEOF_DOUBLE 8 - -/* The number of bytes in type long double */ -#define SIZEOF_LONG_DOUBLE 12 - -/* Define if you have the long double type and it is bigger than a double */ -#define HAVE_LONG_DOUBLE 1 - -/* whether byteorder is bigendian */ -/* #undef WORDS_BIGENDIAN */ - -/* Define if the host machine stores words of multi-word integers in - big-endian order. */ -/* #undef HOST_WORDS_BIG_ENDIAN */ - -/* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */ -#define BYTEORDER 1234 - -/* Define if your assembler and linker support unaligned PC relative relocs. */ -/* #undef HAVE_AS_SPARC_UA_PCREL */ - -/* Define if your assembler supports .register. */ -/* #undef HAVE_AS_REGISTER_PSEUDO_OP */ - -/* Define if .eh_frame sections should be read-only. */ -/* #undef HAVE_RO_EH_FRAME */ - -/* Define to the flags needed for the .section .eh_frame directive. */ -/* #define EH_FRAME_FLAGS "aw" */ - -/* Define to the flags needed for the .section .eh_frame directive. */ -/* #define EH_FRAME_FLAGS "aw" */ - -/* Define this if you want extra debugging. */ -/* #undef FFI_DEBUG */ - -/* Define this is you do not want support for aggregate types. */ -/* #undef FFI_NO_STRUCTS */ - -/* Define this is you do not want support for the raw API. */ -/* #undef FFI_NO_RAW_API */ - -/* Define this if you are using Purify and want to suppress spurious messages. */ -/* #undef USING_PURIFY */ - diff --git a/c/libffi_x86_x64/ffitarget.h b/c/libffi_x86_x64/ffitarget.h deleted file mode 100644 index 85f5ee8..0000000 --- a/c/libffi_x86_x64/ffitarget.h +++ /dev/null @@ -1,85 +0,0 @@ -/* -----------------------------------------------------------------*-C-*- - ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. - Target configuration macros for x86 and x86-64. - - 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 CYGNUS SOLUTIONS 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 - -/* ---- System specific configurations ----------------------------------- */ - -#if defined (X86_64) && defined (__i386__) -#undef X86_64 -#define X86 -#endif - -/* ---- Generic type definitions ----------------------------------------- */ - -#ifndef LIBFFI_ASM -#ifndef _WIN64 -typedef unsigned long ffi_arg; -#else -typedef unsigned __int64 ffi_arg; -#endif -typedef signed long ffi_sarg; - -typedef enum ffi_abi { - FFI_FIRST_ABI = 0, - - /* ---- Intel x86 Win32 ---------- */ - FFI_SYSV, -#ifndef _WIN64 - FFI_STDCALL, -#endif - /* TODO: Add fastcall support for the sake of completeness */ - FFI_DEFAULT_ABI = FFI_SYSV, - - /* ---- Intel x86 and AMD x86-64 - */ -/* #if !defined(X86_WIN32) && (defined(__i386__) || defined(__x86_64__)) */ -/* FFI_SYSV, */ -/* FFI_UNIX64,*/ /* Unix variants all use the same ABI for x86-64 */ -/* #ifdef __i386__ */ -/* FFI_DEFAULT_ABI = FFI_SYSV, */ -/* #else */ -/* FFI_DEFAULT_ABI = FFI_UNIX64, */ -/* #endif */ -/* #endif */ - - FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 -} ffi_abi; -#endif - -/* ---- Definitions for closures ----------------------------------------- */ - -#define FFI_CLOSURES 1 - -#ifdef _WIN64 -#define FFI_TRAMPOLINE_SIZE 29 -#define FFI_NATIVE_RAW_API 0 -#else -#define FFI_TRAMPOLINE_SIZE 15 -#define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */ -#endif - -#endif - diff --git a/c/libffi_x86_x64/prep_cif.c b/c/libffi_x86_x64/prep_cif.c deleted file mode 100644 index df94a98..0000000 --- a/c/libffi_x86_x64/prep_cif.c +++ /dev/null @@ -1,184 +0,0 @@ -/* ----------------------------------------------------------------------- - prep_cif.c - Copyright (c) 1996, 1998 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 CYGNUS SOLUTIONS 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. - ----------------------------------------------------------------------- */ - -#include <ffi.h> -#include <ffi_common.h> -#include <stdlib.h> - - -/* Round up to FFI_SIZEOF_ARG. */ - -#define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG) - -/* Perform machine independent initialization of aggregate type - specifications. */ - -static ffi_status initialize_aggregate(/*@out@*/ ffi_type *arg) -{ - ffi_type **ptr; - - FFI_ASSERT(arg != NULL); - - /*@-usedef@*/ - - FFI_ASSERT(arg->elements != NULL); - FFI_ASSERT(arg->size == 0); - FFI_ASSERT(arg->alignment == 0); - - ptr = &(arg->elements[0]); - - while ((*ptr) != NULL) - { - if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK)) - return FFI_BAD_TYPEDEF; - - /* Perform a sanity check on the argument type */ - FFI_ASSERT_VALID_TYPE(*ptr); - - arg->size = ALIGN(arg->size, (*ptr)->alignment); - arg->size += (*ptr)->size; - - arg->alignment = (arg->alignment > (*ptr)->alignment) ? - arg->alignment : (*ptr)->alignment; - - ptr++; - } - - /* Structure size includes tail padding. This is important for - structures that fit in one register on ABIs like the PowerPC64 - Linux ABI that right justify small structs in a register. - It's also needed for nested structure layout, for example - struct A { long a; char b; }; struct B { struct A x; char y; }; - should find y at an offset of 2*sizeof(long) and result in a - total size of 3*sizeof(long). */ - arg->size = ALIGN (arg->size, arg->alignment); - - if (arg->size == 0) - return FFI_BAD_TYPEDEF; - else - return FFI_OK; - - /*@=usedef@*/ -} - -/* Perform machine independent ffi_cif preparation, then call - machine dependent routine. */ - -ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif, - ffi_abi abi, unsigned int nargs, - /*@dependent@*/ /*@out@*/ /*@partial@*/ ffi_type *rtype, - /*@dependent@*/ ffi_type **atypes) -{ - unsigned bytes = 0; - unsigned int i; - ffi_type **ptr; - - FFI_ASSERT(cif != NULL); - FFI_ASSERT((abi > FFI_FIRST_ABI) && (abi <= FFI_DEFAULT_ABI)); - - cif->abi = abi; - cif->arg_types = atypes; - cif->nargs = nargs; - cif->rtype = rtype; - - cif->flags = 0; - - /* Initialize the return type if necessary */ - /*@-usedef@*/ - if ((cif->rtype->size == 0) && (initialize_aggregate(cif->rtype) != FFI_OK)) - return FFI_BAD_TYPEDEF; - /*@=usedef@*/ - - /* Perform a sanity check on the return type */ - FFI_ASSERT_VALID_TYPE(cif->rtype); - - /* x86-64 and s390 stack space allocation is handled in prep_machdep. */ -#if !defined M68K && !defined __x86_64__ && !defined S390 - /* Make space for the return structure pointer */ - if (cif->rtype->type == FFI_TYPE_STRUCT -#ifdef _WIN32 - && (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) -#endif - ) - bytes = STACK_ARG_SIZE(sizeof(void*)); -#endif - - for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) - { - - /* Initialize any uninitialized aggregate type definitions */ - if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK)) - return FFI_BAD_TYPEDEF; - - /* Perform a sanity check on the argument type, do this - check after the initialization. */ - FFI_ASSERT_VALID_TYPE(*ptr); - -#if !defined __x86_64__ && !defined S390 -#ifdef SPARC - if (((*ptr)->type == FFI_TYPE_STRUCT - && ((*ptr)->size > 16 || cif->abi != FFI_V9)) - || ((*ptr)->type == FFI_TYPE_LONGDOUBLE - && cif->abi != FFI_V9)) - bytes += sizeof(void*); - else -#endif - { -#if !defined(_MSC_VER) && !defined(__MINGW32__) - /* Don't know if this is a libffi bug or not. At least on - Windows with MSVC, function call parameters are *not* - aligned in the same way as structure fields are, they are - only aligned in integer boundaries. - - This doesn't do any harm for cdecl functions and closures, - since the caller cleans up the stack, but it is wrong for - stdcall functions where the callee cleans. - */ - - /* Add any padding if necessary */ - if (((*ptr)->alignment - 1) & bytes) - bytes = ALIGN(bytes, (*ptr)->alignment); - -#endif - bytes += STACK_ARG_SIZE((*ptr)->size); - } -#endif - } - -#ifdef _WIN64 - /* Function call needs at least 40 bytes stack size, on win64 AMD64 */ - if (bytes < 40) - bytes = 40; -#endif - - cif->bytes = bytes; - - /* Perform machine dependent cif processing */ - return ffi_prep_cif_machdep(cif); -} diff --git a/c/libffi_x86_x64/types.c b/c/libffi_x86_x64/types.c deleted file mode 100644 index 4433ac2..0000000 --- a/c/libffi_x86_x64/types.c +++ /dev/null @@ -1,104 +0,0 @@ -/* ----------------------------------------------------------------------- - types.c - Copyright (c) 1996, 1998 Red Hat, Inc. - - Predefined ffi_types needed by libffi. - - 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 CYGNUS SOLUTIONS 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. - ----------------------------------------------------------------------- */ - -#include <ffi.h> -#include <ffi_common.h> - -/* Type definitions */ - -#define FFI_INTEGRAL_TYPEDEF(n, s, a, t) ffi_type ffi_type_##n = { s, a, t, NULL } -#define FFI_AGGREGATE_TYPEDEF(n, e) ffi_type ffi_type_##n = { 0, 0, FFI_TYPE_STRUCT, e } - -/* Size and alignment are fake here. They must not be 0. */ -FFI_INTEGRAL_TYPEDEF(void, 1, 1, FFI_TYPE_VOID); - -FFI_INTEGRAL_TYPEDEF(uint8, 1, 1, FFI_TYPE_UINT8); -FFI_INTEGRAL_TYPEDEF(sint8, 1, 1, FFI_TYPE_SINT8); -FFI_INTEGRAL_TYPEDEF(uint16, 2, 2, FFI_TYPE_UINT16); -FFI_INTEGRAL_TYPEDEF(sint16, 2, 2, FFI_TYPE_SINT16); -FFI_INTEGRAL_TYPEDEF(uint32, 4, 4, FFI_TYPE_UINT32); -FFI_INTEGRAL_TYPEDEF(sint32, 4, 4, FFI_TYPE_SINT32); -FFI_INTEGRAL_TYPEDEF(float, 4, 4, FFI_TYPE_FLOAT); - -#if defined ALPHA || defined SPARC64 || defined X86_64 || defined S390X \ - || defined IA64 || defined _WIN64 - -FFI_INTEGRAL_TYPEDEF(pointer, 8, 8, FFI_TYPE_POINTER); - -#else - -FFI_INTEGRAL_TYPEDEF(pointer, 4, 4, FFI_TYPE_POINTER); - -#endif - -#if defined X86 || defined X86_WIN32 || defined ARM || defined M68K - -FFI_INTEGRAL_TYPEDEF(uint64, 8, 4, FFI_TYPE_UINT64); -FFI_INTEGRAL_TYPEDEF(sint64, 8, 4, FFI_TYPE_SINT64); - -#elif defined SH - -FFI_INTEGRAL_TYPEDEF(uint64, 8, 4, FFI_TYPE_UINT64); -FFI_INTEGRAL_TYPEDEF(sint64, 8, 4, FFI_TYPE_SINT64); - -#else - -FFI_INTEGRAL_TYPEDEF(uint64, 8, 8, FFI_TYPE_UINT64); -FFI_INTEGRAL_TYPEDEF(sint64, 8, 8, FFI_TYPE_SINT64); - -#endif - - -#if defined X86 || defined X86_WIN32 || defined M68K - -FFI_INTEGRAL_TYPEDEF(double, 8, 4, FFI_TYPE_DOUBLE); -FFI_INTEGRAL_TYPEDEF(longdouble, 12, 4, FFI_TYPE_LONGDOUBLE); - -#elif defined ARM || defined SH || defined POWERPC_AIX || defined POWERPC_DARWIN - -FFI_INTEGRAL_TYPEDEF(double, 8, 4, FFI_TYPE_DOUBLE); -FFI_INTEGRAL_TYPEDEF(longdouble, 8, 4, FFI_TYPE_LONGDOUBLE); - -#elif defined SPARC - -FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE); -#ifdef SPARC64 -FFI_INTEGRAL_TYPEDEF(longdouble, 16, 16, FFI_TYPE_LONGDOUBLE); -#else -FFI_INTEGRAL_TYPEDEF(longdouble, 16, 8, FFI_TYPE_LONGDOUBLE); -#endif - -#elif defined X86_64 - -FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE); -FFI_INTEGRAL_TYPEDEF(longdouble, 16, 16, FFI_TYPE_LONGDOUBLE); - -#else - -FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE); -FFI_INTEGRAL_TYPEDEF(longdouble, 8, 8, FFI_TYPE_LONGDOUBLE); - -#endif - diff --git a/c/libffi_x86_x64/win32.c b/c/libffi_x86_x64/win32.c deleted file mode 100644 index d1149a8..0000000 --- a/c/libffi_x86_x64/win32.c +++ /dev/null @@ -1,162 +0,0 @@ -/* ----------------------------------------------------------------------- - win32.S - Copyright (c) 1996, 1998, 2001, 2002 Red Hat, Inc. - Copyright (c) 2001 John Beniton - Copyright (c) 2002 Ranjit Mathew - - - X86 Foreign Function Interface - - 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 CYGNUS SOLUTIONS 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. - ----------------------------------------------------------------------- */ - -/* theller: almost verbatim translation from gas syntax to MSVC inline - assembler code. */ - -/* theller: ffi_call_x86 now returns an integer - the difference of the stack - pointer before and after the function call. If everything is ok, zero is - returned. If stdcall functions are passed the wrong number of arguments, - the difference will be nonzero. */ - -#include <ffi.h> -#include <ffi_common.h> - -__declspec(naked) int -ffi_call_x86(void (* prepfunc)(char *, extended_cif *), /* 8 */ - extended_cif *ecif, /* 12 */ - unsigned bytes, /* 16 */ - unsigned flags, /* 20 */ - unsigned *rvalue, /* 24 */ - void (*fn)()) /* 28 */ -{ - _asm { - push ebp - mov ebp, esp - - push esi // NEW: this register must be preserved across function calls -// XXX SAVE ESP NOW! - mov esi, esp // save stack pointer before the call - -// Make room for all of the new args. - mov ecx, [ebp+16] - sub esp, ecx // sub esp, bytes - - mov eax, esp - -// Place all of the ffi_prep_args in position - push [ebp + 12] // ecif - push eax - call [ebp + 8] // prepfunc - -// Return stack to previous state and call the function - add esp, 8 -// FIXME: Align the stack to a 128-bit boundary to avoid -// potential performance hits. - call [ebp + 28] - -// Load ecif->cif->abi - mov ecx, [ebp + 12] - mov ecx, [ecx]ecif.cif - mov ecx, [ecx]ecif.cif.abi - - cmp ecx, FFI_STDCALL - je noclean -// STDCALL: Remove the space we pushed for the args - mov ecx, [ebp + 16] - add esp, ecx -// CDECL: Caller has already cleaned the stack -noclean: -// Check that esp has the same value as before! - sub esi, esp - -// Load %ecx with the return type code - mov ecx, [ebp + 20] - -// If the return value pointer is NULL, assume no return value. -/* - Intel asm is weird. We have to explicitely specify 'DWORD PTR' in the nexr instruction, - otherwise only one BYTE will be compared (instead of a DWORD)! - */ - cmp DWORD PTR [ebp + 24], 0 - jne sc_retint - -// Even if there is no space for the return value, we are -// obliged to handle floating-point values. - cmp ecx, FFI_TYPE_FLOAT - jne sc_noretval -// fstp %st(0) - fstp st(0) - - jmp sc_epilogue - -sc_retint: - cmp ecx, FFI_TYPE_INT - jne sc_retfloat -// # Load %ecx with the pointer to storage for the return value - mov ecx, [ebp + 24] - mov [ecx + 0], eax - jmp sc_epilogue - -sc_retfloat: - cmp ecx, FFI_TYPE_FLOAT - jne sc_retdouble -// Load %ecx with the pointer to storage for the return value - mov ecx, [ebp+24] -// fstps (%ecx) - fstp DWORD PTR [ecx] - jmp sc_epilogue - -sc_retdouble: - cmp ecx, FFI_TYPE_DOUBLE - jne sc_retlongdouble -// movl 24(%ebp),%ecx - mov ecx, [ebp+24] - fstp QWORD PTR [ecx] - jmp sc_epilogue - - jmp sc_retlongdouble // avoid warning about unused label -sc_retlongdouble: - cmp ecx, FFI_TYPE_LONGDOUBLE - jne sc_retint64 -// Load %ecx with the pointer to storage for the return value - mov ecx, [ebp+24] -// fstpt (%ecx) - fstp QWORD PTR [ecx] /* XXX ??? */ - jmp sc_epilogue - -sc_retint64: - cmp ecx, FFI_TYPE_SINT64 - jne sc_retstruct -// Load %ecx with the pointer to storage for the return value - mov ecx, [ebp+24] - mov [ecx+0], eax - mov [ecx+4], edx - -sc_retstruct: -// Nothing to do! - -sc_noretval: -sc_epilogue: - mov eax, esi - pop esi // NEW restore: must be preserved across function calls - mov esp, ebp - pop ebp - ret - } -} diff --git a/c/libffi_x86_x64/win64.asm b/c/libffi_x86_x64/win64.asm deleted file mode 100644 index 301188b..0000000 --- a/c/libffi_x86_x64/win64.asm +++ /dev/null @@ -1,156 +0,0 @@ -PUBLIC ffi_call_AMD64 - -EXTRN __chkstk:NEAR -EXTRN ffi_closure_SYSV:NEAR - -_TEXT SEGMENT - -;;; ffi_closure_OUTER will be called with these registers set: -;;; rax points to 'closure' -;;; r11 contains a bit mask that specifies which of the -;;; first four parameters are float or double -;;; -;;; It must move the parameters passed in registers to their stack location, -;;; call ffi_closure_SYSV for the actual work, then return the result. -;;; -ffi_closure_OUTER PROC FRAME - ;; save actual arguments to their stack space. - test r11, 1 - jne first_is_float - mov QWORD PTR [rsp+8], rcx - jmp second -first_is_float: - movlpd QWORD PTR [rsp+8], xmm0 - -second: - test r11, 2 - jne second_is_float - mov QWORD PTR [rsp+16], rdx - jmp third -second_is_float: - movlpd QWORD PTR [rsp+16], xmm1 - -third: - test r11, 4 - jne third_is_float - mov QWORD PTR [rsp+24], r8 - jmp forth -third_is_float: - movlpd QWORD PTR [rsp+24], xmm2 - -forth: - test r11, 8 - jne forth_is_float - mov QWORD PTR [rsp+32], r9 - jmp done -forth_is_float: - movlpd QWORD PTR [rsp+32], xmm3 - -done: -.ALLOCSTACK 40 - sub rsp, 40 -.ENDPROLOG - mov rcx, rax ; context is first parameter - mov rdx, rsp ; stack is second parameter - add rdx, 40 ; correct our own area - mov rax, ffi_closure_SYSV - call rax ; call the real closure function - ;; Here, code is missing that handles float return values - add rsp, 40 - movd xmm0, rax ; In case the closure returned a float. - ret 0 -ffi_closure_OUTER ENDP - - -;;; ffi_call_AMD64 - -stack$ = 0 -prepfunc$ = 32 -ecif$ = 40 -bytes$ = 48 -flags$ = 56 -rvalue$ = 64 -fn$ = 72 - -ffi_call_AMD64 PROC FRAME - - mov QWORD PTR [rsp+32], r9 - mov QWORD PTR [rsp+24], r8 - mov QWORD PTR [rsp+16], rdx - mov QWORD PTR [rsp+8], rcx -.PUSHREG rbp - push rbp -.ALLOCSTACK 48 - sub rsp, 48 ; 00000030H -.SETFRAME rbp, 32 - lea rbp, QWORD PTR [rsp+32] -.ENDPROLOG - - mov eax, DWORD PTR bytes$[rbp] - add rax, 15 - and rax, -16 - call __chkstk - sub rsp, rax - lea rax, QWORD PTR [rsp+32] - mov QWORD PTR stack$[rbp], rax - - mov rdx, QWORD PTR ecif$[rbp] - mov rcx, QWORD PTR stack$[rbp] - call QWORD PTR prepfunc$[rbp] - - mov rsp, QWORD PTR stack$[rbp] - - movlpd xmm3, QWORD PTR [rsp+24] - movd r9, xmm3 - - movlpd xmm2, QWORD PTR [rsp+16] - movd r8, xmm2 - - movlpd xmm1, QWORD PTR [rsp+8] - movd rdx, xmm1 - - movlpd xmm0, QWORD PTR [rsp] - movd rcx, xmm0 - - call QWORD PTR fn$[rbp] -ret_int$: - cmp DWORD PTR flags$[rbp], 1 ; FFI_TYPE_INT - jne ret_float$ - - mov rcx, QWORD PTR rvalue$[rbp] - mov DWORD PTR [rcx], eax - jmp SHORT ret_nothing$ - -ret_float$: - cmp DWORD PTR flags$[rbp], 2 ; FFI_TYPE_FLOAT - jne SHORT ret_double$ - - mov rax, QWORD PTR rvalue$[rbp] - movlpd QWORD PTR [rax], xmm0 - jmp SHORT ret_nothing$ - -ret_double$: - cmp DWORD PTR flags$[rbp], 3 ; FFI_TYPE_DOUBLE - jne SHORT ret_int64$ - - mov rax, QWORD PTR rvalue$[rbp] - movlpd QWORD PTR [rax], xmm0 - jmp SHORT ret_nothing$ - -ret_int64$: - cmp DWORD PTR flags$[rbp], 12 ; FFI_TYPE_SINT64 - jne ret_nothing$ - - mov rcx, QWORD PTR rvalue$[rbp] - mov QWORD PTR [rcx], rax - jmp SHORT ret_nothing$ - -ret_nothing$: - xor eax, eax - - lea rsp, QWORD PTR [rbp+16] - pop rbp - ret 0 -ffi_call_AMD64 ENDP -_TEXT ENDS -END diff --git a/c/libffi_x86_x64/win64.obj b/c/libffi_x86_x64/win64.obj Binary files differdeleted file mode 100644 index 38d3cd1..0000000 --- a/c/libffi_x86_x64/win64.obj +++ /dev/null diff --git a/c/malloc_closure.h b/c/malloc_closure.h deleted file mode 100644 index bebb93d..0000000 --- a/c/malloc_closure.h +++ /dev/null @@ -1,176 +0,0 @@ -/* - * This file is from CPython's Modules/_ctypes/malloc_closure.c - * and has received some edits. - */ - -#include <ffi.h> -#ifdef MS_WIN32 -#include <windows.h> -#else -#include <sys/mman.h> -#include <unistd.h> -# if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) -# define MAP_ANONYMOUS MAP_ANON -# endif -#endif - -/* On PaX enable kernels that have MPROTECT enable we can't use PROT_EXEC. - - This is, apparently, an undocumented change to ffi_prep_closure(): - depending on the Linux kernel we're running on, we must give it a - mmap that is either PROT_READ|PROT_WRITE|PROT_EXEC or only - PROT_READ|PROT_WRITE. In the latter case, just trying to obtain a - mmap with PROT_READ|PROT_WRITE|PROT_EXEC would kill our process(!), - but in that situation libffi is fine with only PROT_READ|PROT_WRITE. - There is nothing in the libffi API to know that, though, so we have - to guess by parsing /proc/self/status. "Meh." - */ -#ifdef __linux__ -#include <stdlib.h> - -static int emutramp_enabled = -1; - -static int -emutramp_enabled_check (void) -{ - char *buf = NULL; - size_t len = 0; - FILE *f; - int ret; - f = fopen ("/proc/self/status", "r"); - if (f == NULL) - return 0; - ret = 0; - - while (getline (&buf, &len, f) != -1) - if (!strncmp (buf, "PaX:", 4)) - { - char emutramp; - if (sscanf (buf, "%*s %*c%c", &emutramp) == 1) - ret = (emutramp == 'E'); - break; - } - free (buf); - fclose (f); - return ret; -} - -#define is_emutramp_enabled() (emutramp_enabled >= 0 ? emutramp_enabled \ - : (emutramp_enabled = emutramp_enabled_check ())) -#else -#define is_emutramp_enabled() 0 -#endif - - -/* 'allocate_num_pages' is dynamically adjusted starting from one - page. It grows by a factor of PAGE_ALLOCATION_GROWTH_RATE. This is - meant to handle both the common case of not needing a lot of pages, - and the rare case of needing many of them. Systems in general have a - limit of how many mmap'd blocks can be open. -*/ - -#define PAGE_ALLOCATION_GROWTH_RATE 1.3 - -static Py_ssize_t allocate_num_pages = 0; - -/* #define MALLOC_CLOSURE_DEBUG */ /* enable for some debugging output */ - -/******************************************************************/ - -union mmaped_block { - ffi_closure closure; - union mmaped_block *next; -}; - -static union mmaped_block *free_list = 0; -static Py_ssize_t _pagesize = 0; - -static void more_core(void) -{ - union mmaped_block *item; - Py_ssize_t count, i; - -/* determine the pagesize */ -#ifdef MS_WIN32 - if (!_pagesize) { - SYSTEM_INFO systeminfo; - GetSystemInfo(&systeminfo); - _pagesize = systeminfo.dwPageSize; - } -#else - if (!_pagesize) { -#ifdef _SC_PAGESIZE - _pagesize = sysconf(_SC_PAGESIZE); -#else - _pagesize = getpagesize(); -#endif - } -#endif - if (_pagesize <= 0) - _pagesize = 4096; - - /* bump 'allocate_num_pages' */ - allocate_num_pages = 1 + ( - (Py_ssize_t)(allocate_num_pages * PAGE_ALLOCATION_GROWTH_RATE)); - - /* calculate the number of mmaped_blocks to allocate */ - count = (allocate_num_pages * _pagesize) / sizeof(union mmaped_block); - - /* allocate a memory block */ -#ifdef MS_WIN32 - item = (union mmaped_block *)VirtualAlloc(NULL, - count * sizeof(union mmaped_block), - MEM_COMMIT, - PAGE_EXECUTE_READWRITE); - if (item == NULL) - return; -#else - { - int prot = PROT_READ | PROT_WRITE | PROT_EXEC; - if (is_emutramp_enabled ()) - prot &= ~PROT_EXEC; - item = (union mmaped_block *)mmap(NULL, - allocate_num_pages * _pagesize, - prot, - MAP_PRIVATE | MAP_ANONYMOUS, - -1, - 0); - if (item == (void *)MAP_FAILED) - return; - } -#endif - -#ifdef MALLOC_CLOSURE_DEBUG - printf("block at %p allocated (%ld bytes), %ld mmaped_blocks\n", - item, (long)(allocate_num_pages * _pagesize), (long)count); -#endif - /* put them into the free list */ - for (i = 0; i < count; ++i) { - item->next = free_list; - free_list = item; - ++item; - } -} - -/******************************************************************/ - -/* put the item back into the free list */ -static void cffi_closure_free(ffi_closure *p) -{ - union mmaped_block *item = (union mmaped_block *)p; - item->next = free_list; - free_list = item; -} - -/* return one item from the free list, allocating more if needed */ -static ffi_closure *cffi_closure_alloc(void) -{ - union mmaped_block *item; - if (!free_list) - more_core(); - if (!free_list) - return NULL; - item = free_list; - free_list = item->next; - return &item->closure; -} diff --git a/c/minibuffer.h b/c/minibuffer.h deleted file mode 100644 index f3f5ca1..0000000 --- a/c/minibuffer.h +++ /dev/null @@ -1,408 +0,0 @@ - -/* Implementation of a C object with the 'buffer' or 'memoryview' - * interface at C-level (as approriate for the version of Python we're - * compiling for), but only a minimal but *consistent* part of the - * 'buffer' interface at application level. - */ - -typedef struct { - PyObject_HEAD - char *mb_data; - Py_ssize_t mb_size; - PyObject *mb_keepalive; - PyObject *mb_weakreflist; /* weakref support */ -} MiniBufferObj; - -static Py_ssize_t mb_length(MiniBufferObj *self) -{ - return self->mb_size; -} - -static PyObject *mb_item(MiniBufferObj *self, Py_ssize_t idx) -{ - if (idx < 0 || idx >= self->mb_size ) { - PyErr_SetString(PyExc_IndexError, "buffer index out of range"); - return NULL; - } - return PyBytes_FromStringAndSize(self->mb_data + idx, 1); -} - -static PyObject *mb_slice(MiniBufferObj *self, - Py_ssize_t left, Py_ssize_t right) -{ - Py_ssize_t size = self->mb_size; - if (left < 0) left = 0; - if (right > size) right = size; - if (left > right) left = right; - return PyBytes_FromStringAndSize(self->mb_data + left, right - left); -} - -static int mb_ass_item(MiniBufferObj *self, Py_ssize_t idx, PyObject *other) -{ - if (idx < 0 || idx >= self->mb_size) { - PyErr_SetString(PyExc_IndexError, - "buffer assignment index out of range"); - return -1; - } - if (PyBytes_Check(other) && PyBytes_GET_SIZE(other) == 1) { - self->mb_data[idx] = PyBytes_AS_STRING(other)[0]; - return 0; - } - else { - PyErr_Format(PyExc_TypeError, - "must assign a "STR_OR_BYTES - " of length 1, not %.200s", Py_TYPE(other)->tp_name); - return -1; - } -} - -/* forward: from _cffi_backend.c */ -static int _fetch_as_buffer(PyObject *x, Py_buffer *view, int writable_only); - -static int mb_ass_slice(MiniBufferObj *self, - Py_ssize_t left, Py_ssize_t right, PyObject *other) -{ - Py_ssize_t count; - Py_ssize_t size = self->mb_size; - Py_buffer src_view; - - if (_fetch_as_buffer(other, &src_view, 0) < 0) - return -1; - - if (left < 0) left = 0; - if (right > size) right = size; - if (left > right) left = right; - - count = right - left; - if (count != src_view.len) { - PyBuffer_Release(&src_view); - PyErr_SetString(PyExc_ValueError, - "right operand length must match slice length"); - return -1; - } - memcpy(self->mb_data + left, src_view.buf, count); - PyBuffer_Release(&src_view); - return 0; -} - -#if PY_MAJOR_VERSION < 3 -static Py_ssize_t mb_getdata(MiniBufferObj *self, Py_ssize_t idx, void **pp) -{ - *pp = self->mb_data; - return self->mb_size; -} - -static Py_ssize_t mb_getsegcount(MiniBufferObj *self, Py_ssize_t *lenp) -{ - if (lenp) - *lenp = self->mb_size; - return 1; -} - -static PyObject *mb_str(MiniBufferObj *self) -{ - /* Python 2: we want str(buffer) to behave like buffer[:], because - that's what bytes(buffer) does on Python 3 and there is no way - we can prevent this. */ - return PyString_FromStringAndSize(self->mb_data, self->mb_size); -} -#endif - -static int mb_getbuf(MiniBufferObj *self, Py_buffer *view, int flags) -{ - return PyBuffer_FillInfo(view, (PyObject *)self, - self->mb_data, self->mb_size, - /*readonly=*/0, flags); -} - -static PySequenceMethods mb_as_sequence = { - (lenfunc)mb_length, /*sq_length*/ - (binaryfunc)0, /*sq_concat*/ - (ssizeargfunc)0, /*sq_repeat*/ - (ssizeargfunc)mb_item, /*sq_item*/ - (ssizessizeargfunc)mb_slice, /*sq_slice*/ - (ssizeobjargproc)mb_ass_item, /*sq_ass_item*/ - (ssizessizeobjargproc)mb_ass_slice, /*sq_ass_slice*/ -}; - -static PyBufferProcs mb_as_buffer = { -#if PY_MAJOR_VERSION < 3 - (readbufferproc)mb_getdata, - (writebufferproc)mb_getdata, - (segcountproc)mb_getsegcount, - (charbufferproc)mb_getdata, -#endif - (getbufferproc)mb_getbuf, - (releasebufferproc)0, -}; - -static void -mb_dealloc(MiniBufferObj *ob) -{ - PyObject_GC_UnTrack(ob); - if (ob->mb_weakreflist != NULL) - PyObject_ClearWeakRefs((PyObject *)ob); - Py_XDECREF(ob->mb_keepalive); - Py_TYPE(ob)->tp_free((PyObject *)ob); -} - -static int -mb_traverse(MiniBufferObj *ob, visitproc visit, void *arg) -{ - Py_VISIT(ob->mb_keepalive); - return 0; -} - -static int -mb_clear(MiniBufferObj *ob) -{ - Py_CLEAR(ob->mb_keepalive); - return 0; -} - -static PyObject * -mb_richcompare(PyObject *self, PyObject *other, int op) -{ - Py_ssize_t self_size, other_size; - Py_buffer self_bytes, other_bytes; - PyObject *res; - Py_ssize_t minsize; - int cmp, rc; - - /* Bytes can be compared to anything that supports the (binary) - buffer API. Except that a comparison with Unicode is always an - error, even if the comparison is for equality. */ - rc = PyObject_IsInstance(self, (PyObject*)&PyUnicode_Type); - if (!rc) - rc = PyObject_IsInstance(other, (PyObject*)&PyUnicode_Type); - if (rc < 0) - return NULL; - if (rc) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - if (PyObject_GetBuffer(self, &self_bytes, PyBUF_SIMPLE) != 0) { - PyErr_Clear(); - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - - } - self_size = self_bytes.len; - - if (PyObject_GetBuffer(other, &other_bytes, PyBUF_SIMPLE) != 0) { - PyErr_Clear(); - PyBuffer_Release(&self_bytes); - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - - } - other_size = other_bytes.len; - - if (self_size != other_size && (op == Py_EQ || op == Py_NE)) { - /* Shortcut: if the lengths differ, the objects differ */ - cmp = (op == Py_NE); - } - else { - minsize = self_size; - if (other_size < minsize) - minsize = other_size; - - cmp = memcmp(self_bytes.buf, other_bytes.buf, minsize); - /* In ISO C, memcmp() guarantees to use unsigned bytes! */ - - if (cmp == 0) { - if (self_size < other_size) - cmp = -1; - else if (self_size > other_size) - cmp = 1; - } - - switch (op) { - case Py_LT: cmp = cmp < 0; break; - case Py_LE: cmp = cmp <= 0; break; - case Py_EQ: cmp = cmp == 0; break; - case Py_NE: cmp = cmp != 0; break; - case Py_GT: cmp = cmp > 0; break; - case Py_GE: cmp = cmp >= 0; break; - } - } - - res = cmp ? Py_True : Py_False; - PyBuffer_Release(&self_bytes); - PyBuffer_Release(&other_bytes); - Py_INCREF(res); - return res; -} - -#if PY_MAJOR_VERSION >= 3 -/* pfffffffffffff pages of copy-paste from listobject.c */ - -/* pfffffffffffff#2: the PySlice_GetIndicesEx() *macro* should not - be called, because C extension modules compiled with it differ - on ABI between 3.6.0, 3.6.1 and 3.6.2. */ -#if PY_VERSION_HEX < 0x03070000 && defined(PySlice_GetIndicesEx) && !defined(PYPY_VERSION) -#undef PySlice_GetIndicesEx -#endif - -static PyObject *mb_subscript(MiniBufferObj *self, PyObject *item) -{ - if (PyIndex_Check(item)) { - Py_ssize_t i; - i = PyNumber_AsSsize_t(item, PyExc_IndexError); - if (i == -1 && PyErr_Occurred()) - return NULL; - if (i < 0) - i += self->mb_size; - return mb_item(self, i); - } - else if (PySlice_Check(item)) { - Py_ssize_t start, stop, step, slicelength; - - if (PySlice_GetIndicesEx(item, self->mb_size, - &start, &stop, &step, &slicelength) < 0) - return NULL; - - if (step == 1) - return mb_slice(self, start, stop); - else { - PyErr_SetString(PyExc_TypeError, - "buffer doesn't support slicing with step != 1"); - return NULL; - } - } - else { - PyErr_Format(PyExc_TypeError, - "buffer indices must be integers, not %.200s", - item->ob_type->tp_name); - return NULL; - } -} -static int -mb_ass_subscript(MiniBufferObj* self, PyObject* item, PyObject* value) -{ - if (PyIndex_Check(item)) { - Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); - if (i == -1 && PyErr_Occurred()) - return -1; - if (i < 0) - i += self->mb_size; - return mb_ass_item(self, i, value); - } - else if (PySlice_Check(item)) { - Py_ssize_t start, stop, step, slicelength; - - if (PySlice_GetIndicesEx(item, self->mb_size, - &start, &stop, &step, &slicelength) < 0) { - return -1; - } - - if (step == 1) - return mb_ass_slice(self, start, stop, value); - else { - PyErr_SetString(PyExc_TypeError, - "buffer doesn't support slicing with step != 1"); - return -1; - } - } - else { - PyErr_Format(PyExc_TypeError, - "buffer indices must be integers, not %.200s", - item->ob_type->tp_name); - return -1; - } -} - -static PyMappingMethods mb_as_mapping = { - (lenfunc)mb_length, /*mp_length*/ - (binaryfunc)mb_subscript, /*mp_subscript*/ - (objobjargproc)mb_ass_subscript, /*mp_ass_subscript*/ -}; -#endif - -#if PY_MAJOR_VERSION >= 3 -# define MINIBUF_TPFLAGS 0 -#else -# define MINIBUF_TPFLAGS (Py_TPFLAGS_HAVE_GETCHARBUFFER | Py_TPFLAGS_HAVE_NEWBUFFER) -#endif - -PyDoc_STRVAR(ffi_buffer_doc, -"ffi.buffer(cdata[, byte_size]):\n" -"Return a read-write buffer object that references the raw C data\n" -"pointed to by the given 'cdata'. The 'cdata' must be a pointer or an\n" -"array. Can be passed to functions expecting a buffer, or directly\n" -"manipulated with:\n" -"\n" -" buf[:] get a copy of it in a regular string, or\n" -" buf[idx] as a single character\n" -" buf[:] = ...\n" -" buf[idx] = ... change the content"); - -static PyObject * /* forward, implemented in _cffi_backend.c */ -b_buffer_new(PyTypeObject *type, PyObject *args, PyObject *kwds); - - -static PyTypeObject MiniBuffer_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_cffi_backend.buffer", - sizeof(MiniBufferObj), - 0, - (destructor)mb_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - &mb_as_sequence, /* tp_as_sequence */ -#if PY_MAJOR_VERSION < 3 - 0, /* tp_as_mapping */ -#else - &mb_as_mapping, /* tp_as_mapping */ -#endif - 0, /* tp_hash */ - 0, /* tp_call */ -#if PY_MAJOR_VERSION < 3 - (reprfunc)mb_str, /* tp_str */ -#else - 0, /* tp_str */ -#endif - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - &mb_as_buffer, /* tp_as_buffer */ - (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - MINIBUF_TPFLAGS), /* tp_flags */ - ffi_buffer_doc, /* tp_doc */ - (traverseproc)mb_traverse, /* tp_traverse */ - (inquiry)mb_clear, /* tp_clear */ - (richcmpfunc)mb_richcompare, /* tp_richcompare */ - offsetof(MiniBufferObj, mb_weakreflist), /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - b_buffer_new, /* tp_new */ - 0, /* tp_free */ -}; - -static PyObject *minibuffer_new(char *data, Py_ssize_t size, - PyObject *keepalive) -{ - MiniBufferObj *ob = PyObject_GC_New(MiniBufferObj, &MiniBuffer_Type); - if (ob != NULL) { - ob->mb_data = data; - ob->mb_size = size; - ob->mb_keepalive = keepalive; Py_INCREF(keepalive); - ob->mb_weakreflist = NULL; - PyObject_GC_Track(ob); - } - return (PyObject *)ob; -} diff --git a/c/misc_thread_common.h b/c/misc_thread_common.h deleted file mode 100644 index 66e2835..0000000 --- a/c/misc_thread_common.h +++ /dev/null @@ -1,371 +0,0 @@ -#ifndef WITH_THREAD -# error "xxx no-thread configuration not tested, please report if you need that" -#endif -#include "pythread.h" - - -struct cffi_tls_s { - /* The current thread's ThreadCanaryObj. This is only non-null in - case cffi builds the thread state here. It remains null if this - thread had already a thread state provided by CPython. */ - struct thread_canary_s *local_thread_canary; - -#ifndef USE__THREAD - /* The saved errno. If the C compiler supports '__thread', then - we use that instead. */ - int saved_errno; -#endif - -#ifdef MS_WIN32 - /* The saved lasterror, on Windows. */ - int saved_lasterror; -#endif -}; - -static struct cffi_tls_s *get_cffi_tls(void); /* in misc_thread_posix.h - or misc_win32.h */ - - -/* We try to keep the PyThreadState around in a thread not started by - * Python but where cffi callbacks occur. If we didn't do that, then - * the standard logic in PyGILState_Ensure() and PyGILState_Release() - * would create a new PyThreadState and completely free it for every - * single call. For some applications, this is a huge slow-down. - * - * As shown by issue #362, it is quite messy to do. The current - * solution is to keep the PyThreadState alive by incrementing its - * 'gilstate_counter'. We detect thread shut-down, and we put the - * PyThreadState inside a list of zombies (we can't free it - * immediately because we don't have the GIL at that point in time). - * We also detect other pieces of code (notably Py_Finalize()) which - * clear and free PyThreadStates under our feet, using ThreadCanaryObj. - */ - -#define TLS_ZOM_LOCK() PyThread_acquire_lock(cffi_zombie_lock, WAIT_LOCK) -#define TLS_ZOM_UNLOCK() PyThread_release_lock(cffi_zombie_lock) -static PyThread_type_lock cffi_zombie_lock = NULL; - - -/* A 'canary' object is created in a thread when there is a callback - invoked, and that thread has no PyThreadState so far. It is an - object of reference count equal to 1, which is stored in the - PyThreadState->dict. Two things can occur then: - - 1. The PyThreadState can be forcefully cleared by Py_Finalize(). - Then thread_canary_dealloc() is called, and we have to cancel - the hacks we did to keep the PyThreadState alive. - - 2. The thread finishes. In that case, we put the canary in a list - of zombies, and at some convenient time later when we have the - GIL, we free all PyThreadStates in the zombie list. - - Some more fun comes from the fact that thread_canary_dealloc() can - be called at a point where the canary is in the zombie list already. - Also, the various pieces are freed at specific points in time, and - we must make sure not to access already-freed structures: - - - the struct cffi_tls_s is valid until the thread shuts down, and - then it is freed by cffi_thread_shutdown(). - - - the canary is a normal Python object, but we have a borrowed - reference to it from cffi_tls_s.local_thread_canary. - */ - -typedef struct thread_canary_s { - PyObject_HEAD - struct thread_canary_s *zombie_prev, *zombie_next; - PyThreadState *tstate; - struct cffi_tls_s *tls; -} ThreadCanaryObj; - -static PyTypeObject ThreadCanary_Type; /* forward */ -static ThreadCanaryObj cffi_zombie_head; - -static void -_thread_canary_detach_with_lock(ThreadCanaryObj *ob) -{ - /* must be called with both the GIL and TLS_ZOM_LOCK. */ - ThreadCanaryObj *p, *n; - p = ob->zombie_prev; - n = ob->zombie_next; - p->zombie_next = n; - n->zombie_prev = p; - ob->zombie_prev = NULL; - ob->zombie_next = NULL; -} - -static void -thread_canary_dealloc(ThreadCanaryObj *ob) -{ - /* this ThreadCanaryObj is being freed: if it is in the zombie - chained list, remove it. Thread-safety: 'zombie_next' amd - 'local_thread_canary' accesses need to be protected with - the TLS_ZOM_LOCK. - */ - TLS_ZOM_LOCK(); - if (ob->zombie_next != NULL) { - //fprintf(stderr, "thread_canary_dealloc(%p): ZOMBIE\n", ob); - _thread_canary_detach_with_lock(ob); - } - else { - //fprintf(stderr, "thread_canary_dealloc(%p): not a zombie\n", ob); - } - - if (ob->tls != NULL) { - //fprintf(stderr, "thread_canary_dealloc(%p): was local_thread_canary\n", ob); - assert(ob->tls->local_thread_canary == ob); - ob->tls->local_thread_canary = NULL; - } - TLS_ZOM_UNLOCK(); - - PyObject_Del((PyObject *)ob); -} - -static void -thread_canary_make_zombie(ThreadCanaryObj *ob) -{ - /* This must be called without the GIL, but with the TLS_ZOM_LOCK. - It must be called at most once for a given ThreadCanaryObj. */ - ThreadCanaryObj *last; - - //fprintf(stderr, "thread_canary_make_zombie(%p)\n", ob); - if (ob->zombie_next) - Py_FatalError("cffi: ThreadCanaryObj is already a zombie"); - last = cffi_zombie_head.zombie_prev; - ob->zombie_next = &cffi_zombie_head; - ob->zombie_prev = last; - last->zombie_next = ob; - cffi_zombie_head.zombie_prev = ob; -} - -static void -thread_canary_free_zombies(void) -{ - /* This must be called with the GIL. */ - if (cffi_zombie_head.zombie_next == &cffi_zombie_head) - return; /* fast path */ - - while (1) { - ThreadCanaryObj *ob; - PyThreadState *tstate = NULL; - - TLS_ZOM_LOCK(); - ob = cffi_zombie_head.zombie_next; - if (ob != &cffi_zombie_head) { - tstate = ob->tstate; - //fprintf(stderr, "thread_canary_free_zombie(%p) tstate=%p\n", ob, tstate); - _thread_canary_detach_with_lock(ob); - if (tstate == NULL) - Py_FatalError("cffi: invalid ThreadCanaryObj->tstate"); - } - TLS_ZOM_UNLOCK(); - - if (tstate == NULL) - break; - PyThreadState_Clear(tstate); /* calls thread_canary_dealloc on 'ob', - but now ob->zombie_next == NULL. */ - PyThreadState_Delete(tstate); - //fprintf(stderr, "thread_canary_free_zombie: cleared and deleted tstate=%p\n", tstate); - } - //fprintf(stderr, "thread_canary_free_zombie: end\n"); -} - -static void -thread_canary_register(PyThreadState *tstate) -{ - /* called with the GIL; 'tstate' is the current PyThreadState. */ - ThreadCanaryObj *canary; - PyObject *tdict; - struct cffi_tls_s *tls; - int err; - - /* first free the zombies, if any */ - thread_canary_free_zombies(); - - tls = get_cffi_tls(); - if (tls == NULL) - goto ignore_error; - - tdict = PyThreadState_GetDict(); - if (tdict == NULL) - goto ignore_error; - - canary = PyObject_New(ThreadCanaryObj, &ThreadCanary_Type); - //fprintf(stderr, "thread_canary_register(%p): tstate=%p tls=%p\n", canary, tstate, tls); - if (canary == NULL) - goto ignore_error; - canary->zombie_prev = NULL; - canary->zombie_next = NULL; - canary->tstate = tstate; - canary->tls = tls; - - err = PyDict_SetItemString(tdict, "cffi.thread.canary", (PyObject *)canary); - Py_DECREF(canary); - if (err < 0) - goto ignore_error; - - /* thread-safety: we have the GIL here, and 'tstate' is the one that - corresponds to our own thread. We are allocating a new 'canary' - and setting it up for our own thread, both in 'tdict' (which owns - the reference) and in 'tls->local_thread_canary' (which doesn't). */ - assert(Py_REFCNT(canary) == 1); - tls->local_thread_canary = canary; - tstate->gilstate_counter++; - /* ^^^ this means 'tstate' will never be automatically freed by - PyGILState_Release() */ - return; - - ignore_error: - PyErr_Clear(); -} - -static PyTypeObject ThreadCanary_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_cffi_backend.thread_canary", - sizeof(ThreadCanaryObj), - 0, - (destructor)thread_canary_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ -}; - -static void init_cffi_tls_zombie(void) -{ - cffi_zombie_head.zombie_next = &cffi_zombie_head; - cffi_zombie_head.zombie_prev = &cffi_zombie_head; - cffi_zombie_lock = PyThread_allocate_lock(); - if (cffi_zombie_lock == NULL) - PyErr_SetString(PyExc_SystemError, "can't allocate cffi_zombie_lock"); -} - -static void cffi_thread_shutdown(void *p) -{ - /* this function is called from misc_thread_posix or misc_win32 - when a thread is about to end. */ - struct cffi_tls_s *tls = (struct cffi_tls_s *)p; - - /* thread-safety: this field 'local_thread_canary' can be reset - to NULL in parallel, protected by TLS_ZOM_LOCK. */ - TLS_ZOM_LOCK(); - if (tls->local_thread_canary != NULL) { - tls->local_thread_canary->tls = NULL; - thread_canary_make_zombie(tls->local_thread_canary); - } - TLS_ZOM_UNLOCK(); - //fprintf(stderr, "thread_shutdown(%p)\n", tls); - free(tls); -} - -/* USE__THREAD is defined by setup.py if it finds that it is - syntactically valid to use "__thread" with this C compiler. */ -#ifdef USE__THREAD - -static __thread int cffi_saved_errno = 0; -static void save_errno_only(void) { cffi_saved_errno = errno; } -static void restore_errno_only(void) { errno = cffi_saved_errno; } - -#else - -static void save_errno_only(void) -{ - int saved = errno; - struct cffi_tls_s *tls = get_cffi_tls(); - if (tls != NULL) - tls->saved_errno = saved; -} - -static void restore_errno_only(void) -{ - struct cffi_tls_s *tls = get_cffi_tls(); - if (tls != NULL) - errno = tls->saved_errno; -} - -#endif - - -/* MESS. We can't use PyThreadState_GET(), because that calls - PyThreadState_Get() which fails an assert if the result is NULL. - - * in Python 2.7 and <= 3.4, the variable _PyThreadState_Current - is directly available, so use that. - - * in Python 3.5, the variable is available too, but it might be - the case that the headers don't define it (this changed in 3.5.1). - In case we're compiling with 3.5.x with x >= 1, we need to - manually define this variable. - - * in Python >= 3.6 there is _PyThreadState_UncheckedGet(). - It was added in 3.5.2 but should never be used in 3.5.x - because it is not available in 3.5.0 or 3.5.1. -*/ -#if PY_VERSION_HEX >= 0x03050100 && PY_VERSION_HEX < 0x03060000 -PyAPI_DATA(void *volatile) _PyThreadState_Current; -#endif - -static PyThreadState *get_current_ts(void) -{ -#if PY_VERSION_HEX >= 0x03060000 - return _PyThreadState_UncheckedGet(); -#elif defined(_Py_atomic_load_relaxed) - return (PyThreadState*)_Py_atomic_load_relaxed(&_PyThreadState_Current); -#else - return (PyThreadState*)_PyThreadState_Current; /* assume atomic read */ -#endif -} - -static PyGILState_STATE gil_ensure(void) -{ - /* Called at the start of a callback. Replacement for - PyGILState_Ensure(). - */ - PyGILState_STATE result; - PyThreadState *ts = PyGILState_GetThisThreadState(); - - if (ts != NULL) { - ts->gilstate_counter++; - if (ts != get_current_ts()) { - /* common case: 'ts' is our non-current thread state and - we have to make it current and acquire the GIL */ - PyEval_RestoreThread(ts); - return PyGILState_UNLOCKED; - } - else { - return PyGILState_LOCKED; - } - } - else { - /* no thread state here so far. */ - result = PyGILState_Ensure(); - assert(result == PyGILState_UNLOCKED); - - ts = PyGILState_GetThisThreadState(); - assert(ts != NULL); - assert(ts == get_current_ts()); - assert(ts->gilstate_counter >= 1); - - /* Use the ThreadCanary mechanism to keep 'ts' alive until the - thread really shuts down */ - thread_canary_register(ts); - - return result; - } -} - -static void gil_release(PyGILState_STATE oldstate) -{ - PyGILState_Release(oldstate); -} diff --git a/c/misc_thread_posix.h b/c/misc_thread_posix.h deleted file mode 100644 index bcc0177..0000000 --- a/c/misc_thread_posix.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - Logic for a better replacement of PyGILState_Ensure(). - - This version is ready to handle the case of a non-Python-started - thread in which we do a large number of calls to CFFI callbacks. If - we were to rely on PyGILState_Ensure() for that, we would constantly - be creating and destroying PyThreadStates---it is slow, and - PyThreadState_Delete() will actually walk the list of all thread - states, making it O(n). :-( - - This version only creates one PyThreadState object the first time we - see a given thread, and keep it alive until the thread is really - shut down, using a destructor on the tls key. -*/ - -#include <pthread.h> -#include "misc_thread_common.h" - - -static pthread_key_t cffi_tls_key; - -static void init_cffi_tls(void) -{ - if (pthread_key_create(&cffi_tls_key, &cffi_thread_shutdown) != 0) - PyErr_SetString(PyExc_OSError, "pthread_key_create() failed"); -} - -static struct cffi_tls_s *_make_cffi_tls(void) -{ - void *p = calloc(1, sizeof(struct cffi_tls_s)); - if (p == NULL) - return NULL; - if (pthread_setspecific(cffi_tls_key, p) != 0) { - free(p); - return NULL; - } - return p; -} - -static struct cffi_tls_s *get_cffi_tls(void) -{ - void *p = pthread_getspecific(cffi_tls_key); - if (p == NULL) - p = _make_cffi_tls(); - return (struct cffi_tls_s *)p; -} - -#define save_errno save_errno_only -#define restore_errno restore_errno_only diff --git a/c/misc_win32.h b/c/misc_win32.h deleted file mode 100644 index 156cf5d..0000000 --- a/c/misc_win32.h +++ /dev/null @@ -1,242 +0,0 @@ -#include <malloc.h> /* for alloca() */ - - -/************************************************************/ -/* errno and GetLastError support */ - -#include "misc_thread_common.h" - -static DWORD cffi_tls_index = TLS_OUT_OF_INDEXES; - -BOOL WINAPI DllMain(HINSTANCE hinstDLL, - DWORD reason_for_call, - LPVOID reserved) -{ - LPVOID p; - - switch (reason_for_call) { - - case DLL_THREAD_DETACH: - if (cffi_tls_index != TLS_OUT_OF_INDEXES) { - p = TlsGetValue(cffi_tls_index); - if (p != NULL) { - TlsSetValue(cffi_tls_index, NULL); - cffi_thread_shutdown(p); - } - } - break; - - default: - break; - } - return TRUE; -} - -static void init_cffi_tls(void) -{ - if (cffi_tls_index == TLS_OUT_OF_INDEXES) { - cffi_tls_index = TlsAlloc(); - if (cffi_tls_index == TLS_OUT_OF_INDEXES) - PyErr_SetString(PyExc_WindowsError, "TlsAlloc() failed"); - } -} - -static struct cffi_tls_s *get_cffi_tls(void) -{ - LPVOID p = TlsGetValue(cffi_tls_index); - - if (p == NULL) { - p = malloc(sizeof(struct cffi_tls_s)); - if (p == NULL) - return NULL; - memset(p, 0, sizeof(struct cffi_tls_s)); - TlsSetValue(cffi_tls_index, p); - } - return (struct cffi_tls_s *)p; -} - -#ifdef USE__THREAD -# error "unexpected USE__THREAD on Windows" -#endif - -static void save_errno(void) -{ - int current_err = errno; - int current_lasterr = GetLastError(); - struct cffi_tls_s *p = get_cffi_tls(); - if (p != NULL) { - p->saved_errno = current_err; - p->saved_lasterror = current_lasterr; - } - /* else: cannot report the error */ -} - -static void restore_errno(void) -{ - struct cffi_tls_s *p = get_cffi_tls(); - if (p != NULL) { - SetLastError(p->saved_lasterror); - errno = p->saved_errno; - } - /* else: cannot report the error */ -} - -/************************************************************/ - - -#if PY_MAJOR_VERSION >= 3 -static PyObject *b_getwinerror(PyObject *self, PyObject *args, PyObject *kwds) -{ - int err = -1; - int len; - WCHAR *s_buf = NULL; /* Free via LocalFree */ - PyObject *v, *message; - static char *keywords[] = {"code", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", keywords, &err)) - return NULL; - - if (err == -1) { - struct cffi_tls_s *p = get_cffi_tls(); - if (p == NULL) - return PyErr_NoMemory(); - err = p->saved_lasterror; - } - - len = FormatMessageW( - /* Error API error */ - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, /* no message source */ - err, - MAKELANGID(LANG_NEUTRAL, - SUBLANG_DEFAULT), /* Default language */ - (LPWSTR) &s_buf, - 0, /* size not used */ - NULL); /* no args */ - if (len==0) { - /* Only seen this in out of mem situations */ - message = PyUnicode_FromFormat("Windows Error 0x%X", err); - } else { - /* remove trailing cr/lf and dots */ - while (len > 0 && (s_buf[len-1] <= L' ' || s_buf[len-1] == L'.')) - s_buf[--len] = L'\0'; - message = PyUnicode_FromWideChar(s_buf, len); - } - if (message != NULL) { - v = Py_BuildValue("(iO)", err, message); - Py_DECREF(message); - } - else - v = NULL; - LocalFree(s_buf); - return v; -} -#else -static PyObject *b_getwinerror(PyObject *self, PyObject *args, PyObject *kwds) -{ - int err = -1; - int len; - char *s; - char *s_buf = NULL; /* Free via LocalFree */ - char s_small_buf[40]; /* Room for "Windows Error 0xFFFFFFFFFFFFFFFF" */ - PyObject *v; - static char *keywords[] = {"code", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", keywords, &err)) - return NULL; - - if (err == -1) { - struct cffi_tls_s *p = get_cffi_tls(); - if (p == NULL) - return PyErr_NoMemory(); - err = p->saved_lasterror; - } - - len = FormatMessage( - /* Error API error */ - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, /* no message source */ - err, - MAKELANGID(LANG_NEUTRAL, - SUBLANG_DEFAULT), /* Default language */ - (LPTSTR) &s_buf, - 0, /* size not used */ - NULL); /* no args */ - if (len==0) { - /* Only seen this in out of mem situations */ - sprintf(s_small_buf, "Windows Error 0x%X", err); - s = s_small_buf; - } else { - s = s_buf; - /* remove trailing cr/lf and dots */ - while (len > 0 && (s[len-1] <= ' ' || s[len-1] == '.')) - s[--len] = '\0'; - } - v = Py_BuildValue("(is)", err, s); - LocalFree(s_buf); - return v; -} -#endif - - -/************************************************************/ -/* Emulate dlopen()&co. from the Windows API */ - -#define RTLD_LAZY 0 -#define RTLD_NOW 0 -#define RTLD_GLOBAL 0 -#define RTLD_LOCAL 0 - -static void *dlopen(const char *filename, int flag) -{ - return (void *)LoadLibraryA(filename); -} - -static void *dlopenW(const wchar_t *filename) -{ - return (void *)LoadLibraryW(filename); -} - -static void *dlsym(void *handle, const char *symbol) -{ - void *address = GetProcAddress((HMODULE)handle, symbol); -#ifndef MS_WIN64 - if (!address) { - /* If 'symbol' is not found, then try '_symbol@N' for N in - (0, 4, 8, 12, ..., 124). Unlike ctypes, we try to do that - for any symbol, although in theory it should only be done - for __stdcall functions. - */ - int i; - char *mangled_name = alloca(1 + strlen(symbol) + 1 + 3 + 1); - if (!mangled_name) - return NULL; - for (i = 0; i < 32; i++) { - sprintf(mangled_name, "_%s@%d", symbol, i * 4); - address = GetProcAddress((HMODULE)handle, mangled_name); - if (address) - break; - } - } -#endif - return address; -} - -static int dlclose(void *handle) -{ - return FreeLibrary((HMODULE)handle) ? 0 : -1; -} - -static const char *dlerror(void) -{ - static char buf[32]; - DWORD dw = GetLastError(); - if (dw == 0) - return NULL; - sprintf(buf, "error 0x%x", (unsigned int)dw); - return buf; -} diff --git a/c/parse_c_type.c b/c/parse_c_type.c deleted file mode 100644 index 698ef64..0000000 --- a/c/parse_c_type.c +++ /dev/null @@ -1,847 +0,0 @@ -#include <stdlib.h> -#include <string.h> -#include <assert.h> -#include <errno.h> - -#define _CFFI_INTERNAL -#include "../cffi/parse_c_type.h" - - -enum token_e { - TOK_STAR='*', - TOK_OPEN_PAREN='(', - TOK_CLOSE_PAREN=')', - TOK_OPEN_BRACKET='[', - TOK_CLOSE_BRACKET=']', - TOK_COMMA=',', - - TOK_START=256, - TOK_END, - TOK_ERROR, - TOK_IDENTIFIER, - TOK_INTEGER, - TOK_DOTDOTDOT, - - /* keywords */ - TOK__BOOL, - TOK_CHAR, - TOK__COMPLEX, - TOK_CONST, - TOK_DOUBLE, - TOK_ENUM, - TOK_FLOAT, - //TOK__IMAGINARY, - TOK_INT, - TOK_LONG, - TOK_SHORT, - TOK_SIGNED, - TOK_STRUCT, - TOK_UNION, - TOK_UNSIGNED, - TOK_VOID, - TOK_VOLATILE, - - TOK_CDECL, - TOK_STDCALL, -}; - -typedef struct { - struct _cffi_parse_info_s *info; - const char *input, *p; - size_t size; // the next token is at 'p' and of length 'size' - enum token_e kind; - _cffi_opcode_t *output; - size_t output_index; -} token_t; - -static int is_space(char x) -{ - return (x == ' ' || x == '\f' || x == '\n' || x == '\r' || - x == '\t' || x == '\v'); -} - -static int is_ident_first(char x) -{ - return (('A' <= x && x <= 'Z') || ('a' <= x && x <= 'z') || x == '_' || - x == '$'); /* '$' in names is supported here, for the struct - names invented by cparser */ -} - -static int is_digit(char x) -{ - return ('0' <= x && x <= '9'); -} - -static int is_hex_digit(char x) -{ - return (('0' <= x && x <= '9') || - ('A' <= x && x <= 'F') || - ('a' <= x && x <= 'f')); -} - -static int is_ident_next(char x) -{ - return (is_ident_first(x) || is_digit(x)); -} - -static char get_following_char(token_t *tok) -{ - const char *p = tok->p + tok->size; - if (tok->kind == TOK_ERROR) - return 0; - while (is_space(*p)) - p++; - return *p; -} - -static int number_of_commas(token_t *tok) -{ - const char *p = tok->p; - int result = 0; - int nesting = 0; - while (1) { - switch (*p++) { - case ',': result += !nesting; break; - case '(': nesting++; break; - case ')': if ((--nesting) < 0) return result; break; - case 0: return result; - default: break; - } - } -} - -static void next_token(token_t *tok) -{ - const char *p = tok->p + tok->size; - if (tok->kind == TOK_ERROR) - return; - while (!is_ident_first(*p)) { - if (is_space(*p)) { - p++; - } - else if (is_digit(*p)) { - tok->kind = TOK_INTEGER; - tok->p = p; - tok->size = 1; - if (p[1] == 'x' || p[1] == 'X') - tok->size = 2; - while (is_hex_digit(p[tok->size])) - tok->size++; - return; - } - else if (p[0] == '.' && p[1] == '.' && p[2] == '.') { - tok->kind = TOK_DOTDOTDOT; - tok->p = p; - tok->size = 3; - return; - } - else if (*p) { - tok->kind = *p; - tok->p = p; - tok->size = 1; - return; - } - else { - tok->kind = TOK_END; - tok->p = p; - tok->size = 0; - return; - } - } - tok->kind = TOK_IDENTIFIER; - tok->p = p; - tok->size = 1; - while (is_ident_next(p[tok->size])) - tok->size++; - - switch (*p) { - case '_': - if (tok->size == 5 && !memcmp(p, "_Bool", 5)) tok->kind = TOK__BOOL; - if (tok->size == 7 && !memcmp(p,"__cdecl",7)) tok->kind = TOK_CDECL; - if (tok->size == 9 && !memcmp(p,"__stdcall",9))tok->kind = TOK_STDCALL; - if (tok->size == 8 && !memcmp(p,"_Complex",8)) tok->kind = TOK__COMPLEX; - break; - case 'c': - if (tok->size == 4 && !memcmp(p, "char", 4)) tok->kind = TOK_CHAR; - if (tok->size == 5 && !memcmp(p, "const", 5)) tok->kind = TOK_CONST; - break; - case 'd': - if (tok->size == 6 && !memcmp(p, "double", 6)) tok->kind = TOK_DOUBLE; - break; - case 'e': - if (tok->size == 4 && !memcmp(p, "enum", 4)) tok->kind = TOK_ENUM; - break; - case 'f': - if (tok->size == 5 && !memcmp(p, "float", 5)) tok->kind = TOK_FLOAT; - break; - case 'i': - if (tok->size == 3 && !memcmp(p, "int", 3)) tok->kind = TOK_INT; - break; - case 'l': - if (tok->size == 4 && !memcmp(p, "long", 4)) tok->kind = TOK_LONG; - break; - case 's': - if (tok->size == 5 && !memcmp(p, "short", 5)) tok->kind = TOK_SHORT; - if (tok->size == 6 && !memcmp(p, "signed", 6)) tok->kind = TOK_SIGNED; - if (tok->size == 6 && !memcmp(p, "struct", 6)) tok->kind = TOK_STRUCT; - break; - case 'u': - if (tok->size == 5 && !memcmp(p, "union", 5)) tok->kind = TOK_UNION; - if (tok->size == 8 && !memcmp(p,"unsigned",8)) tok->kind = TOK_UNSIGNED; - break; - case 'v': - if (tok->size == 4 && !memcmp(p, "void", 4)) tok->kind = TOK_VOID; - if (tok->size == 8 && !memcmp(p,"volatile",8)) tok->kind = TOK_VOLATILE; - break; - } -} - -static int parse_error(token_t *tok, const char *msg) -{ - if (tok->kind != TOK_ERROR) { - tok->kind = TOK_ERROR; - tok->info->error_location = tok->p - tok->input; - tok->info->error_message = msg; - } - return -1; -} - -static int write_ds(token_t *tok, _cffi_opcode_t ds) -{ - size_t index = tok->output_index; - if (index >= tok->info->output_size) { - parse_error(tok, "internal type complexity limit reached"); - return -1; - } - tok->output[index] = ds; - tok->output_index = index + 1; - return index; -} - -#define MAX_SSIZE_T (((size_t)-1) >> 1) - -static int parse_complete(token_t *tok); -static const char *get_common_type(const char *search, size_t search_len); -static int parse_common_type_replacement(token_t *tok, const char *replacement); - -static int parse_sequel(token_t *tok, int outer) -{ - /* Emit opcodes for the "sequel", which is the optional part of a - type declaration that follows the type name, i.e. everything - with '*', '[ ]', '( )'. Returns the entry point index pointing - the innermost opcode (the one that corresponds to the complete - type). The 'outer' argument is the index of the opcode outside - this "sequel". - */ - int check_for_grouping, abi=0; - _cffi_opcode_t result, *p_current; - - header: - switch (tok->kind) { - case TOK_STAR: - outer = write_ds(tok, _CFFI_OP(_CFFI_OP_POINTER, outer)); - next_token(tok); - goto header; - case TOK_CONST: - /* ignored for now */ - next_token(tok); - goto header; - case TOK_VOLATILE: - /* ignored for now */ - next_token(tok); - goto header; - case TOK_CDECL: - case TOK_STDCALL: - /* must be in a function; checked below */ - abi = tok->kind; - next_token(tok); - goto header; - default: - break; - } - - check_for_grouping = 1; - if (tok->kind == TOK_IDENTIFIER) { - next_token(tok); /* skip a potential variable name */ - check_for_grouping = 0; - } - - result = 0; - p_current = &result; - - while (tok->kind == TOK_OPEN_PAREN) { - next_token(tok); - - if (tok->kind == TOK_CDECL || tok->kind == TOK_STDCALL) { - abi = tok->kind; - next_token(tok); - } - - if ((check_for_grouping--) == 1 && (tok->kind == TOK_STAR || - tok->kind == TOK_CONST || - tok->kind == TOK_VOLATILE || - tok->kind == TOK_OPEN_BRACKET)) { - /* just parentheses for grouping. Use a OP_NOOP to simplify */ - int x; - assert(p_current == &result); - x = tok->output_index; - p_current = tok->output + x; - - write_ds(tok, _CFFI_OP(_CFFI_OP_NOOP, 0)); - - x = parse_sequel(tok, x); - result = _CFFI_OP(_CFFI_GETOP(0), x); - } - else { - /* function type */ - int arg_total, base_index, arg_next, flags=0; - - if (abi == TOK_STDCALL) { - flags = 2; - /* note that an ellipsis below will overwrite this flags, - which is the goal: variadic functions are always cdecl */ - } - abi = 0; - - if (tok->kind == TOK_VOID && get_following_char(tok) == ')') { - next_token(tok); - } - - /* (over-)estimate 'arg_total'. May return 1 when it is really 0 */ - arg_total = number_of_commas(tok) + 1; - - *p_current = _CFFI_OP(_CFFI_GETOP(*p_current), tok->output_index); - p_current = tok->output + tok->output_index; - - base_index = write_ds(tok, _CFFI_OP(_CFFI_OP_FUNCTION, 0)); - if (base_index < 0) - return -1; - /* reserve (arg_total + 1) slots for the arguments and the - final FUNCTION_END */ - for (arg_next = 0; arg_next <= arg_total; arg_next++) - if (write_ds(tok, _CFFI_OP(0, 0)) < 0) - return -1; - - arg_next = base_index + 1; - - if (tok->kind != TOK_CLOSE_PAREN) { - while (1) { - int arg; - _cffi_opcode_t oarg; - - if (tok->kind == TOK_DOTDOTDOT) { - flags = 1; /* ellipsis */ - next_token(tok); - break; - } - arg = parse_complete(tok); - switch (_CFFI_GETOP(tok->output[arg])) { - case _CFFI_OP_ARRAY: - case _CFFI_OP_OPEN_ARRAY: - arg = _CFFI_GETARG(tok->output[arg]); - /* fall-through */ - case _CFFI_OP_FUNCTION: - oarg = _CFFI_OP(_CFFI_OP_POINTER, arg); - break; - default: - oarg = _CFFI_OP(_CFFI_OP_NOOP, arg); - break; - } - assert(arg_next - base_index <= arg_total); - tok->output[arg_next++] = oarg; - if (tok->kind != TOK_COMMA) - break; - next_token(tok); - } - } - tok->output[arg_next] = _CFFI_OP(_CFFI_OP_FUNCTION_END, flags); - } - - if (tok->kind != TOK_CLOSE_PAREN) - return parse_error(tok, "expected ')'"); - next_token(tok); - } - - if (abi != 0) - return parse_error(tok, "expected '('"); - - while (tok->kind == TOK_OPEN_BRACKET) { - *p_current = _CFFI_OP(_CFFI_GETOP(*p_current), tok->output_index); - p_current = tok->output + tok->output_index; - - next_token(tok); - if (tok->kind != TOK_CLOSE_BRACKET) { - size_t length; - int gindex; - char *endptr; - - switch (tok->kind) { - - case TOK_INTEGER: - errno = 0; - if (sizeof(length) > sizeof(unsigned long)) { -#ifdef MS_WIN32 -# ifdef _WIN64 - length = _strtoui64(tok->p, &endptr, 0); -# else - abort(); /* unreachable */ -# endif -#else - length = strtoull(tok->p, &endptr, 0); -#endif - } - else - length = strtoul(tok->p, &endptr, 0); - if (endptr != tok->p + tok->size) - return parse_error(tok, "invalid number"); - if (errno == ERANGE || length > MAX_SSIZE_T) - return parse_error(tok, "number too large"); - break; - - case TOK_IDENTIFIER: - gindex = search_in_globals(tok->info->ctx, tok->p, tok->size); - if (gindex >= 0) { - const struct _cffi_global_s *g; - g = &tok->info->ctx->globals[gindex]; - if (_CFFI_GETOP(g->type_op) == _CFFI_OP_CONSTANT_INT || - _CFFI_GETOP(g->type_op) == _CFFI_OP_ENUM) { - int neg; - struct _cffi_getconst_s gc; - gc.ctx = tok->info->ctx; - gc.gindex = gindex; - neg = ((int(*)(struct _cffi_getconst_s*))g->address) - (&gc); - if (neg == 0 && gc.value > MAX_SSIZE_T) - return parse_error(tok, - "integer constant too large"); - if (neg == 0 || gc.value == 0) { - length = (size_t)gc.value; - break; - } - if (neg != 1) - return parse_error(tok, "disagreement about" - " this constant's value"); - } - } - /* fall-through to the default case */ - default: - return parse_error(tok, "expected a positive integer constant"); - } - - next_token(tok); - - write_ds(tok, _CFFI_OP(_CFFI_OP_ARRAY, 0)); - write_ds(tok, (_cffi_opcode_t)length); - } - else - write_ds(tok, _CFFI_OP(_CFFI_OP_OPEN_ARRAY, 0)); - - if (tok->kind != TOK_CLOSE_BRACKET) - return parse_error(tok, "expected ']'"); - next_token(tok); - } - - *p_current = _CFFI_OP(_CFFI_GETOP(*p_current), outer); - return _CFFI_GETARG(result); -} - -static int search_sorted(const char *const *base, - size_t item_size, int array_len, - const char *search, size_t search_len) -{ - int left = 0, right = array_len; - const char *baseptr = (const char *)base; - - while (left < right) { - int middle = (left + right) / 2; - const char *src = *(const char *const *)(baseptr + middle * item_size); - int diff = strncmp(src, search, search_len); - if (diff == 0 && src[search_len] == '\0') - return middle; - else if (diff >= 0) - right = middle; - else - left = middle + 1; - } - return -1; -} - -#define MAKE_SEARCH_FUNC(FIELD) \ - static \ - int search_in_##FIELD(const struct _cffi_type_context_s *ctx, \ - const char *search, size_t search_len) \ - { \ - return search_sorted(&ctx->FIELD->name, sizeof(*ctx->FIELD), \ - ctx->num_##FIELD, search, search_len); \ - } - -MAKE_SEARCH_FUNC(globals) -MAKE_SEARCH_FUNC(struct_unions) -MAKE_SEARCH_FUNC(typenames) -MAKE_SEARCH_FUNC(enums) - -#undef MAKE_SEARCH_FUNC - - -static -int search_standard_typename(const char *p, size_t size) -{ - if (size < 6 || p[size-2] != '_' || p[size-1] != 't') - return -1; - - switch (p[4]) { - - case '1': - if (size == 8 && !memcmp(p, "uint16", 6)) return _CFFI_PRIM_UINT16; - if (size == 8 && !memcmp(p, "char16", 6)) return _CFFI_PRIM_CHAR16; - break; - - case '2': - if (size == 7 && !memcmp(p, "int32", 5)) return _CFFI_PRIM_INT32; - break; - - case '3': - if (size == 8 && !memcmp(p, "uint32", 6)) return _CFFI_PRIM_UINT32; - if (size == 8 && !memcmp(p, "char32", 6)) return _CFFI_PRIM_CHAR32; - break; - - case '4': - if (size == 7 && !memcmp(p, "int64", 5)) return _CFFI_PRIM_INT64; - break; - - case '6': - if (size == 8 && !memcmp(p, "uint64", 6)) return _CFFI_PRIM_UINT64; - if (size == 7 && !memcmp(p, "int16", 5)) return _CFFI_PRIM_INT16; - break; - - case '8': - if (size == 7 && !memcmp(p, "uint8", 5)) return _CFFI_PRIM_UINT8; - break; - - case 'a': - if (size == 8 && !memcmp(p, "intmax", 6)) return _CFFI_PRIM_INTMAX; - break; - - case 'e': - if (size == 7 && !memcmp(p, "ssize", 5)) return _CFFI_PRIM_SSIZE; - break; - - case 'f': - if (size == 11 && !memcmp(p, "int_fast8", 9)) return _CFFI_PRIM_INT_FAST8; - if (size == 12 && !memcmp(p, "int_fast16", 10)) return _CFFI_PRIM_INT_FAST16; - if (size == 12 && !memcmp(p, "int_fast32", 10)) return _CFFI_PRIM_INT_FAST32; - if (size == 12 && !memcmp(p, "int_fast64", 10)) return _CFFI_PRIM_INT_FAST64; - break; - - case 'i': - if (size == 9 && !memcmp(p, "ptrdiff", 7)) return _CFFI_PRIM_PTRDIFF; - break; - - case 'l': - if (size == 12 && !memcmp(p, "int_least8", 10)) return _CFFI_PRIM_INT_LEAST8; - if (size == 13 && !memcmp(p, "int_least16", 11)) return _CFFI_PRIM_INT_LEAST16; - if (size == 13 && !memcmp(p, "int_least32", 11)) return _CFFI_PRIM_INT_LEAST32; - if (size == 13 && !memcmp(p, "int_least64", 11)) return _CFFI_PRIM_INT_LEAST64; - break; - - case 'm': - if (size == 9 && !memcmp(p, "uintmax", 7)) return _CFFI_PRIM_UINTMAX; - break; - - case 'p': - if (size == 9 && !memcmp(p, "uintptr", 7)) return _CFFI_PRIM_UINTPTR; - break; - - case 'r': - if (size == 7 && !memcmp(p, "wchar", 5)) return _CFFI_PRIM_WCHAR; - break; - - case 't': - if (size == 8 && !memcmp(p, "intptr", 6)) return _CFFI_PRIM_INTPTR; - break; - - case '_': - if (size == 6 && !memcmp(p, "size", 4)) return _CFFI_PRIM_SIZE; - if (size == 6 && !memcmp(p, "int8", 4)) return _CFFI_PRIM_INT8; - if (size >= 12) { - switch (p[10]) { - case '1': - if (size == 14 && !memcmp(p, "uint_least16", 12)) return _CFFI_PRIM_UINT_LEAST16; - break; - case '2': - if (size == 13 && !memcmp(p, "uint_fast32", 11)) return _CFFI_PRIM_UINT_FAST32; - break; - case '3': - if (size == 14 && !memcmp(p, "uint_least32", 12)) return _CFFI_PRIM_UINT_LEAST32; - break; - case '4': - if (size == 13 && !memcmp(p, "uint_fast64", 11)) return _CFFI_PRIM_UINT_FAST64; - break; - case '6': - if (size == 14 && !memcmp(p, "uint_least64", 12)) return _CFFI_PRIM_UINT_LEAST64; - if (size == 13 && !memcmp(p, "uint_fast16", 11)) return _CFFI_PRIM_UINT_FAST16; - break; - case '8': - if (size == 13 && !memcmp(p, "uint_least8", 11)) return _CFFI_PRIM_UINT_LEAST8; - break; - case '_': - if (size == 12 && !memcmp(p, "uint_fast8", 10)) return _CFFI_PRIM_UINT_FAST8; - break; - default: - break; - } - } - break; - - default: - break; - } - return -1; -} - - -static int parse_complete(token_t *tok) -{ - unsigned int t0; - _cffi_opcode_t t1; - _cffi_opcode_t t1complex; - int modifiers_length, modifiers_sign; - - qualifiers: - switch (tok->kind) { - case TOK_CONST: - /* ignored for now */ - next_token(tok); - goto qualifiers; - case TOK_VOLATILE: - /* ignored for now */ - next_token(tok); - goto qualifiers; - default: - ; - } - - modifiers_length = 0; - modifiers_sign = 0; - modifiers: - switch (tok->kind) { - - case TOK_SHORT: - if (modifiers_length != 0) - return parse_error(tok, "'short' after another 'short' or 'long'"); - modifiers_length--; - next_token(tok); - goto modifiers; - - case TOK_LONG: - if (modifiers_length < 0) - return parse_error(tok, "'long' after 'short'"); - if (modifiers_length >= 2) - return parse_error(tok, "'long long long' is too long"); - modifiers_length++; - next_token(tok); - goto modifiers; - - case TOK_SIGNED: - if (modifiers_sign) - return parse_error(tok, "multiple 'signed' or 'unsigned'"); - modifiers_sign++; - next_token(tok); - goto modifiers; - - case TOK_UNSIGNED: - if (modifiers_sign) - return parse_error(tok, "multiple 'signed' or 'unsigned'"); - modifiers_sign--; - next_token(tok); - goto modifiers; - - default: - break; - } - - t1complex = 0; - - if (modifiers_length || modifiers_sign) { - - switch (tok->kind) { - - case TOK_VOID: - case TOK__BOOL: - case TOK_FLOAT: - case TOK_STRUCT: - case TOK_UNION: - case TOK_ENUM: - case TOK__COMPLEX: - return parse_error(tok, "invalid combination of types"); - - case TOK_DOUBLE: - if (modifiers_sign != 0 || modifiers_length != 1) - return parse_error(tok, "invalid combination of types"); - next_token(tok); - t0 = _CFFI_PRIM_LONGDOUBLE; - break; - - case TOK_CHAR: - if (modifiers_length != 0) - return parse_error(tok, "invalid combination of types"); - modifiers_length = -2; - /* fall-through */ - case TOK_INT: - next_token(tok); - /* fall-through */ - default: - if (modifiers_sign >= 0) - switch (modifiers_length) { - case -2: t0 = _CFFI_PRIM_SCHAR; break; - case -1: t0 = _CFFI_PRIM_SHORT; break; - case 1: t0 = _CFFI_PRIM_LONG; break; - case 2: t0 = _CFFI_PRIM_LONGLONG; break; - default: t0 = _CFFI_PRIM_INT; break; - } - else - switch (modifiers_length) { - case -2: t0 = _CFFI_PRIM_UCHAR; break; - case -1: t0 = _CFFI_PRIM_USHORT; break; - case 1: t0 = _CFFI_PRIM_ULONG; break; - case 2: t0 = _CFFI_PRIM_ULONGLONG; break; - default: t0 = _CFFI_PRIM_UINT; break; - } - } - t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, t0); - } - else { - switch (tok->kind) { - case TOK_INT: - t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_INT); - break; - case TOK_CHAR: - t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_CHAR); - break; - case TOK_VOID: - t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_VOID); - break; - case TOK__BOOL: - t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_BOOL); - break; - case TOK_FLOAT: - t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_FLOAT); - t1complex = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_FLOATCOMPLEX); - break; - case TOK_DOUBLE: - t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_DOUBLE); - t1complex = _CFFI_OP(_CFFI_OP_PRIMITIVE, _CFFI_PRIM_DOUBLECOMPLEX); - break; - case TOK_IDENTIFIER: - { - const char *replacement; - int n = search_in_typenames(tok->info->ctx, tok->p, tok->size); - if (n >= 0) { - t1 = _CFFI_OP(_CFFI_OP_TYPENAME, n); - break; - } - n = search_standard_typename(tok->p, tok->size); - if (n >= 0) { - t1 = _CFFI_OP(_CFFI_OP_PRIMITIVE, n); - break; - } - replacement = get_common_type(tok->p, tok->size); - if (replacement != NULL) { - n = parse_common_type_replacement(tok, replacement); - if (n < 0) - return parse_error(tok, "internal error, please report!"); - t1 = _CFFI_OP(_CFFI_OP_NOOP, n); - break; - } - return parse_error(tok, "undefined type name"); - } - case TOK_STRUCT: - case TOK_UNION: - { - int n, kind = tok->kind; - next_token(tok); - if (tok->kind != TOK_IDENTIFIER) - return parse_error(tok, "struct or union name expected"); - - n = search_in_struct_unions(tok->info->ctx, tok->p, tok->size); - if (n < 0) { - if (kind == TOK_STRUCT && tok->size == 8 && - !memcmp(tok->p, "_IO_FILE", 8)) - n = _CFFI__IO_FILE_STRUCT; - else - return parse_error(tok, "undefined struct/union name"); - } - else if (((tok->info->ctx->struct_unions[n].flags & _CFFI_F_UNION) - != 0) ^ (kind == TOK_UNION)) - return parse_error(tok, "wrong kind of tag: struct vs union"); - - t1 = _CFFI_OP(_CFFI_OP_STRUCT_UNION, n); - break; - } - case TOK_ENUM: - { - int n; - next_token(tok); - if (tok->kind != TOK_IDENTIFIER) - return parse_error(tok, "enum name expected"); - - n = search_in_enums(tok->info->ctx, tok->p, tok->size); - if (n < 0) - return parse_error(tok, "undefined enum name"); - - t1 = _CFFI_OP(_CFFI_OP_ENUM, n); - break; - } - default: - return parse_error(tok, "identifier expected"); - } - next_token(tok); - } - if (tok->kind == TOK__COMPLEX) - { - if (t1complex == 0) - return parse_error(tok, "_Complex type combination unsupported"); - t1 = t1complex; - next_token(tok); - } - - return parse_sequel(tok, write_ds(tok, t1)); -} - - -static -int parse_c_type_from(struct _cffi_parse_info_s *info, size_t *output_index, - const char *input) -{ - int result; - token_t token; - - token.info = info; - token.kind = TOK_START; - token.input = input; - token.p = input; - token.size = 0; - token.output = info->output; - token.output_index = *output_index; - - next_token(&token); - result = parse_complete(&token); - - *output_index = token.output_index; - if (token.kind != TOK_END) - return parse_error(&token, "unexpected symbol"); - return result; -} - -static -int parse_c_type(struct _cffi_parse_info_s *info, const char *input) -{ - size_t output_index = 0; - return parse_c_type_from(info, &output_index, input); -} - -static -int parse_common_type_replacement(token_t *tok, const char *replacement) -{ - return parse_c_type_from(tok->info, &tok->output_index, replacement); -} diff --git a/c/realize_c_type.c b/c/realize_c_type.c deleted file mode 100644 index 82629b7..0000000 --- a/c/realize_c_type.c +++ /dev/null @@ -1,820 +0,0 @@ - -typedef struct { - struct _cffi_type_context_s ctx; /* inlined substructure */ - PyObject *types_dict; - PyObject *included_ffis; - PyObject *included_libs; - PyObject *_keepalive1; - PyObject *_keepalive2; -} builder_c_t; - - -static PyObject *all_primitives[_CFFI__NUM_PRIM]; -static CTypeDescrObject *g_ct_voidp, *g_ct_chararray; - -static PyObject *build_primitive_type(int num); /* forward */ - -#define primitive_in_range(num) ((num) >= 0 && (num) < _CFFI__NUM_PRIM) -#define get_primitive_type(num) \ - ((primitive_in_range(num) && all_primitives[num] != NULL) ? \ - all_primitives[num] : build_primitive_type(num)) - -static int init_global_types_dict(PyObject *ffi_type_dict) -{ - int err; - PyObject *ct_void, *ct_char, *ct2, *pnull; - /* XXX some leaks in case these functions fail, but well, - MemoryErrors during importing an extension module are kind - of bad anyway */ - - ct_void = get_primitive_type(_CFFI_PRIM_VOID); // 'void' - if (ct_void == NULL) - return -1; - - ct2 = new_pointer_type((CTypeDescrObject *)ct_void); // 'void *' - if (ct2 == NULL) - return -1; - g_ct_voidp = (CTypeDescrObject *)ct2; - - ct_char = get_primitive_type(_CFFI_PRIM_CHAR); // 'char' - if (ct_char == NULL) - return -1; - - ct2 = new_pointer_type((CTypeDescrObject *)ct_char); // 'char *' - if (ct2 == NULL) - return -1; - - ct2 = new_array_type((CTypeDescrObject *)ct2, -1); // 'char[]' - if (ct2 == NULL) - return -1; - g_ct_chararray = (CTypeDescrObject *)ct2; - - pnull = new_simple_cdata(NULL, g_ct_voidp); - if (pnull == NULL) - return -1; - err = PyDict_SetItemString(ffi_type_dict, "NULL", pnull); - Py_DECREF(pnull); - return err; -} - -static void free_builder_c(builder_c_t *builder, int ctx_is_static) -{ - if (!ctx_is_static) { - size_t i; - const void *mem[] = {builder->ctx.types, - builder->ctx.globals, - builder->ctx.struct_unions, - //builder->ctx.fields: allocated with struct_unions - builder->ctx.enums, - builder->ctx.typenames}; - for (i = 0; i < sizeof(mem) / sizeof(*mem); i++) { - if (mem[i] != NULL) - PyMem_Free((void *)mem[i]); - } - } - Py_XDECREF(builder->included_ffis); - Py_XDECREF(builder->included_libs); - Py_XDECREF(builder->types_dict); - Py_XDECREF(builder->_keepalive1); - Py_XDECREF(builder->_keepalive2); -} - -static int init_builder_c(builder_c_t *builder, - const struct _cffi_type_context_s *ctx) -{ - PyObject *ldict = PyDict_New(); - if (ldict == NULL) - return -1; - - if (ctx) - builder->ctx = *ctx; - else - memset(&builder->ctx, 0, sizeof(builder->ctx)); - - builder->types_dict = ldict; - builder->included_ffis = NULL; - builder->included_libs = NULL; - builder->_keepalive1 = NULL; - builder->_keepalive2 = NULL; - return 0; -} - -static PyObject *build_primitive_type(int num) -{ - /* XXX too many translations between here and new_primitive_type() */ - static const char *primitive_name[] = { - NULL, - "_Bool", - "char", - "signed char", - "unsigned char", - "short", - "unsigned short", - "int", - "unsigned int", - "long", - "unsigned long", - "long long", - "unsigned long long", - "float", - "double", - "long double", - "wchar_t", - "int8_t", - "uint8_t", - "int16_t", - "uint16_t", - "int32_t", - "uint32_t", - "int64_t", - "uint64_t", - "intptr_t", - "uintptr_t", - "ptrdiff_t", - "size_t", - "ssize_t", - "int_least8_t", - "uint_least8_t", - "int_least16_t", - "uint_least16_t", - "int_least32_t", - "uint_least32_t", - "int_least64_t", - "uint_least64_t", - "int_fast8_t", - "uint_fast8_t", - "int_fast16_t", - "uint_fast16_t", - "int_fast32_t", - "uint_fast32_t", - "int_fast64_t", - "uint_fast64_t", - "intmax_t", - "uintmax_t", - "float _Complex", - "double _Complex", - "char16_t", - "char32_t", - }; - PyObject *x; - - assert(sizeof(primitive_name) == sizeof(*primitive_name) * _CFFI__NUM_PRIM); - if (num == _CFFI_PRIM_VOID) { - x = new_void_type(); - } - else if (primitive_in_range(num) && primitive_name[num] != NULL) { - x = new_primitive_type(primitive_name[num]); - } - else if (num == _CFFI__UNKNOWN_PRIM) { - PyErr_SetString(FFIError, "primitive integer type with an unexpected " - "size (or not an integer type at all)"); - return NULL; - } - else if (num == _CFFI__UNKNOWN_FLOAT_PRIM) { - PyErr_SetString(FFIError, "primitive floating-point type with an " - "unexpected size (or not a float type at all)"); - return NULL; - } - else if (num == _CFFI__UNKNOWN_LONG_DOUBLE) { - PyErr_SetString(FFIError, "primitive floating-point type is " - "'long double', not supported for now with " - "the syntax 'typedef double... xxx;'"); - return NULL; - } - else { - PyErr_Format(PyExc_NotImplementedError, "prim=%d", num); - return NULL; - } - - all_primitives[num] = x; - return x; -} - -static PyObject *realize_global_int(builder_c_t *builder, int gindex) -{ - int neg; - char got[64]; - unsigned long long value; - struct _cffi_getconst_s gc; - const struct _cffi_global_s *g = &builder->ctx.globals[gindex]; - gc.ctx = &builder->ctx; - gc.gindex = gindex; - /* note: we cast g->address to this function type; we do the same - in parse_c_type:parse_sequel() too. Note that the called function - may be declared simply with "unsigned long long *" as argument, - which is fine as it is the first field in _cffi_getconst_s. */ - assert(&gc.value == (unsigned long long *)&gc); - neg = ((int(*)(struct _cffi_getconst_s *))g->address)(&gc); - value = gc.value; - - switch (neg) { - - case 0: - if (value <= (unsigned long long)LONG_MAX) - return PyInt_FromLong((long)value); - else - return PyLong_FromUnsignedLongLong(value); - - case 1: - if ((long long)value >= (long long)LONG_MIN) - return PyInt_FromLong((long)value); - else - return PyLong_FromLongLong((long long)value); - - default: - break; - } - if (neg == 2) - sprintf(got, "%llu (0x%llx)", value, value); - else - sprintf(got, "%lld", (long long)value); - PyErr_Format(FFIError, "the C compiler says '%.200s' is equal to %s, " - "but the cdef disagrees", g->name, got); - return NULL; -} - -static CTypeDescrObject * -unwrap_fn_as_fnptr(PyObject *x) -{ - assert(PyTuple_Check(x)); - return (CTypeDescrObject *)PyTuple_GET_ITEM(x, 0); -} - -static CTypeDescrObject * -unexpected_fn_type(PyObject *x) -{ - CTypeDescrObject *ct = unwrap_fn_as_fnptr(x); - char *text1 = ct->ct_name; - char *text2 = text1 + ct->ct_name_position + 1; - assert(text2[-3] == '('); - text2[-3] = '\0'; - PyErr_Format(FFIError, "the type '%s%s' is a function type, not a " - "pointer-to-function type", text1, text2); - text2[-3] = '('; - return NULL; -} - -static PyObject * -realize_c_type_or_func(builder_c_t *builder, - _cffi_opcode_t opcodes[], int index); /* forward */ - - -/* Interpret an opcodes[] array. If opcodes == ctx->types, store all - the intermediate types back in the opcodes[]. Returns a new - reference. -*/ -static CTypeDescrObject * -realize_c_type(builder_c_t *builder, _cffi_opcode_t opcodes[], int index) -{ - PyObject *x = realize_c_type_or_func(builder, opcodes, index); - if (x == NULL || CTypeDescr_Check(x)) - return (CTypeDescrObject *)x; - else { - unexpected_fn_type(x); - Py_DECREF(x); - return NULL; - } -} - -static void _realize_name(char *target, const char *prefix, const char *srcname) -{ - /* "xyz" => "struct xyz" - "$xyz" => "xyz" - "$1" => "struct $1" - */ - if (srcname[0] == '$' && srcname[1] != '$' && - !('0' <= srcname[1] && srcname[1] <= '9')) { - strcpy(target, &srcname[1]); - } - else { - strcpy(target, prefix); - strcat(target, srcname); - } -} - -static void _unrealize_name(char *target, const char *srcname) -{ - /* reverse of _realize_name() */ - if (strncmp(srcname, "struct ", 7) == 0) { - strcpy(target, &srcname[7]); - } - else if (strncmp(srcname, "union ", 6) == 0) { - strcpy(target, &srcname[6]); - } - else if (strncmp(srcname, "enum ", 5) == 0) { - strcpy(target, &srcname[5]); - } - else { - strcpy(target, "$"); - strcat(target, srcname); - } -} - -static PyObject * /* forward */ -_fetch_external_struct_or_union(const struct _cffi_struct_union_s *s, - PyObject *included_ffis, int recursion); - -static PyObject * -_realize_c_struct_or_union(builder_c_t *builder, int sindex) -{ - PyObject *x; - _cffi_opcode_t op2; - const struct _cffi_struct_union_s *s; - - if (sindex == _CFFI__IO_FILE_STRUCT) { - /* returns a single global cached opaque type */ - static PyObject *file_struct = NULL; - if (file_struct == NULL) - file_struct = new_struct_or_union_type("FILE", - CT_STRUCT | CT_IS_FILE); - Py_XINCREF(file_struct); - return file_struct; - } - - s = &builder->ctx.struct_unions[sindex]; - op2 = builder->ctx.types[s->type_index]; - if ((((uintptr_t)op2) & 1) == 0) { - x = (PyObject *)op2; /* found already in the "primary" slot */ - Py_INCREF(x); - } - else { - CTypeDescrObject *ct = NULL; - - if (!(s->flags & _CFFI_F_EXTERNAL)) { - int flags = (s->flags & _CFFI_F_UNION) ? CT_UNION : CT_STRUCT; - char *name = alloca(8 + strlen(s->name)); - _realize_name(name, - (s->flags & _CFFI_F_UNION) ? "union " : "struct ", - s->name); - if (strcmp(name, "struct _IO_FILE") == 0) - x = _realize_c_struct_or_union(builder, _CFFI__IO_FILE_STRUCT); - else - x = new_struct_or_union_type(name, flags); - if (x == NULL) - return NULL; - - if (!(s->flags & _CFFI_F_OPAQUE)) { - assert(s->first_field_index >= 0); - ct = (CTypeDescrObject *)x; - ct->ct_size = (Py_ssize_t)s->size; - ct->ct_length = s->alignment; /* may be -1 */ - ct->ct_flags &= ~CT_IS_OPAQUE; - ct->ct_flags |= CT_LAZY_FIELD_LIST; - ct->ct_extra = builder; - } - else - assert(s->first_field_index < 0); - } - else { - assert(s->first_field_index < 0); - x = _fetch_external_struct_or_union(s, builder->included_ffis, 0); - if (x == NULL) { - if (!PyErr_Occurred()) - PyErr_Format(FFIError, "'%s %.200s' should come from " - "ffi.include() but was not found", - (s->flags & _CFFI_F_UNION) ? "union" - : "struct", s->name); - return NULL; - } - if (!(s->flags & _CFFI_F_OPAQUE)) { - if (((CTypeDescrObject *)x)->ct_flags & CT_IS_OPAQUE) { - const char *prefix = (s->flags & _CFFI_F_UNION) ? "union" - : "struct"; - PyErr_Format(PyExc_NotImplementedError, - "'%s %.200s' is opaque in the ffi.include(), " - "but no longer in the ffi doing the include " - "(workaround: don't use ffi.include() but " - "duplicate the declarations of everything " - "using %s %.200s)", - prefix, s->name, prefix, s->name); - Py_DECREF(x); - return NULL; - } - } - } - - /* Update the "primary" OP_STRUCT_UNION slot */ - assert((((uintptr_t)x) & 1) == 0); - assert(builder->ctx.types[s->type_index] == op2); - Py_INCREF(x); - builder->ctx.types[s->type_index] = x; - - if (ct != NULL && s->size == (size_t)-2) { - /* oops, this struct is unnamed and we couldn't generate - a C expression to get its size. We have to rely on - complete_struct_or_union() to compute it now. */ - if (do_realize_lazy_struct(ct) < 0) { - builder->ctx.types[s->type_index] = op2; - return NULL; - } - } - } - return x; -} - -static PyObject * -realize_c_type_or_func_now(builder_c_t *builder, _cffi_opcode_t op, - _cffi_opcode_t opcodes[], int index) -{ - PyObject *x, *y, *z; - Py_ssize_t length = -1; - - switch (_CFFI_GETOP(op)) { - - case _CFFI_OP_PRIMITIVE: - x = get_primitive_type(_CFFI_GETARG(op)); - Py_XINCREF(x); - break; - - case _CFFI_OP_POINTER: - y = realize_c_type_or_func(builder, opcodes, _CFFI_GETARG(op)); - if (y == NULL) - return NULL; - if (CTypeDescr_Check(y)) { - x = new_pointer_type((CTypeDescrObject *)y); - } - else { - assert(PyTuple_Check(y)); /* from _CFFI_OP_FUNCTION */ - x = PyTuple_GET_ITEM(y, 0); - Py_INCREF(x); - } - Py_DECREF(y); - break; - - case _CFFI_OP_ARRAY: - length = (Py_ssize_t)opcodes[index + 1]; - /* fall-through */ - case _CFFI_OP_OPEN_ARRAY: - y = (PyObject *)realize_c_type(builder, opcodes, _CFFI_GETARG(op)); - if (y == NULL) - return NULL; - z = new_pointer_type((CTypeDescrObject *)y); - Py_DECREF(y); - if (z == NULL) - return NULL; - x = new_array_type((CTypeDescrObject *)z, length); - Py_DECREF(z); - break; - - case _CFFI_OP_STRUCT_UNION: - x = _realize_c_struct_or_union(builder, _CFFI_GETARG(op)); - break; - - case _CFFI_OP_ENUM: - { - const struct _cffi_enum_s *e; - _cffi_opcode_t op2; - - e = &builder->ctx.enums[_CFFI_GETARG(op)]; - op2 = builder->ctx.types[e->type_index]; - if ((((uintptr_t)op2) & 1) == 0) { - x = (PyObject *)op2; - Py_INCREF(x); - } - else { - PyObject *enumerators = NULL, *enumvalues = NULL, *tmp; - Py_ssize_t i, j, n = 0; - const char *p; - int gindex; - PyObject *args; - PyObject *basetd = get_primitive_type(e->type_prim); - if (basetd == NULL) - return NULL; - - if (*e->enumerators != '\0') { - n++; - for (p = e->enumerators; *p != '\0'; p++) - n += (*p == ','); - } - enumerators = PyTuple_New(n); - if (enumerators == NULL) - return NULL; - - enumvalues = PyTuple_New(n); - if (enumvalues == NULL) { - Py_DECREF(enumerators); - return NULL; - } - - p = e->enumerators; - for (i = 0; i < n; i++) { - j = 0; - while (p[j] != ',' && p[j] != '\0') - j++; - tmp = PyText_FromStringAndSize(p, j); - if (tmp == NULL) - break; - PyTuple_SET_ITEM(enumerators, i, tmp); - - gindex = search_in_globals(&builder->ctx, p, j); - assert(gindex >= 0); - assert(builder->ctx.globals[gindex].type_op == - _CFFI_OP(_CFFI_OP_ENUM, -1)); - - tmp = realize_global_int(builder, gindex); - if (tmp == NULL) - break; - PyTuple_SET_ITEM(enumvalues, i, tmp); - - p += j + 1; - } - - args = NULL; - if (!PyErr_Occurred()) { - char *name = alloca(6 + strlen(e->name)); - _realize_name(name, "enum ", e->name); - args = Py_BuildValue("(sOOO)", name, enumerators, - enumvalues, basetd); - } - Py_DECREF(enumerators); - Py_DECREF(enumvalues); - if (args == NULL) - return NULL; - - x = b_new_enum_type(NULL, args); - Py_DECREF(args); - if (x == NULL) - return NULL; - - /* Update the "primary" _CFFI_OP_ENUM slot, which - may be the same or a different slot than the "current" one */ - assert((((uintptr_t)x) & 1) == 0); - assert(builder->ctx.types[e->type_index] == op2); - Py_INCREF(x); - builder->ctx.types[e->type_index] = x; - - /* Done, leave without updating the "current" slot because - it may be done already above. If not, never mind, the - next call to realize_c_type() will do it. */ - return x; - } - break; - } - - case _CFFI_OP_FUNCTION: - { - PyObject *fargs; - int i, base_index, num_args, ellipsis, abi; - - y = (PyObject *)realize_c_type(builder, opcodes, _CFFI_GETARG(op)); - if (y == NULL) - return NULL; - - base_index = index + 1; - num_args = 0; - /* note that if the arguments are already built, they have a - pointer in the 'opcodes' array, and GETOP() returns a - random even value. But OP_FUNCTION_END is odd, so the - condition below still works correctly. */ - while (_CFFI_GETOP(opcodes[base_index + num_args]) != - _CFFI_OP_FUNCTION_END) - num_args++; - - ellipsis = _CFFI_GETARG(opcodes[base_index + num_args]) & 0x01; - abi = _CFFI_GETARG(opcodes[base_index + num_args]) & 0xFE; - switch (abi) { - case 0: - abi = FFI_DEFAULT_ABI; - break; - case 2: -#if defined(MS_WIN32) && !defined(_WIN64) - abi = FFI_STDCALL; -#else - abi = FFI_DEFAULT_ABI; -#endif - break; - default: - PyErr_Format(FFIError, "abi number %d not supported", abi); - Py_DECREF(y); - return NULL; - } - - fargs = PyTuple_New(num_args); - if (fargs == NULL) { - Py_DECREF(y); - return NULL; - } - - for (i = 0; i < num_args; i++) { - z = (PyObject *)realize_c_type(builder, opcodes, base_index + i); - if (z == NULL) { - Py_DECREF(fargs); - Py_DECREF(y); - return NULL; - } - PyTuple_SET_ITEM(fargs, i, z); - } - - z = new_function_type(fargs, (CTypeDescrObject *)y, ellipsis, abi); - Py_DECREF(fargs); - Py_DECREF(y); - if (z == NULL) - return NULL; - - x = PyTuple_Pack(1, z); /* hack: hide the CT_FUNCTIONPTR. it will - be revealed again by the OP_POINTER */ - Py_DECREF(z); - break; - } - - case _CFFI_OP_NOOP: - x = realize_c_type_or_func(builder, opcodes, _CFFI_GETARG(op)); - break; - - case _CFFI_OP_TYPENAME: - { - /* essential: the TYPENAME opcode resolves the type index looked - up in the 'ctx->typenames' array, but it does so in 'ctx->types' - instead of in 'opcodes'! */ - int type_index = builder->ctx.typenames[_CFFI_GETARG(op)].type_index; - x = realize_c_type_or_func(builder, builder->ctx.types, type_index); - break; - } - - default: - PyErr_Format(PyExc_NotImplementedError, "op=%d", (int)_CFFI_GETOP(op)); - 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); - Py_INCREF(x); - opcodes[index] = x; - } - return x; -} - -static CTypeDescrObject * -realize_c_func_return_type(builder_c_t *builder, - _cffi_opcode_t opcodes[], int index) -{ - PyObject *x; - _cffi_opcode_t op = opcodes[index]; - - if ((((uintptr_t)op) & 1) == 0) { - /* already built: assert that it is a function and fish - for the return type */ - x = (PyObject *)op; - assert(PyTuple_Check(x)); /* from _CFFI_OP_FUNCTION */ - x = PyTuple_GET_ITEM(x, 0); - assert(CTypeDescr_Check(x)); - assert(((CTypeDescrObject *)x)->ct_flags & CT_FUNCTIONPTR); - x = PyTuple_GET_ITEM(((CTypeDescrObject *)x)->ct_stuff, 1); - assert(CTypeDescr_Check(x)); - Py_INCREF(x); - return (CTypeDescrObject *)x; - } - else { - assert(_CFFI_GETOP(op) == _CFFI_OP_FUNCTION); - return realize_c_type(builder, opcodes, _CFFI_GETARG(opcodes[index])); - } -} - -static int do_realize_lazy_struct(CTypeDescrObject *ct) -{ - /* This is called by force_lazy_struct() in _cffi_backend.c */ - assert(ct->ct_flags & (CT_STRUCT | CT_UNION)); - - if (ct->ct_flags & CT_LAZY_FIELD_LIST) { - builder_c_t *builder; - char *p; - int n, i, sflags; - const struct _cffi_struct_union_s *s; - const struct _cffi_field_s *fld; - PyObject *fields, *args, *res; - - assert(!(ct->ct_flags & CT_IS_OPAQUE)); - - builder = ct->ct_extra; - assert(builder != NULL); - - p = alloca(2 + strlen(ct->ct_name)); - _unrealize_name(p, ct->ct_name); - - n = search_in_struct_unions(&builder->ctx, p, strlen(p)); - if (n < 0) - Py_FatalError("lost a struct/union!"); - - s = &builder->ctx.struct_unions[n]; - fld = &builder->ctx.fields[s->first_field_index]; - - /* XXX painfully build all the Python objects that are the args - to b_complete_struct_or_union() */ - - fields = PyList_New(s->num_fields); - if (fields == NULL) - return -1; - - for (i = 0; i < s->num_fields; i++, fld++) { - _cffi_opcode_t op = fld->field_type_op; - int fbitsize = -1; - PyObject *f; - CTypeDescrObject *ctf; - - switch (_CFFI_GETOP(op)) { - - case _CFFI_OP_BITFIELD: - assert(fld->field_size >= 0); - fbitsize = (int)fld->field_size; - /* fall-through */ - case _CFFI_OP_NOOP: - ctf = realize_c_type(builder, builder->ctx.types, - _CFFI_GETARG(op)); - break; - - default: - Py_DECREF(fields); - PyErr_Format(PyExc_NotImplementedError, "field op=%d", - (int)_CFFI_GETOP(op)); - return -1; - } - - if (ctf != NULL && fld->field_offset == (size_t)-1) { - /* unnamed struct, with field positions and sizes entirely - determined by complete_struct_or_union() and not checked. - Or, bitfields (field_size >= 0), similarly not checked. */ - assert(fld->field_size == (size_t)-1 || fbitsize >= 0); - } - else if (ctf == NULL || detect_custom_layout(ct, SF_STD_FIELD_POS, - ctf->ct_size, fld->field_size, - "wrong size for field '", - fld->name, "'") < 0) { - Py_DECREF(fields); - return -1; - } - - f = Py_BuildValue("(sOin)", fld->name, ctf, - fbitsize, (Py_ssize_t)fld->field_offset); - if (f == NULL) { - Py_DECREF(fields); - return -1; - } - PyList_SET_ITEM(fields, i, f); - } - - sflags = 0; - if (s->flags & _CFFI_F_CHECK_FIELDS) - sflags |= SF_STD_FIELD_POS; - if (s->flags & _CFFI_F_PACKED) - sflags |= SF_PACKED; - - args = Py_BuildValue("(OOOnii)", ct, fields, Py_None, - (Py_ssize_t)s->size, - s->alignment, - sflags); - Py_DECREF(fields); - if (args == NULL) - return -1; - - ct->ct_extra = NULL; - ct->ct_flags |= CT_IS_OPAQUE; - res = b_complete_struct_or_union(NULL, args); - ct->ct_flags &= ~CT_IS_OPAQUE; - Py_DECREF(args); - - if (res == NULL) { - ct->ct_extra = builder; - return -1; - } - - assert(ct->ct_stuff != NULL); - ct->ct_flags &= ~CT_LAZY_FIELD_LIST; - Py_DECREF(res); - return 1; - } - else { - assert(ct->ct_flags & CT_IS_OPAQUE); - return 0; - } -} diff --git a/c/test_c.py b/c/test_c.py deleted file mode 100644 index 654584d..0000000 --- a/c/test_c.py +++ /dev/null @@ -1,4575 +0,0 @@ -import py -import pytest - -def _setup_path(): - import os, sys - sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) -_setup_path() -from _cffi_backend import * -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.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,): - type_or_class = "type" - mandatory_b_prefix = '' - mandatory_u_prefix = 'u' - bytechr = chr - bitem2bchr = lambda x: x - class U(object): - def __add__(self, other): - return eval('u'+repr(other).replace(r'\\u', r'\u') - .replace(r'\\U', r'\U')) - u = U() - str2bytes = str - strict_compare = False -else: - type_or_class = "class" - long = int - unicode = str - unichr = chr - mandatory_b_prefix = 'b' - mandatory_u_prefix = '' - bytechr = lambda n: bytes([n]) - bitem2bchr = bytechr - u = "" - str2bytes = lambda s: bytes(s, "ascii") - strict_compare = True - -def size_of_int(): - BInt = new_primitive_type("int") - return sizeof(BInt) - -def size_of_long(): - BLong = new_primitive_type("long") - return sizeof(BLong) - -def size_of_ptr(): - BInt = new_primitive_type("int") - BPtr = new_pointer_type(BInt) - return sizeof(BPtr) - - -def find_and_load_library(name, flags=RTLD_NOW): - import ctypes.util - if name is None: - path = None - else: - path = ctypes.util.find_library(name) - if path is None and name == 'c': - assert sys.platform == 'win32' - 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(): - x = find_and_load_library('c') - assert repr(x).startswith("<clibrary '") - x = find_and_load_library('c', RTLD_NOW | RTLD_GLOBAL) - assert repr(x).startswith("<clibrary '") - x = find_and_load_library('c', RTLD_LAZY) - assert repr(x).startswith("<clibrary '") - -def test_all_rtld_symbols(): - import sys - FFI_DEFAULT_ABI # these symbols must be defined - FFI_CDECL - RTLD_LAZY - RTLD_NOW - RTLD_GLOBAL - RTLD_LOCAL - if sys.platform.startswith("linux"): - RTLD_NODELETE - RTLD_NOLOAD - RTLD_DEEPBIND - -def test_new_primitive_type(): - py.test.raises(KeyError, new_primitive_type, "foo") - p = new_primitive_type("signed char") - assert repr(p) == "<ctype 'signed char'>" - -def check_dir(p, expected): - got = [name for name in dir(p) if not name.startswith('_')] - assert got == sorted(expected) - -def test_inspect_primitive_type(): - p = new_primitive_type("signed char") - assert p.kind == "primitive" - assert p.cname == "signed char" - check_dir(p, ['cname', 'kind']) - -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._CDataBase'>" % type_or_class - assert int(x) == -65 - x = cast(p, -66 + (1<<199)*256) - assert repr(x) == "<cdata 'signed char' -66>" - assert int(x) == -66 - assert (x == cast(p, -66)) is True - assert (x != cast(p, -66)) is False - q = new_primitive_type("short") - assert (x == cast(q, -66)) is True - assert (x != cast(q, -66)) is False - -def test_sizeof_type(): - py.test.raises(TypeError, sizeof, 42.5) - p = new_primitive_type("short") - assert sizeof(p) == 2 - -def test_integer_types(): - for name in ['signed char', 'short', 'int', 'long', 'long long']: - p = new_primitive_type(name) - size = sizeof(p) - min = -(1 << (8*size-1)) - max = (1 << (8*size-1)) - 1 - assert int(cast(p, min)) == min - assert int(cast(p, max)) == max - assert int(cast(p, min - 1)) == max - assert int(cast(p, max + 1)) == min - py.test.raises(TypeError, cast, p, None) - assert long(cast(p, min - 1)) == max - assert int(cast(p, b'\x08')) == 8 - assert int(cast(p, u+'\x08')) == 8 - for name in ['char', 'short', 'int', 'long', 'long long']: - p = new_primitive_type('unsigned ' + name) - size = sizeof(p) - max = (1 << (8*size)) - 1 - assert int(cast(p, 0)) == 0 - assert int(cast(p, max)) == max - assert int(cast(p, -1)) == max - assert int(cast(p, max + 1)) == 0 - assert long(cast(p, -1)) == max - assert int(cast(p, b'\xFE')) == 254 - assert int(cast(p, u+'\xFE')) == 254 - -def test_no_float_on_int_types(): - p = new_primitive_type('long') - py.test.raises(TypeError, float, cast(p, 42)) - py.test.raises(TypeError, complex, cast(p, 42)) - -def test_float_types(): - INF = 1E200 * 1E200 - for name in ["float", "double"]: - p = new_primitive_type(name) - assert bool(cast(p, 0)) is False # since 1.7 - assert bool(cast(p, -0.0)) is False # since 1.7 - assert bool(cast(p, 1e-42)) is True - assert bool(cast(p, -1e-42)) is True - assert bool(cast(p, INF)) - assert bool(cast(p, -INF)) - assert bool(cast(p, float("nan"))) - assert int(cast(p, -150)) == -150 - assert int(cast(p, 61.91)) == 61 - assert long(cast(p, 61.91)) == 61 - assert type(int(cast(p, 61.91))) is int - assert type(int(cast(p, 1E22))) is long - assert type(long(cast(p, 61.91))) is long - assert type(long(cast(p, 1E22))) is long - py.test.raises(OverflowError, int, cast(p, INF)) - py.test.raises(OverflowError, int, cast(p, -INF)) - assert float(cast(p, 1.25)) == 1.25 - assert float(cast(p, INF)) == INF - assert float(cast(p, -INF)) == -INF - if name == "float": - assert float(cast(p, 1.1)) != 1.1 # rounding error - assert float(cast(p, 1E200)) == INF # limited range - - assert cast(p, -1.1) == cast(p, -1.1) - assert repr(float(cast(p, -0.0))) == '-0.0' - assert float(cast(p, b'\x09')) == 9.0 - assert float(cast(p, u+'\x09')) == 9.0 - assert float(cast(p, True)) == 1.0 - py.test.raises(TypeError, cast, p, None) - -def test_complex_types(): - INF = 1E200 * 1E200 - for name in ["float", "double"]: - p = new_primitive_type(name + " _Complex") - assert bool(cast(p, 0)) is False - assert bool(cast(p, INF)) - assert bool(cast(p, -INF)) - assert bool(cast(p, 0j)) is False - assert bool(cast(p, INF*1j)) - assert bool(cast(p, -INF*1j)) - # "can't convert complex to float", like CPython's "float(0j)" - py.test.raises(TypeError, int, cast(p, -150)) - py.test.raises(TypeError, long, cast(p, -150)) - py.test.raises(TypeError, float, cast(p, -150)) - assert complex(cast(p, 1.25)) == 1.25 - assert complex(cast(p, 1.25j)) == 1.25j - assert complex(cast(p, complex(0,INF))) == complex(0,INF) - assert complex(cast(p, -INF)) == -INF - if name == "float": - assert complex(cast(p, 1.1j)) != 1.1j # rounding error - assert complex(cast(p, 1E200+3j)) == INF+3j # limited range - assert complex(cast(p, complex(3,1E200))) == complex(3,INF) # limited range - - assert cast(p, -1.1j) == cast(p, -1.1j) - assert repr(complex(cast(p, -0.0)).real) == '-0.0' - #assert repr(complex(cast(p, -0j))) == '-0j' # http://bugs.python.org/issue29602 - assert complex(cast(p, b'\x09')) == 9.0 + 0j - assert complex(cast(p, u+'\x09')) == 9.0 + 0j - assert complex(cast(p, True)) == 1.0 + 0j - py.test.raises(TypeError, cast, p, None) - # - py.test.raises(TypeError, cast, new_primitive_type(name), 1+0j) - # - for basetype in ["char", "int", "uint64_t", "float", - "double", "long double"]: - baseobj = cast(new_primitive_type(basetype), 65) - py.test.raises(TypeError, complex, baseobj) - # - BArray = new_array_type(new_pointer_type(p), 10) - x = newp(BArray, None) - x[5] = 12.34 + 56.78j - assert type(x[5]) is complex - assert abs(x[5] - (12.34 + 56.78j)) < 1e-5 - assert (x[5] == 12.34 + 56.78j) == (name == "double") # rounding error - # - class Foo: - def __complex__(self): - return 2 + 3j - assert complex(Foo()) == 2 + 3j - assert complex(cast(p, Foo())) == 2 + 3j - py.test.raises(TypeError, cast, new_primitive_type("int"), 1+0j) - -def test_character_type(): - p = new_primitive_type("char") - assert bool(cast(p, 'A')) is True - assert bool(cast(p, '\x00')) is False # since 1.7 - assert cast(p, '\x00') == cast(p, -17*256) - assert int(cast(p, 'A')) == 65 - assert long(cast(p, 'A')) == 65 - assert type(int(cast(p, 'A'))) is int - assert type(long(cast(p, 'A'))) is long - assert str(cast(p, 'A')) == repr(cast(p, 'A')) - assert repr(cast(p, 'A')) == "<cdata 'char' %s'A'>" % mandatory_b_prefix - assert repr(cast(p, 255)) == r"<cdata 'char' %s'\xff'>" % mandatory_b_prefix - assert repr(cast(p, 0)) == r"<cdata 'char' %s'\x00'>" % mandatory_b_prefix - -def test_pointer_type(): - p = new_primitive_type("int") - assert repr(p) == "<ctype 'int'>" - p = new_pointer_type(p) - assert repr(p) == "<ctype 'int *'>" - p = new_pointer_type(p) - assert repr(p) == "<ctype 'int * *'>" - p = new_pointer_type(p) - assert repr(p) == "<ctype 'int * * *'>" - -def test_inspect_pointer_type(): - p1 = new_primitive_type("int") - p2 = new_pointer_type(p1) - assert p2.kind == "pointer" - assert p2.cname == "int *" - assert p2.item is p1 - check_dir(p2, ['cname', 'kind', 'item']) - p3 = new_pointer_type(p2) - assert p3.item is p2 - -def test_pointer_to_int(): - BInt = new_primitive_type("int") - py.test.raises(TypeError, newp, BInt) - py.test.raises(TypeError, newp, BInt, None) - BPtr = new_pointer_type(BInt) - p = newp(BPtr) - assert repr(p) == "<cdata 'int *' owning %d bytes>" % size_of_int() - p = newp(BPtr, None) - assert repr(p) == "<cdata 'int *' owning %d bytes>" % size_of_int() - p = newp(BPtr, 5000) - assert repr(p) == "<cdata 'int *' owning %d bytes>" % size_of_int() - q = cast(BPtr, p) - assert repr(q).startswith("<cdata 'int *' 0x") - assert p == q - assert hash(p) == hash(q) - e = py.test.raises(TypeError, newp, new_array_type(BPtr, None), None) - assert str(e.value) == ( - "expected new array length or list/tuple/str, not NoneType") - -def test_pointer_bool(): - BInt = new_primitive_type("int") - BPtr = new_pointer_type(BInt) - p = cast(BPtr, 0) - assert bool(p) is False - p = cast(BPtr, 42) - assert bool(p) is True - -def test_pointer_to_pointer(): - BInt = new_primitive_type("int") - BPtr = new_pointer_type(BInt) - BPtrPtr = new_pointer_type(BPtr) - p = newp(BPtrPtr, None) - assert repr(p) == "<cdata 'int * *' owning %d bytes>" % size_of_ptr() - -def test_reading_pointer_to_int(): - BInt = new_primitive_type("int") - BPtr = new_pointer_type(BInt) - p = newp(BPtr, None) - assert p[0] == 0 - p = newp(BPtr, 5000) - assert p[0] == 5000 - with pytest.raises(IndexError): - p[1] - with pytest.raises(IndexError): - p[-1] - -def test_reading_pointer_to_float(): - BFloat = new_primitive_type("float") - py.test.raises(TypeError, newp, BFloat, None) - BPtr = new_pointer_type(BFloat) - p = newp(BPtr, None) - assert p[0] == 0.0 and type(p[0]) is float - p = newp(BPtr, 1.25) - assert p[0] == 1.25 and type(p[0]) is float - p = newp(BPtr, 1.1) - assert p[0] != 1.1 and abs(p[0] - 1.1) < 1E-5 # rounding errors - -def test_cast_float_to_int(): - for type in ["int", "unsigned int", "long", "unsigned long", - "long long", "unsigned long long"]: - p = new_primitive_type(type) - assert int(cast(p, 4.2)) == 4 - py.test.raises(TypeError, newp, new_pointer_type(p), 4.2) - -def test_newp_integer_types(): - for name in ['signed char', 'short', 'int', 'long', 'long long']: - p = new_primitive_type(name) - pp = new_pointer_type(p) - size = sizeof(p) - min = -(1 << (8*size-1)) - max = (1 << (8*size-1)) - 1 - assert newp(pp, min)[0] == min - assert newp(pp, max)[0] == max - py.test.raises(OverflowError, newp, pp, min - 2 ** 32) - py.test.raises(OverflowError, newp, pp, min - 2 ** 64) - py.test.raises(OverflowError, newp, pp, max + 2 ** 32) - py.test.raises(OverflowError, newp, pp, max + 2 ** 64) - py.test.raises(OverflowError, newp, pp, min - 1) - py.test.raises(OverflowError, newp, pp, max + 1) - py.test.raises(OverflowError, newp, pp, min - 1 - 2 ** 32) - py.test.raises(OverflowError, newp, pp, min - 1 - 2 ** 64) - py.test.raises(OverflowError, newp, pp, max + 1) - py.test.raises(OverflowError, newp, pp, max + 1 + 2 ** 32) - py.test.raises(OverflowError, newp, pp, max + 1 + 2 ** 64) - py.test.raises(TypeError, newp, pp, 1.0) - for name in ['char', 'short', 'int', 'long', 'long long']: - p = new_primitive_type('unsigned ' + name) - pp = new_pointer_type(p) - size = sizeof(p) - max = (1 << (8*size)) - 1 - assert newp(pp, 0)[0] == 0 - assert newp(pp, max)[0] == max - py.test.raises(OverflowError, newp, pp, -1) - py.test.raises(OverflowError, newp, pp, max + 1) - -def test_reading_pointer_to_char(): - BChar = new_primitive_type("char") - py.test.raises(TypeError, newp, BChar, None) - BPtr = new_pointer_type(BChar) - p = newp(BPtr, None) - assert p[0] == b'\x00' - p = newp(BPtr, b'A') - assert p[0] == b'A' - py.test.raises(TypeError, newp, BPtr, 65) - py.test.raises(TypeError, newp, BPtr, b"foo") - py.test.raises(TypeError, newp, BPtr, u+"foo") - c = cast(BChar, b'A') - assert str(c) == repr(c) - assert int(c) == ord(b'A') - py.test.raises(TypeError, cast, BChar, b'foo') - py.test.raises(TypeError, cast, BChar, u+'foo') - e = py.test.raises(TypeError, newp, new_array_type(BPtr, None), 12.3) - assert str(e.value) == ( - "expected new array length or list/tuple/str, not float") - -def test_reading_pointer_to_pointer(): - BVoidP = new_pointer_type(new_void_type()) - BCharP = new_pointer_type(new_primitive_type("char")) - BInt = new_primitive_type("int") - BIntPtr = new_pointer_type(BInt) - BIntPtrPtr = new_pointer_type(BIntPtr) - q = newp(BIntPtr, 42) - assert q[0] == 42 - p = newp(BIntPtrPtr, None) - assert p[0] is not None - assert p[0] == cast(BVoidP, 0) - assert p[0] == cast(BCharP, 0) - assert p[0] != None - assert repr(p[0]) == "<cdata 'int *' NULL>" - p[0] = q - assert p[0] != cast(BVoidP, 0) - assert p[0] != cast(BCharP, 0) - assert p[0][0] == 42 - q[0] += 1 - assert p[0][0] == 43 - p = newp(BIntPtrPtr, q) - assert p[0][0] == 43 - -def test_load_standard_library(): - if sys.platform == "win32": - py.test.raises(OSError, find_and_load_library, None) - return - x = find_and_load_library(None) - BVoidP = new_pointer_type(new_void_type()) - assert x.load_function(BVoidP, 'strcpy') - py.test.raises(AttributeError, x.load_function, - BVoidP, 'xxx_this_function_does_not_exist') - # the next one is from 'libm', not 'libc', but we assume - # that it is already loaded too, so it should work - assert x.load_function(BVoidP, 'sqrt') - # - x.close_lib() - py.test.raises(ValueError, x.load_function, BVoidP, 'sqrt') - x.close_lib() - -def test_no_len_on_nonarray(): - p = new_primitive_type("int") - py.test.raises(TypeError, len, cast(p, 42)) - -def test_cmp_none(): - p = new_primitive_type("int") - x = cast(p, 42) - assert (x == None) is False - assert (x != None) is True - assert (x == ["hello"]) is False - assert (x != ["hello"]) is True - y = cast(p, 0) - assert (y == None) is False - -def test_invalid_indexing(): - p = new_primitive_type("int") - x = cast(p, 42) - with pytest.raises(TypeError): - x[0] - -def test_default_str(): - BChar = new_primitive_type("char") - x = cast(BChar, 42) - assert str(x) == repr(x) - BInt = new_primitive_type("int") - x = cast(BInt, 42) - assert str(x) == repr(x) - BArray = new_array_type(new_pointer_type(BInt), 10) - x = newp(BArray, None) - assert str(x) == repr(x) - -def test_default_unicode(): - BInt = new_primitive_type("int") - x = cast(BInt, 42) - assert unicode(x) == unicode(repr(x)) - BArray = new_array_type(new_pointer_type(BInt), 10) - x = newp(BArray, None) - assert unicode(x) == unicode(repr(x)) - -def test_cast_from_cdataint(): - BInt = new_primitive_type("int") - x = cast(BInt, 0) - y = cast(new_pointer_type(BInt), x) - assert bool(y) is False - # - x = cast(BInt, 42) - y = cast(BInt, x) - assert int(y) == 42 - y = cast(new_primitive_type("char"), x) - assert int(y) == 42 - y = cast(new_primitive_type("float"), x) - assert float(y) == 42.0 - # - z = cast(BInt, 42.5) - assert int(z) == 42 - z = cast(BInt, y) - assert int(z) == 42 - -def test_void_type(): - p = new_void_type() - assert p.kind == "void" - assert p.cname == "void" - check_dir(p, ['kind', 'cname']) - -def test_array_type(): - p = new_primitive_type("int") - assert repr(p) == "<ctype 'int'>" - # - py.test.raises(TypeError, new_array_type, new_pointer_type(p), "foo") - py.test.raises(ValueError, new_array_type, new_pointer_type(p), -42) - # - p1 = new_array_type(new_pointer_type(p), None) - assert repr(p1) == "<ctype 'int[]'>" - py.test.raises(ValueError, new_array_type, new_pointer_type(p1), 42) - # - p1 = new_array_type(new_pointer_type(p), 42) - p2 = new_array_type(new_pointer_type(p1), 25) - assert repr(p2) == "<ctype 'int[25][42]'>" - p2 = new_array_type(new_pointer_type(p1), None) - assert repr(p2) == "<ctype 'int[][42]'>" - # - py.test.raises(OverflowError, - new_array_type, new_pointer_type(p), sys.maxsize+1) - py.test.raises(OverflowError, - new_array_type, new_pointer_type(p), sys.maxsize // 3) - -def test_inspect_array_type(): - p = new_primitive_type("int") - p1 = new_array_type(new_pointer_type(p), None) - assert p1.kind == "array" - assert p1.cname == "int[]" - assert p1.item is p - assert p1.length is None - check_dir(p1, ['cname', 'kind', 'item', 'length']) - p1 = new_array_type(new_pointer_type(p), 42) - assert p1.kind == "array" - assert p1.cname == "int[42]" - assert p1.item is p - assert p1.length == 42 - check_dir(p1, ['cname', 'kind', 'item', 'length']) - -def test_array_instance(): - LENGTH = 1423 - p = new_primitive_type("int") - p1 = new_array_type(new_pointer_type(p), LENGTH) - a = newp(p1, None) - assert repr(a) == "<cdata 'int[%d]' owning %d bytes>" % ( - LENGTH, LENGTH * size_of_int()) - assert len(a) == LENGTH - for i in range(LENGTH): - assert a[i] == 0 - 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 - 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) - -def test_array_of_unknown_length_instance(): - p = new_primitive_type("int") - p1 = new_array_type(new_pointer_type(p), None) - py.test.raises(TypeError, newp, p1, None) - py.test.raises(ValueError, newp, p1, -42) - a = newp(p1, 42) - assert len(a) == 42 - for i in range(42): - a[i] -= i - for i in range(42): - assert a[i] == -i - 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") - p1 = new_array_type(new_pointer_type(p), None) - a = newp(p1, list(range(42))) - assert len(a) == 42 - a = newp(p1, tuple(range(142))) - assert len(a) == 142 - -def test_array_initializer(): - p = new_primitive_type("int") - p1 = new_array_type(new_pointer_type(p), None) - a = newp(p1, list(range(100, 142))) - for i in range(42): - assert a[i] == 100 + i - # - p2 = new_array_type(new_pointer_type(p), 43) - a = newp(p2, tuple(range(100, 142))) - for i in range(42): - assert a[i] == 100 + i - assert a[42] == 0 # extra uninitialized item - -def test_array_add(): - p = new_primitive_type("int") - p1 = new_array_type(new_pointer_type(p), 5) # int[5] - p2 = new_array_type(new_pointer_type(p1), 3) # int[3][5] - a = newp(p2, [list(range(n, n+5)) for n in [100, 200, 300]]) - assert repr(a) == "<cdata 'int[3][5]' owning %d bytes>" % ( - 3*5*size_of_int(),) - assert repr(a + 0).startswith("<cdata 'int(*)[5]' 0x") - assert 0 + a == a + 0 != 1 + a == a + 1 - assert repr(a[0]).startswith("<cdata 'int[5]' 0x") - assert repr((a + 0)[0]).startswith("<cdata 'int[5]' 0x") - assert repr(a[0] + 0).startswith("<cdata 'int *' 0x") - assert type(a[0][0]) is int - assert type((a[0] + 0)[0]) is int - -def test_array_sub(): - BInt = new_primitive_type("int") - BArray = new_array_type(new_pointer_type(BInt), 5) # int[5] - a = newp(BArray, None) - p = a + 1 - assert p - a == 1 - assert p - (a+0) == 1 - assert a == (p - 1) - BPtr = new_pointer_type(new_primitive_type("short")) - q = newp(BPtr, None) - 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(): - BInt = new_primitive_type("int") - BIntPtr = new_pointer_type(BInt) - a = cast(BIntPtr, 1240) - for bi in range(1430, 1438): - b = cast(BIntPtr, bi) - if ((bi - 1240) % size_of_int()) == 0: - assert b - a == (bi - 1240) // size_of_int() - assert a - b == (1240 - bi) // size_of_int() - else: - with pytest.raises(ValueError): - b - a - with pytest.raises(ValueError): - a - b - -def test_cast_primitive_from_cdata(): - p = new_primitive_type("int") - n = cast(p, cast(p, -42)) - assert int(n) == -42 - # - p = new_primitive_type("unsigned int") - n = cast(p, cast(p, 42)) - assert int(n) == 42 - # - p = new_primitive_type("long long") - n = cast(p, cast(p, -(1<<60))) - assert int(n) == -(1<<60) - # - p = new_primitive_type("unsigned long long") - n = cast(p, cast(p, 1<<63)) - assert int(n) == 1<<63 - # - p = new_primitive_type("float") - n = cast(p, cast(p, 42.5)) - assert float(n) == 42.5 - # - p = new_primitive_type("char") - n = cast(p, cast(p, "A")) - assert int(n) == ord("A") - -def test_new_primitive_from_cdata(): - p = new_primitive_type("int") - p1 = new_pointer_type(p) - n = newp(p1, cast(p, -42)) - assert n[0] == -42 - # - p = new_primitive_type("unsigned int") - p1 = new_pointer_type(p) - n = newp(p1, cast(p, 42)) - assert n[0] == 42 - # - p = new_primitive_type("float") - p1 = new_pointer_type(p) - n = newp(p1, cast(p, 42.5)) - assert n[0] == 42.5 - # - p = new_primitive_type("char") - p1 = new_pointer_type(p) - n = newp(p1, cast(p, "A")) - assert n[0] == b"A" - -def test_cast_between_pointers(): - BIntP = new_pointer_type(new_primitive_type("int")) - BIntA = new_array_type(BIntP, None) - a = newp(BIntA, [40, 41, 42, 43, 44]) - BShortP = new_pointer_type(new_primitive_type("short")) - b = cast(BShortP, a) - c = cast(BIntP, b) - assert c[3] == 43 - BLongLong = new_primitive_type("long long") - d = cast(BLongLong, c) - e = cast(BIntP, d) - assert e[3] == 43 - f = cast(BIntP, int(d)) - assert f[3] == 43 - # - b = cast(BShortP, 0) - assert not b - c = cast(BIntP, b) - assert not c - assert int(cast(BLongLong, c)) == 0 - -def test_alignof(): - BInt = new_primitive_type("int") - assert alignof(BInt) == sizeof(BInt) - BPtr = new_pointer_type(BInt) - assert alignof(BPtr) == sizeof(BPtr) - BArray = new_array_type(BPtr, None) - assert alignof(BArray) == alignof(BInt) - -def test_new_struct_type(): - BStruct = new_struct_type("foo") - assert repr(BStruct) == "<ctype 'foo'>" - BStruct = new_struct_type("struct foo") - assert repr(BStruct) == "<ctype 'struct foo'>" - BPtr = new_pointer_type(BStruct) - assert repr(BPtr) == "<ctype 'struct foo *'>" - py.test.raises(ValueError, sizeof, BStruct) - py.test.raises(ValueError, alignof, BStruct) - -def test_new_union_type(): - BUnion = new_union_type("union foo") - assert repr(BUnion) == "<ctype 'union foo'>" - BPtr = new_pointer_type(BUnion) - assert repr(BPtr) == "<ctype 'union foo *'>" - -def test_complete_struct(): - BLong = new_primitive_type("long") - BChar = new_primitive_type("char") - BShort = new_primitive_type("short") - BStruct = new_struct_type("struct foo") - assert BStruct.kind == "struct" - assert BStruct.cname == "struct foo" - assert BStruct.fields is None - check_dir(BStruct, ['cname', 'kind', 'fields']) - # - complete_struct_or_union(BStruct, [('a1', BLong, -1), - ('a2', BChar, -1), - ('a3', BShort, -1)]) - d = BStruct.fields - assert len(d) == 3 - assert d[0][0] == 'a1' - assert d[0][1].type is BLong - assert d[0][1].offset == 0 - assert d[0][1].bitshift == -1 - assert d[0][1].bitsize == -1 - assert d[1][0] == 'a2' - assert d[1][1].type is BChar - assert d[1][1].offset == sizeof(BLong) - assert d[1][1].bitshift == -1 - assert d[1][1].bitsize == -1 - assert d[2][0] == 'a3' - assert d[2][1].type is BShort - assert d[2][1].offset == sizeof(BLong) + sizeof(BShort) - assert d[2][1].bitshift == -1 - assert d[2][1].bitsize == -1 - assert sizeof(BStruct) == 2 * sizeof(BLong) - assert alignof(BStruct) == alignof(BLong) - -def test_complete_union(): - BLong = new_primitive_type("long") - BChar = new_primitive_type("char") - BUnion = new_union_type("union foo") - assert BUnion.kind == "union" - assert BUnion.cname == "union foo" - assert BUnion.fields is None - complete_struct_or_union(BUnion, [('a1', BLong, -1), - ('a2', BChar, -1)]) - d = BUnion.fields - assert len(d) == 2 - assert d[0][0] == 'a1' - assert d[0][1].type is BLong - assert d[0][1].offset == 0 - assert d[1][0] == 'a2' - assert d[1][1].type is BChar - assert d[1][1].offset == 0 - assert sizeof(BUnion) == sizeof(BLong) - assert alignof(BUnion) == alignof(BLong) - -def test_struct_instance(): - BInt = new_primitive_type("int") - BStruct = new_struct_type("struct foo") - BStructPtr = new_pointer_type(BStruct) - p = cast(BStructPtr, 42) - with pytest.raises(AttributeError) as e: - p.a1 # opaque - assert str(e.value) == ("cdata 'struct foo *' points to an opaque type: " - "cannot read fields") - 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") - - complete_struct_or_union(BStruct, [('a1', BInt, -1), - ('a2', BInt, -1)]) - p = newp(BStructPtr, None) - s = p[0] - assert s.a1 == 0 - s.a2 = 123 - assert s.a1 == 0 - assert s.a2 == 123 - with pytest.raises(OverflowError): - s.a1 = sys.maxsize+1 - assert s.a1 == 0 - with pytest.raises(AttributeError) as e: - p.foobar - assert str(e.value) == "cdata 'struct foo *' has no field 'foobar'" - with pytest.raises(AttributeError) as e: - p.foobar = 42 - assert str(e.value) == "cdata 'struct foo *' has no field 'foobar'" - with pytest.raises(AttributeError) as e: - s.foobar - assert str(e.value) == "cdata 'struct foo' has no field 'foobar'" - with pytest.raises(AttributeError) as e: - s.foobar = 42 - assert str(e.value) == "cdata 'struct foo' has no field 'foobar'" - j = cast(BInt, 42) - with pytest.raises(AttributeError) as e: - j.foobar - assert str(e.value) == "cdata 'int' has no attribute 'foobar'" - 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) - with pytest.raises(AttributeError) as e: - j.foobar - assert str(e.value) == "cdata 'int *' has no attribute 'foobar'" - 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) - with pytest.raises(AttributeError) as e: - pp.a1 - assert str(e.value) == "cdata 'struct foo * *' has no attribute 'a1'" - with pytest.raises(AttributeError) as e: - pp.a1 = 42 - assert str(e.value) == "cdata 'struct foo * *' has no attribute 'a1'" - -def test_union_instance(): - BInt = new_primitive_type("int") - BUInt = new_primitive_type("unsigned int") - BUnion = new_union_type("union bar") - complete_struct_or_union(BUnion, [('a1', BInt, -1), ('a2', BUInt, -1)]) - p = newp(new_pointer_type(BUnion), [-42]) - bigval = -42 + (1 << (8*size_of_int())) - assert p.a1 == -42 - assert p.a2 == bigval - p = newp(new_pointer_type(BUnion), {'a2': bigval}) - assert p.a1 == -42 - assert p.a2 == bigval - py.test.raises(OverflowError, newp, new_pointer_type(BUnion), - {'a1': bigval}) - p = newp(new_pointer_type(BUnion), []) - assert p.a1 == p.a2 == 0 - -def test_struct_pointer(): - BInt = new_primitive_type("int") - BStruct = new_struct_type("struct foo") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a1', BInt, -1), - ('a2', BInt, -1)]) - p = newp(BStructPtr, None) - assert p.a1 == 0 # read/write via the pointer (C equivalent: '->') - p.a2 = 123 - assert p.a1 == 0 - assert p.a2 == 123 - -def test_struct_init_list(): - BVoidP = new_pointer_type(new_void_type()) - BInt = new_primitive_type("int") - BIntPtr = new_pointer_type(BInt) - BStruct = new_struct_type("struct foo") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a1', BInt, -1), - ('a2', BInt, -1), - ('a3', BInt, -1), - ('p4', BIntPtr, -1)]) - s = newp(BStructPtr, [123, 456]) - assert s.a1 == 123 - assert s.a2 == 456 - assert s.a3 == 0 - assert s.p4 == cast(BVoidP, 0) - assert s.p4 != 0 - # - s = newp(BStructPtr, {'a2': 41122, 'a3': -123}) - assert s.a1 == 0 - assert s.a2 == 41122 - assert s.a3 == -123 - assert s.p4 == cast(BVoidP, 0) - # - py.test.raises(KeyError, newp, BStructPtr, {'foobar': 0}) - # - p = newp(BIntPtr, 14141) - s = newp(BStructPtr, [12, 34, 56, p]) - assert s.p4 == p - assert s.p4 - # - s = newp(BStructPtr, [12, 34, 56, cast(BVoidP, 0)]) - assert s.p4 == cast(BVoidP, 0) - assert not s.p4 - # - py.test.raises(TypeError, newp, BStructPtr, [12, 34, 56, None]) - -def test_array_in_struct(): - BInt = new_primitive_type("int") - BStruct = new_struct_type("struct foo") - BArrayInt5 = new_array_type(new_pointer_type(BInt), 5) - complete_struct_or_union(BStruct, [('a1', BArrayInt5, -1)]) - s = newp(new_pointer_type(BStruct), [[20, 24, 27, 29, 30]]) - assert s.a1[2] == 27 - assert repr(s.a1).startswith("<cdata 'int[5]' 0x") - -def test_offsetof(): - def offsetof(BType, fieldname): - return typeoffsetof(BType, fieldname)[1] - BInt = new_primitive_type("int") - BStruct = new_struct_type("struct foo") - py.test.raises(TypeError, offsetof, BInt, "abc") - py.test.raises(TypeError, offsetof, BStruct, "abc") - complete_struct_or_union(BStruct, [('abc', BInt, -1), ('def', BInt, -1)]) - assert offsetof(BStruct, 'abc') == 0 - assert offsetof(BStruct, 'def') == size_of_int() - py.test.raises(KeyError, offsetof, BStruct, "ghi") - assert offsetof(new_pointer_type(BStruct), "def") == size_of_int() - -def test_function_type(): - BInt = new_primitive_type("int") - BFunc = new_function_type((BInt, BInt), BInt, False) - assert repr(BFunc) == "<ctype 'int(*)(int, int)'>" - BFunc2 = new_function_type((), BFunc, False) - assert repr(BFunc2) == "<ctype 'int(*(*)())(int, int)'>" - -def test_inspect_function_type(): - BInt = new_primitive_type("int") - BFunc = new_function_type((BInt, BInt), BInt, False) - assert BFunc.kind == "function" - assert BFunc.cname == "int(*)(int, int)" - assert BFunc.args == (BInt, BInt) - assert BFunc.result is BInt - assert BFunc.ellipsis is False - assert BFunc.abi == FFI_DEFAULT_ABI - -def test_function_type_taking_struct(): - BChar = new_primitive_type("char") - BShort = new_primitive_type("short") - BStruct = new_struct_type("struct foo") - complete_struct_or_union(BStruct, [('a1', BChar, -1), - ('a2', BShort, -1)]) - BFunc = new_function_type((BStruct,), BShort, False) - assert repr(BFunc) == "<ctype 'short(*)(struct foo)'>" - -def test_function_void_result(): - BVoid = new_void_type() - BInt = new_primitive_type("int") - BFunc = new_function_type((BInt, BInt), BVoid, False) - assert repr(BFunc) == "<ctype 'void(*)(int, int)'>" - -def test_function_void_arg(): - BVoid = new_void_type() - BInt = new_primitive_type("int") - py.test.raises(TypeError, new_function_type, (BVoid,), BInt, False) - -def test_call_function_0(): - BSignedChar = new_primitive_type("signed char") - BFunc0 = new_function_type((BSignedChar, BSignedChar), BSignedChar, False) - f = cast(BFunc0, _testfunc(0)) - assert f(40, 2) == 42 - assert f(-100, -100) == -200 + 256 - py.test.raises(OverflowError, f, 128, 0) - py.test.raises(OverflowError, f, 0, 128) - -def test_call_function_0_pretend_bool_result(): - BSignedChar = new_primitive_type("signed char") - BBool = new_primitive_type("_Bool") - BFunc0 = new_function_type((BSignedChar, BSignedChar), BBool, False) - f = cast(BFunc0, _testfunc(0)) - assert f(40, -39) is True - assert f(40, -40) is False - py.test.raises(ValueError, f, 40, 2) - -def test_call_function_1(): - BInt = new_primitive_type("int") - BLong = new_primitive_type("long") - BFunc1 = new_function_type((BInt, BLong), BLong, False) - f = cast(BFunc1, _testfunc(1)) - assert f(40, 2) == 42 - assert f(-100, -100) == -200 - int_max = (1 << (8*size_of_int()-1)) - 1 - long_max = (1 << (8*size_of_long()-1)) - 1 - if int_max == long_max: - assert f(int_max, 1) == - int_max - 1 - else: - assert f(int_max, 1) == int_max + 1 - -def test_call_function_2(): - BLongLong = new_primitive_type("long long") - BFunc2 = new_function_type((BLongLong, BLongLong), BLongLong, False) - f = cast(BFunc2, _testfunc(2)) - longlong_max = (1 << (8*sizeof(BLongLong)-1)) - 1 - assert f(longlong_max - 42, 42) == longlong_max - assert f(43, longlong_max - 42) == - longlong_max - 1 - -def test_call_function_3(): - BFloat = new_primitive_type("float") - BDouble = new_primitive_type("double") - BFunc3 = new_function_type((BFloat, BDouble), BDouble, False) - f = cast(BFunc3, _testfunc(3)) - assert f(1.25, 5.1) == 1.25 + 5.1 # exact - res = f(1.3, 5.1) - assert res != 6.4 and abs(res - 6.4) < 1E-5 # inexact - -def test_call_function_4(): - BFloat = new_primitive_type("float") - BDouble = new_primitive_type("double") - BFunc4 = new_function_type((BFloat, BDouble), BFloat, False) - f = cast(BFunc4, _testfunc(4)) - res = f(1.25, 5.1) - assert res != 6.35 and abs(res - 6.35) < 1E-5 # inexact - -def test_call_function_5(): - BVoid = new_void_type() - BFunc5 = new_function_type((), BVoid, False) - f = cast(BFunc5, _testfunc(5)) - f() # did not crash - -def test_call_function_6(): - BInt = new_primitive_type("int") - BIntPtr = new_pointer_type(BInt) - BFunc6 = new_function_type((BIntPtr,), BIntPtr, False) - f = cast(BFunc6, _testfunc(6)) - x = newp(BIntPtr, 42) - res = f(x) - assert typeof(res) is BIntPtr - assert res[0] == 42 - 1000 - # - BIntArray = new_array_type(BIntPtr, None) - BFunc6bis = new_function_type((BIntArray,), BIntPtr, False) - f = cast(BFunc6bis, _testfunc(6)) - # - res = f([142]) - assert typeof(res) is BIntPtr - assert res[0] == 142 - 1000 - # - res = f((143,)) - assert typeof(res) is BIntPtr - assert res[0] == 143 - 1000 - # - x = newp(BIntArray, [242]) - res = f(x) - assert typeof(res) is BIntPtr - assert res[0] == 242 - 1000 - # - py.test.raises(TypeError, f, 123456) - py.test.raises(TypeError, f, "foo") - py.test.raises(TypeError, f, u+"bar") - -def test_call_function_7(): - BChar = new_primitive_type("char") - BShort = new_primitive_type("short") - BStruct = new_struct_type("struct foo") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a1', BChar, -1), - ('a2', BShort, -1)]) - BFunc7 = new_function_type((BStruct,), BShort, False) - f = cast(BFunc7, _testfunc(7)) - res = f({'a1': b'A', 'a2': -4042}) - assert res == -4042 + ord(b'A') - # - x = newp(BStructPtr, {'a1': b'A', 'a2': -4042}) - res = f(x[0]) - assert res == -4042 + ord(b'A') - -def test_call_function_20(): - BChar = new_primitive_type("char") - BShort = new_primitive_type("short") - BStruct = new_struct_type("struct foo") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a1', BChar, -1), - ('a2', BShort, -1)]) - BFunc20 = new_function_type((BStructPtr,), BShort, False) - f = cast(BFunc20, _testfunc(20)) - x = newp(BStructPtr, {'a1': b'A', 'a2': -4042}) - # can't pass a 'struct foo' - py.test.raises(TypeError, f, x[0]) - -def test_call_function_21(): - BInt = new_primitive_type("int") - BStruct = new_struct_type("struct foo") - complete_struct_or_union(BStruct, [('a', BInt, -1), - ('b', BInt, -1), - ('c', BInt, -1), - ('d', BInt, -1), - ('e', BInt, -1), - ('f', BInt, -1), - ('g', BInt, -1), - ('h', BInt, -1), - ('i', BInt, -1), - ('j', BInt, -1)]) - BFunc21 = new_function_type((BStruct,), BInt, False) - f = cast(BFunc21, _testfunc(21)) - res = f(list(range(13, 3, -1))) - lst = [(n << i) for (i, n) in enumerate(range(13, 3, -1))] - assert res == sum(lst) - -def test_call_function_22(): - BInt = new_primitive_type("int") - BArray10 = new_array_type(new_pointer_type(BInt), 10) - BStruct = new_struct_type("struct foo") - BStructP = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a', BArray10, -1)]) - BFunc22 = new_function_type((BStruct, BStruct), BStruct, False) - f = cast(BFunc22, _testfunc(22)) - p1 = newp(BStructP, {'a': list(range(100, 110))}) - p2 = newp(BStructP, {'a': list(range(1000, 1100, 10))}) - res = f(p1[0], p2[0]) - for i in range(10): - assert res.a[i] == p1.a[i] - p2.a[i] - -def test_call_function_23(): - BVoid = new_void_type() # declaring the function as int(void*) - BVoidP = new_pointer_type(BVoid) - BInt = new_primitive_type("int") - BFunc23 = new_function_type((BVoidP,), BInt, False) - f = cast(BFunc23, _testfunc(23)) - res = f(b"foo") - assert res == 1000 * ord(b'f') - res = f(cast(BVoidP, 0)) # NULL - assert res == -42 - py.test.raises(TypeError, f, None) - py.test.raises(TypeError, f, 0) - py.test.raises(TypeError, f, 0.0) - -def test_call_function_23_bis(): - # declaring the function as int(unsigned char*) - BUChar = new_primitive_type("unsigned char") - BUCharP = new_pointer_type(BUChar) - BInt = new_primitive_type("int") - BFunc23 = new_function_type((BUCharP,), BInt, False) - f = cast(BFunc23, _testfunc(23)) - res = f(b"foo") - assert res == 1000 * ord(b'f') - -def test_call_function_23_bool_array(): - # declaring the function as int(_Bool*) - BBool = new_primitive_type("_Bool") - BBoolP = new_pointer_type(BBool) - BInt = new_primitive_type("int") - BFunc23 = new_function_type((BBoolP,), BInt, False) - f = cast(BFunc23, _testfunc(23)) - res = f(b"\x01\x01") - assert res == 1000 - py.test.raises(ValueError, f, b"\x02\x02") - -def test_cannot_pass_struct_with_array_of_length_0(): - BInt = new_primitive_type("int") - BArray0 = new_array_type(new_pointer_type(BInt), 0) - BStruct = new_struct_type("struct foo") - BStructP = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a', BArray0)]) - BFunc = new_function_type((BStruct,), BInt, False) - py.test.raises(NotImplementedError, cast(BFunc, 123), cast(BStructP, 123)) - BFunc2 = new_function_type((BInt,), BStruct, False) - py.test.raises(NotImplementedError, cast(BFunc2, 123), 123) - -def test_call_function_9(): - BInt = new_primitive_type("int") - BFunc9 = new_function_type((BInt,), BInt, True) # vararg - f = cast(BFunc9, _testfunc(9)) - assert f(0) == 0 - assert f(1, cast(BInt, 42)) == 42 - assert f(2, cast(BInt, 40), cast(BInt, 2)) == 42 - py.test.raises(TypeError, f, 1, 42) - py.test.raises(TypeError, f, 2, None) - # promotion of chars and shorts to ints - BSChar = new_primitive_type("signed char") - BUChar = new_primitive_type("unsigned char") - BSShort = new_primitive_type("short") - assert f(3, cast(BSChar, -3), cast(BUChar, 200), cast(BSShort, -5)) == 192 - -def test_call_function_24(): - BFloat = new_primitive_type("float") - BFloatComplex = new_primitive_type("float _Complex") - BFunc3 = new_function_type((BFloat, BFloat), BFloatComplex, False) - if 0: # libffi returning nonsense silently, so logic disabled for now - f = cast(BFunc3, _testfunc(24)) - result = f(1.25, 5.1) - assert type(result) == complex - assert result.real == 1.25 # exact - assert (result.imag != 2*5.1) and (abs(result.imag - 2*5.1) < 1e-5) # inexact - else: - f = cast(BFunc3, _testfunc(9)) - py.test.raises(NotImplementedError, f, 12.3, 34.5) - -def test_call_function_25(): - BDouble = new_primitive_type("double") - BDoubleComplex = new_primitive_type("double _Complex") - BFunc3 = new_function_type((BDouble, BDouble), BDoubleComplex, False) - if 0: # libffi returning nonsense silently, so logic disabled for now - f = cast(BFunc3, _testfunc(25)) - result = f(1.25, 5.1) - assert type(result) == complex - assert result.real == 1.25 # exact - assert (result.imag != 2*5.1) and (abs(result.imag - 2*5.1) < 1e-10) # inexact - else: - f = cast(BFunc3, _testfunc(9)) - py.test.raises(NotImplementedError, f, 12.3, 34.5) - -def test_cannot_call_with_a_autocompleted_struct(): - BSChar = new_primitive_type("signed char") - BDouble = new_primitive_type("double") - BStruct = new_struct_type("struct foo") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('c', BDouble, -1, 8), - ('a', BSChar, -1, 2), - ('b', BSChar, -1, 0)]) - BFunc = new_function_type((BStruct,), BDouble) # internally not callable - dummy_func = cast(BFunc, 42) - e = py.test.raises(NotImplementedError, dummy_func, "?") - msg = ("ctype 'struct foo' not supported as argument. It is a struct " - 'declared with "...;", but the C calling convention may depend ' - "on the missing fields; or, it contains anonymous struct/unions. " - "Such structs are only supported as argument if the function is " - "'API mode' and non-variadic (i.e. declared inside ffibuilder." - "cdef()+ffibuilder.set_source() and not taking a final '...' " - "argument)") - assert str(e.value) == msg - -def test_new_charp(): - BChar = new_primitive_type("char") - BCharP = new_pointer_type(BChar) - BCharA = new_array_type(BCharP, None) - x = newp(BCharA, 42) - assert len(x) == 42 - x = newp(BCharA, b"foobar") - assert len(x) == 7 - -def test_load_and_call_function(): - BChar = new_primitive_type("char") - BCharP = new_pointer_type(BChar) - BLong = new_primitive_type("long") - BFunc = new_function_type((BCharP,), BLong, False) - ll = find_and_load_library('c') - strlen = ll.load_function(BFunc, "strlen") - input = newp(new_array_type(BCharP, None), b"foobar") - assert strlen(input) == 6 - # - assert strlen(b"foobarbaz") == 9 - # - BVoidP = new_pointer_type(new_void_type()) - strlenaddr = ll.load_function(BVoidP, "strlen") - assert strlenaddr == cast(BVoidP, strlen) - -def test_read_variable(): - ## FIXME: this test assumes glibc specific behavior, it's not compliant with C standard - ## https://bugs.pypy.org/issue1643 - if not sys.platform.startswith("linux"): - py.test.skip("untested") - BVoidP = new_pointer_type(new_void_type()) - ll = find_and_load_library('c') - stderr = ll.read_variable(BVoidP, "stderr") - assert stderr == cast(BVoidP, _testfunc(8)) - # - ll.close_lib() - py.test.raises(ValueError, ll.read_variable, BVoidP, "stderr") - -def test_read_variable_as_unknown_length_array(): - ## FIXME: this test assumes glibc specific behavior, it's not compliant with C standard - ## https://bugs.pypy.org/issue1643 - if not sys.platform.startswith("linux"): - py.test.skip("untested") - BCharP = new_pointer_type(new_primitive_type("char")) - BArray = new_array_type(BCharP, None) - ll = find_and_load_library('c') - stderr = ll.read_variable(BArray, "stderr") - assert repr(stderr).startswith("<cdata 'char *' 0x") - # ^^ and not 'char[]', which is basically not allowed and would crash - -def test_write_variable(): - ## FIXME: this test assumes glibc specific behavior, it's not compliant with C standard - ## https://bugs.pypy.org/issue1643 - if not sys.platform.startswith("linux"): - py.test.skip("untested") - BVoidP = new_pointer_type(new_void_type()) - ll = find_and_load_library('c') - stderr = ll.read_variable(BVoidP, "stderr") - ll.write_variable(BVoidP, "stderr", cast(BVoidP, 0)) - assert ll.read_variable(BVoidP, "stderr") is not None - assert not ll.read_variable(BVoidP, "stderr") - ll.write_variable(BVoidP, "stderr", stderr) - assert ll.read_variable(BVoidP, "stderr") == stderr - # - ll.close_lib() - py.test.raises(ValueError, ll.write_variable, BVoidP, "stderr", stderr) - -def test_callback(): - BInt = new_primitive_type("int") - def make_callback(): - def cb(n): - return n + 1 - BFunc = new_function_type((BInt,), BInt, False) - return callback(BFunc, cb, 42) # 'cb' and 'BFunc' go out of scope - f = make_callback() - assert f(-142) == -141 - assert repr(f).startswith( - "<cdata 'int(*)(int)' calling <function ") - assert "cb at 0x" in repr(f) - e = py.test.raises(TypeError, f) - assert str(e.value) == "'int(*)(int)' expects 1 arguments, got 0" - -def test_callback_exception(): - try: - import cStringIO - except ImportError: - import io as cStringIO # Python 3 - import linecache - def matches(istr, ipattern, ipattern38): - if sys.version_info >= (3, 8): - ipattern = ipattern38 - str, pattern = istr, ipattern - while '$' in pattern: - i = pattern.index('$') - assert str[:i] == pattern[:i] - j = str.find(pattern[i+1], i) - assert i + 1 <= j <= str.find('\n', i) - str = str[j:] - pattern = pattern[i+1:] - assert str == pattern - return True - def check_value(x): - if x == 10000: - raise ValueError(42) - def Zcb1(x): - check_value(x) - return x * 3 - BShort = new_primitive_type("short") - BFunc = new_function_type((BShort,), BShort, False) - f = callback(BFunc, Zcb1, -42) - # - seen = [] - oops_result = None - def oops(*args): - seen.append(args) - return oops_result - ff = callback(BFunc, Zcb1, -42, oops) - # - orig_stderr = sys.stderr - orig_getline = linecache.getline - 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 - assert matches(sys.stderr.getvalue(), """\ -From cffi callback <function$Zcb1 at 0x$>: -Traceback (most recent call last): - File "$", line $, in Zcb1 - $ - 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 - assert f(bigvalue) == -42 - assert matches(sys.stderr.getvalue(), """\ -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 - assert len(seen) == 0 - assert ff(bigvalue) == -42 - assert sys.stderr.getvalue() == "" - assert len(seen) == 1 - exc, val, tb = seen[0] - assert exc is OverflowError - assert str(val) == "integer 60000 does not fit 'short'" - # - sys.stderr = cStringIO.StringIO() - bigvalue = 20000 - del seen[:] - oops_result = 81 - assert ff(bigvalue) == 81 - oops_result = None - assert sys.stderr.getvalue() == "" - assert len(seen) == 1 - exc, val, tb = seen[0] - assert exc is OverflowError - assert str(val) == "integer 60000 does not fit 'short'" - # - sys.stderr = cStringIO.StringIO() - bigvalue = 20000 - del seen[:] - oops_result = "xy" # not None and not an int! - assert ff(bigvalue) == -42 - oops_result = None - assert matches(sys.stderr.getvalue(), """\ -From cffi callback <function$Zcb1 at 0x$>: -Trying to convert the result back to C: -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: -OverflowError: integer 60000 does not fit 'short' - -During the call to 'onerror', another exception occurred: - -Traceback (most recent call last): - File "$", line $, in oops - $ -AttributeError: 'str' object has no attribute 'append$ -""", """\ -Exception ignored from cffi callback <function$Zcb1 at 0x$>, trying to convert the result back to C: -Traceback (most recent call last): - File "$", line $, in test_callback_exception - $ -OverflowError: integer 60000 does not fit 'short' -Exception ignored during handling of the above exception by 'onerror': -Traceback (most recent call last): - File "$", line $, in oops - $ -AttributeError: 'str' object has no attribute 'append$ -""") - finally: - sys.stderr = orig_stderr - linecache.getline = orig_getline - -def test_callback_return_type(): - for rettype in ["signed char", "short", "int", "long", "long long", - "unsigned char", "unsigned short", "unsigned int", - "unsigned long", "unsigned long long"]: - BRet = new_primitive_type(rettype) - def cb(n): - return n + 1 - BFunc = new_function_type((BRet,), BRet) - f = callback(BFunc, cb, 42) - assert f(41) == 42 - if rettype.startswith("unsigned "): - min = 0 - max = (1 << (8*sizeof(BRet))) - 1 - else: - min = -(1 << (8*sizeof(BRet)-1)) - max = (1 << (8*sizeof(BRet)-1)) - 1 - assert f(min) == min + 1 - assert f(max - 1) == max - assert f(max) == 42 - -def test_a_lot_of_callbacks(): - BIGNUM = 10000 - if 'PY_DOT_PY' in globals(): BIGNUM = 100 # tests on py.py - # - BInt = new_primitive_type("int") - BFunc = new_function_type((BInt,), BInt, False) - def make_callback(m): - def cb(n): - return n + m - 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): - assert f(-142) == -142 + i - -def test_callback_receiving_tiny_struct(): - BSChar = new_primitive_type("signed char") - BInt = new_primitive_type("int") - BStruct = new_struct_type("struct foo") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a', BSChar, -1), - ('b', BSChar, -1)]) - def cb(s): - return s.a + 10 * s.b - BFunc = new_function_type((BStruct,), BInt) - f = callback(BFunc, cb) - p = newp(BStructPtr, [-2, -4]) - n = f(p[0]) - assert n == -42 - -def test_callback_returning_tiny_struct(): - BSChar = new_primitive_type("signed char") - BInt = new_primitive_type("int") - BStruct = new_struct_type("struct foo") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a', BSChar, -1), - ('b', BSChar, -1)]) - def cb(n): - return newp(BStructPtr, [-n, -3*n])[0] - BFunc = new_function_type((BInt,), BStruct) - f = callback(BFunc, cb) - s = f(10) - assert typeof(s) is BStruct - assert repr(s) == "<cdata 'struct foo' owning 2 bytes>" - assert s.a == -10 - assert s.b == -30 - -def test_callback_receiving_struct(): - BSChar = new_primitive_type("signed char") - BInt = new_primitive_type("int") - BDouble = new_primitive_type("double") - BStruct = new_struct_type("struct foo") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a', BSChar, -1), - ('b', BDouble, -1)]) - def cb(s): - return s.a + int(s.b) - BFunc = new_function_type((BStruct,), BInt) - f = callback(BFunc, cb) - p = newp(BStructPtr, [-2, 44.444]) - n = f(p[0]) - assert n == 42 - -def test_callback_returning_struct(): - BSChar = new_primitive_type("signed char") - BInt = new_primitive_type("int") - BDouble = new_primitive_type("double") - BStruct = new_struct_type("struct foo") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a', BSChar, -1), - ('b', BDouble, -1)]) - def cb(n): - return newp(BStructPtr, [-n, 1E-42])[0] - BFunc = new_function_type((BInt,), BStruct) - f = callback(BFunc, cb) - s = f(10) - assert typeof(s) is BStruct - assert repr(s) in ["<cdata 'struct foo' owning 12 bytes>", - "<cdata 'struct foo' owning 16 bytes>"] - assert s.a == -10 - assert s.b == 1E-42 - -def test_callback_receiving_big_struct(): - BInt = new_primitive_type("int") - BStruct = new_struct_type("struct foo") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a', BInt, -1), - ('b', BInt, -1), - ('c', BInt, -1), - ('d', BInt, -1), - ('e', BInt, -1), - ('f', BInt, -1), - ('g', BInt, -1), - ('h', BInt, -1), - ('i', BInt, -1), - ('j', BInt, -1)]) - def cb(s): - for i, name in enumerate("abcdefghij"): - assert getattr(s, name) == 13 - i - return 42 - BFunc = new_function_type((BStruct,), BInt) - f = callback(BFunc, cb) - p = newp(BStructPtr, list(range(13, 3, -1))) - n = f(p[0]) - assert n == 42 - -def test_callback_returning_big_struct(): - BInt = new_primitive_type("int") - BStruct = new_struct_type("struct foo") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a', BInt, -1), - ('b', BInt, -1), - ('c', BInt, -1), - ('d', BInt, -1), - ('e', BInt, -1), - ('f', BInt, -1), - ('g', BInt, -1), - ('h', BInt, -1), - ('i', BInt, -1), - ('j', BInt, -1)]) - def cb(): - return newp(BStructPtr, list(range(13, 3, -1)))[0] - BFunc = new_function_type((), BStruct) - f = callback(BFunc, cb) - s = f() - assert typeof(s) is BStruct - assert repr(s) in ["<cdata 'struct foo' owning 40 bytes>", - "<cdata 'struct foo' owning 80 bytes>"] - for i, name in enumerate("abcdefghij"): - assert getattr(s, name) == 13 - i - -def test_callback_returning_void(): - BVoid = new_void_type() - BFunc = new_function_type((), BVoid, False) - def cb(): - seen.append(42) - f = callback(BFunc, cb) - seen = [] - f() - assert seen == [42] - py.test.raises(TypeError, callback, BFunc, cb, -42) - -def test_enum_type(): - BUInt = new_primitive_type("unsigned int") - BEnum = new_enum_type("foo", (), (), BUInt) - assert repr(BEnum) == "<ctype 'foo'>" - assert BEnum.kind == "enum" - assert BEnum.cname == "foo" - assert BEnum.elements == {} - # - BInt = new_primitive_type("int") - BEnum = new_enum_type("enum foo", ('def', 'c', 'ab'), (0, 1, -20), BInt) - assert BEnum.kind == "enum" - assert BEnum.cname == "enum foo" - assert BEnum.elements == {-20: 'ab', 0: 'def', 1: 'c'} - # 'elements' is not the real dict, but merely a copy - BEnum.elements[2] = '??' - assert BEnum.elements == {-20: 'ab', 0: 'def', 1: 'c'} - # - BEnum = new_enum_type("enum bar", ('ab', 'cd'), (5, 5), BUInt) - assert BEnum.elements == {5: 'ab'} - assert BEnum.relements == {'ab': 5, 'cd': 5} - -def test_cast_to_enum(): - BInt = new_primitive_type("int") - BEnum = new_enum_type("enum foo", ('def', 'c', 'ab'), (0, 1, -20), BInt) - assert sizeof(BEnum) == sizeof(BInt) - e = cast(BEnum, 0) - assert repr(e) == "<cdata 'enum foo' 0: def>" - assert repr(cast(BEnum, -42)) == "<cdata 'enum foo' -42>" - assert repr(cast(BEnum, -20)) == "<cdata 'enum foo' -20: ab>" - assert string(e) == 'def' - assert string(cast(BEnum, -20)) == 'ab' - assert int(cast(BEnum, 1)) == 1 - assert int(cast(BEnum, 0)) == 0 - assert int(cast(BEnum, -242 + 2**128)) == -242 - assert string(cast(BEnum, -242 + 2**128)) == '-242' - # - BUInt = new_primitive_type("unsigned int") - BEnum = new_enum_type("enum bar", ('def', 'c', 'ab'), (0, 1, 20), BUInt) - e = cast(BEnum, -1) - assert repr(e) == "<cdata 'enum bar' 4294967295>" # unsigned int - # - BLong = new_primitive_type("long") - BEnum = new_enum_type("enum baz", (), (), BLong) - assert sizeof(BEnum) == sizeof(BLong) - e = cast(BEnum, -1) - assert repr(e) == "<cdata 'enum baz' -1>" - -def test_enum_with_non_injective_mapping(): - BInt = new_primitive_type("int") - BEnum = new_enum_type("enum foo", ('ab', 'cd'), (7, 7), BInt) - e = cast(BEnum, 7) - assert repr(e) == "<cdata 'enum foo' 7: ab>" - assert string(e) == 'ab' - -def test_enum_in_struct(): - BInt = new_primitive_type("int") - BEnum = new_enum_type("enum foo", ('def', 'c', 'ab'), (0, 1, -20), BInt) - BStruct = new_struct_type("struct bar") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a1', BEnum, -1)]) - p = newp(BStructPtr, [-20]) - assert p.a1 == -20 - p = newp(BStructPtr, [12]) - assert p.a1 == 12 - e = py.test.raises(TypeError, newp, BStructPtr, [None]) - msg = str(e.value) - 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 - 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' - assert type(string(cast(BEnum2, 5))) is str - -def test_enum_overflow(): - max_uint = 2 ** (size_of_int()*8) - 1 - max_int = max_uint // 2 - max_ulong = 2 ** (size_of_long()*8) - 1 - max_long = max_ulong // 2 - for BPrimitive in [new_primitive_type("int"), - new_primitive_type("unsigned int"), - new_primitive_type("long"), - new_primitive_type("unsigned long")]: - for x in [max_uint, max_int, max_ulong, max_long]: - for testcase in [x, x+1, -x-1, -x-2]: - if int(cast(BPrimitive, testcase)) == testcase: - # fits - BEnum = new_enum_type("foo", ("AA",), (testcase,), - BPrimitive) - assert int(cast(BEnum, testcase)) == testcase - else: - # overflows - py.test.raises(OverflowError, new_enum_type, - "foo", ("AA",), (testcase,), BPrimitive) - -def test_callback_returning_enum(): - BInt = new_primitive_type("int") - BEnum = new_enum_type("foo", ('def', 'c', 'ab'), (0, 1, -20), BInt) - def cb(n): - if n & 1: - return cast(BEnum, n) - else: - return n - BFunc = new_function_type((BInt,), BEnum) - f = callback(BFunc, cb) - assert f(0) == 0 - assert f(1) == 1 - assert f(-20) == -20 - assert f(20) == 20 - assert f(21) == 21 - -def test_callback_returning_enum_unsigned(): - BInt = new_primitive_type("int") - BUInt = new_primitive_type("unsigned int") - BEnum = new_enum_type("foo", ('def', 'c', 'ab'), (0, 1, 20), BUInt) - def cb(n): - if n & 1: - return cast(BEnum, n) - else: - return n - BFunc = new_function_type((BInt,), BEnum) - f = callback(BFunc, cb) - assert f(0) == 0 - assert f(1) == 1 - assert f(-21) == 2**32 - 21 - assert f(20) == 20 - assert f(21) == 21 - -def test_callback_returning_char(): - BInt = new_primitive_type("int") - BChar = new_primitive_type("char") - def cb(n): - return bytechr(n) - BFunc = new_function_type((BInt,), BChar) - f = callback(BFunc, cb) - assert f(0) == b'\x00' - assert f(255) == b'\xFF' - -def _hacked_pypy_uni4(): - pyuni4 = {1: True, 2: False}[len(u+'\U00012345')] - return 'PY_DOT_PY' in globals() and not pyuni4 - -def test_callback_returning_wchar_t(): - BInt = new_primitive_type("int") - BWChar = new_primitive_type("wchar_t") - def cb(n): - if n == -1: - return u+'\U00012345' - if n == -2: - raise ValueError - return unichr(n) - BFunc = new_function_type((BInt,), BWChar) - f = callback(BFunc, cb) - assert f(0) == unichr(0) - assert f(255) == unichr(255) - assert f(0x1234) == u+'\u1234' - if sizeof(BWChar) == 4 and not _hacked_pypy_uni4(): - assert f(-1) == u+'\U00012345' - assert f(-2) == u+'\x00' # and an exception printed to stderr - -def test_struct_with_bitfields(): - BLong = new_primitive_type("long") - BStruct = new_struct_type("struct foo") - LONGBITS = 8 * sizeof(BLong) - complete_struct_or_union(BStruct, [('a1', BLong, 1), - ('a2', BLong, 2), - ('a3', BLong, 3), - ('a4', BLong, LONGBITS - 5)]) - d = BStruct.fields - assert d[0][1].offset == d[1][1].offset == d[2][1].offset == 0 - assert d[3][1].offset == sizeof(BLong) - def f(m, r): - if sys.byteorder == 'little': - return r - else: - return LONGBITS - m - r - assert d[0][1].bitshift == f(1, 0) - assert d[0][1].bitsize == 1 - assert d[1][1].bitshift == f(2, 1) - assert d[1][1].bitsize == 2 - assert d[2][1].bitshift == f(3, 3) - assert d[2][1].bitsize == 3 - assert d[3][1].bitshift == f(LONGBITS - 5, 0) - assert d[3][1].bitsize == LONGBITS - 5 - assert sizeof(BStruct) == 2 * sizeof(BLong) - assert alignof(BStruct) == alignof(BLong) - -def test_bitfield_instance(): - BInt = new_primitive_type("int") - BUnsignedInt = new_primitive_type("unsigned int") - BStruct = new_struct_type("struct foo") - complete_struct_or_union(BStruct, [('a1', BInt, 1), - ('a2', BUnsignedInt, 2), - ('a3', BInt, 3)]) - p = newp(new_pointer_type(BStruct), None) - p.a1 = -1 - assert p.a1 == -1 - p.a1 = 0 - with pytest.raises(OverflowError): - p.a1 = 2 - assert p.a1 == 0 - # - p.a1 = -1 - p.a2 = 3 - p.a3 = -4 - 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 - # - # special case for convenience: "int x:1", while normally signed, - # allows also setting the value "1" (it still gets read back as -1) - p.a1 = 1 - assert p.a1 == -1 - 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") - -def test_bitfield_instance_init(): - BInt = new_primitive_type("int") - BStruct = new_struct_type("struct foo") - complete_struct_or_union(BStruct, [('a1', BInt, 1)]) - p = newp(new_pointer_type(BStruct), [-1]) - assert p.a1 == -1 - p = newp(new_pointer_type(BStruct), {'a1': -1}) - assert p.a1 == -1 - # - BUnion = new_union_type("union bar") - complete_struct_or_union(BUnion, [('a1', BInt, 1)]) - p = newp(new_pointer_type(BUnion), [-1]) - assert p.a1 == -1 - -def test_weakref(): - import _weakref - BInt = new_primitive_type("int") - BPtr = new_pointer_type(BInt) - rlist = [_weakref.ref(BInt), - _weakref.ref(newp(BPtr, 42)), - _weakref.ref(cast(BPtr, 42)), - _weakref.ref(cast(BInt, 42)), - _weakref.ref(buffer(newp(BPtr, 42))), - ] - for i in range(5): - import gc; gc.collect() - if [r() for r in rlist] == [None for r in rlist]: - break - -def test_no_inheritance(): - BInt = new_primitive_type("int") - try: - class foo(type(BInt)): pass - except TypeError: - pass - else: - raise AssertionError - x = cast(BInt, 42) - try: - class foo(type(x)): pass - except TypeError: - pass - else: - raise AssertionError - -def test_assign_string(): - BChar = new_primitive_type("char") - BArray1 = new_array_type(new_pointer_type(BChar), 5) - BArray2 = new_array_type(new_pointer_type(BArray1), 5) - a = newp(BArray2, [b"abc", b"de", b"ghij"]) - assert string(a[1]) == b"de" - assert string(a[2]) == b"ghij" - a[2] = b"." - assert string(a[2]) == b"." - a[2] = b"12345" - assert string(a[2]) == b"12345" - 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) - with pytest.raises(TypeError): - x + 1 - with pytest.raises(TypeError): - x - 1 - -def test_void_errors(): - py.test.raises(ValueError, alignof, new_void_type()) - py.test.raises(TypeError, newp, new_pointer_type(new_void_type()), None) - -def test_too_many_items(): - BChar = new_primitive_type("char") - BArray = new_array_type(new_pointer_type(BChar), 5) - py.test.raises(IndexError, newp, BArray, tuple(b'123456')) - py.test.raises(IndexError, newp, BArray, list(b'123456')) - py.test.raises(IndexError, newp, BArray, b'123456') - BStruct = new_struct_type("struct foo") - complete_struct_or_union(BStruct, []) - py.test.raises(TypeError, newp, new_pointer_type(BStruct), b'') - py.test.raises(ValueError, newp, new_pointer_type(BStruct), [b'1']) - -def test_more_type_errors(): - BInt = new_primitive_type("int") - BChar = new_primitive_type("char") - BArray = new_array_type(new_pointer_type(BChar), 5) - py.test.raises(TypeError, newp, BArray, 12.34) - BArray = new_array_type(new_pointer_type(BInt), 5) - py.test.raises(TypeError, newp, BArray, 12.34) - BFloat = new_primitive_type("float") - py.test.raises(TypeError, cast, BFloat, newp(BArray, None)) - -def test_more_overflow_errors(): - BUInt = new_primitive_type("unsigned int") - py.test.raises(OverflowError, newp, new_pointer_type(BUInt), -1) - py.test.raises(OverflowError, newp, new_pointer_type(BUInt), 2**32) - -def test_newp_copying(): - """Test that we can do newp(<type>, <cdata of the given type>) for most - types, including same-type arrays. - """ - BInt = new_primitive_type("int") - p = newp(new_pointer_type(BInt), cast(BInt, 42)) - assert p[0] == 42 - # - BUInt = new_primitive_type("unsigned int") - p = newp(new_pointer_type(BUInt), cast(BUInt, 42)) - assert p[0] == 42 - # - BChar = new_primitive_type("char") - p = newp(new_pointer_type(BChar), cast(BChar, '!')) - assert p[0] == b'!' - # - BFloat = new_primitive_type("float") - p = newp(new_pointer_type(BFloat), cast(BFloat, 12.25)) - assert p[0] == 12.25 - # - BStruct = new_struct_type("struct foo_s") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a1', BInt, -1)]) - s1 = newp(BStructPtr, [42]) - p1 = newp(new_pointer_type(BStructPtr), s1) - assert p1[0] == s1 - # - BArray = new_array_type(new_pointer_type(BInt), None) - a1 = newp(BArray, [1, 2, 3, 4]) - py.test.raises(TypeError, newp, BArray, a1) - BArray6 = new_array_type(new_pointer_type(BInt), 6) - a1 = newp(BArray6, [10, 20, 30]) - a2 = newp(BArray6, a1) - assert list(a2) == [10, 20, 30, 0, 0, 0] - # - s1 = newp(BStructPtr, [42]) - s2 = newp(BStructPtr, s1[0]) - assert s2.a1 == 42 - # - BUnion = new_union_type("union foo_u") - BUnionPtr = new_pointer_type(BUnion) - complete_struct_or_union(BUnion, [('a1', BInt, -1)]) - u1 = newp(BUnionPtr, [42]) - u2 = newp(BUnionPtr, u1[0]) - assert u2.a1 == 42 - # - BFunc = new_function_type((BInt,), BUInt) - p1 = cast(BFunc, 42) - p2 = newp(new_pointer_type(BFunc), p1) - assert p2[0] == p1 - -def test_string(): - BChar = new_primitive_type("char") - assert string(cast(BChar, 42)) == b'*' - assert string(cast(BChar, 0)) == b'\x00' - BCharP = new_pointer_type(BChar) - BArray = new_array_type(BCharP, 10) - a = newp(BArray, b"hello") - assert len(a) == 10 - assert string(a) == b"hello" - p = a + 2 - assert string(p) == b"llo" - assert string(newp(new_array_type(BCharP, 4), b"abcd")) == b"abcd" - py.test.raises(RuntimeError, string, cast(BCharP, 0)) - assert string(a, 4) == b"hell" - assert string(a, 5) == b"hello" - assert string(a, 6) == b"hello" - -def test_string_byte(): - BByte = new_primitive_type("signed char") - assert string(cast(BByte, 42)) == b'*' - assert string(cast(BByte, 0)) == b'\x00' - BArray = new_array_type(new_pointer_type(BByte), None) - a = newp(BArray, [65, 66, 67]) - assert type(string(a)) is bytes and string(a) == b'ABC' - # - BByte = new_primitive_type("unsigned char") - assert string(cast(BByte, 42)) == b'*' - assert string(cast(BByte, 0)) == b'\x00' - BArray = new_array_type(new_pointer_type(BByte), None) - a = newp(BArray, [65, 66, 67]) - assert type(string(a)) is bytes and string(a) == b'ABC' - if 'PY_DOT_PY' not in globals() and sys.version_info < (3,): - assert string(a, 8).startswith(b'ABC') # may contain additional garbage - -def test_string_wchar(): - for typename in ["wchar_t", "char16_t", "char32_t"]: - _test_string_wchar_variant(typename) - -def _test_string_wchar_variant(typename): - BWChar = new_primitive_type(typename) - assert string(cast(BWChar, 42)) == u+'*' - assert string(cast(BWChar, 0x4253)) == u+'\u4253' - assert string(cast(BWChar, 0)) == u+'\x00' - BArray = new_array_type(new_pointer_type(BWChar), None) - a = newp(BArray, [u+'A', u+'B', u+'C']) - assert type(string(a)) is unicode and string(a) == u+'ABC' - if 'PY_DOT_PY' not in globals() and sys.version_info < (3,): - try: - # may contain additional garbage - assert string(a, 8).startswith(u+'ABC') - except ValueError: # garbage contains values > 0x10FFFF - assert sizeof(BWChar) == 4 - -def test_string_typeerror(): - BShort = new_primitive_type("short") - BArray = new_array_type(new_pointer_type(BShort), None) - a = newp(BArray, [65, 66, 67]) - py.test.raises(TypeError, string, a) - -def test_bug_convert_to_ptr(): - BChar = new_primitive_type("char") - BCharP = new_pointer_type(BChar) - BDouble = new_primitive_type("double") - x = cast(BDouble, 42) - py.test.raises(TypeError, newp, new_pointer_type(BCharP), x) - -def test_set_struct_fields(): - BChar = new_primitive_type("char") - BCharP = new_pointer_type(BChar) - BCharArray10 = new_array_type(BCharP, 10) - BStruct = new_struct_type("struct foo") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a1', BCharArray10, -1)]) - p = newp(BStructPtr, None) - assert string(p.a1) == b'' - p.a1 = b'foo' - assert string(p.a1) == b'foo' - assert list(p.a1) == [b'f', b'o', b'o'] + [b'\x00'] * 7 - p.a1 = [b'x', b'y'] - assert string(p.a1) == b'xyo' - -def test_invalid_function_result_types(): - BFunc = new_function_type((), new_void_type()) - BArray = new_array_type(new_pointer_type(BFunc), 5) # works - new_function_type((), BFunc) # works - new_function_type((), new_primitive_type("int")) - new_function_type((), new_pointer_type(BFunc)) - BUnion = new_union_type("union foo_u") - complete_struct_or_union(BUnion, []) - BFunc = new_function_type((), BUnion) - py.test.raises(NotImplementedError, cast(BFunc, 123)) - py.test.raises(TypeError, new_function_type, (), BArray) - -def test_struct_return_in_func(): - BChar = new_primitive_type("char") - BShort = new_primitive_type("short") - BFloat = new_primitive_type("float") - BDouble = new_primitive_type("double") - BInt = new_primitive_type("int") - BStruct = new_struct_type("struct foo_s") - complete_struct_or_union(BStruct, [('a1', BChar, -1), - ('a2', BShort, -1)]) - BFunc10 = new_function_type((BInt,), BStruct) - f = cast(BFunc10, _testfunc(10)) - s = f(40) - assert repr(s) == "<cdata 'struct foo_s' owning 4 bytes>" - assert s.a1 == bytechr(40) - assert s.a2 == 40 * 40 - # - BStruct11 = new_struct_type("struct test11") - complete_struct_or_union(BStruct11, [('a1', BInt, -1), - ('a2', BInt, -1)]) - BFunc11 = new_function_type((BInt,), BStruct11) - f = cast(BFunc11, _testfunc(11)) - s = f(40) - assert repr(s) == "<cdata 'struct test11' owning 8 bytes>" - assert s.a1 == 40 - assert s.a2 == 40 * 40 - # - BStruct12 = new_struct_type("struct test12") - complete_struct_or_union(BStruct12, [('a1', BDouble, -1), - ]) - BFunc12 = new_function_type((BInt,), BStruct12) - f = cast(BFunc12, _testfunc(12)) - s = f(40) - assert repr(s) == "<cdata 'struct test12' owning 8 bytes>" - assert s.a1 == 40.0 - # - BStruct13 = new_struct_type("struct test13") - complete_struct_or_union(BStruct13, [('a1', BInt, -1), - ('a2', BInt, -1), - ('a3', BInt, -1)]) - BFunc13 = new_function_type((BInt,), BStruct13) - f = cast(BFunc13, _testfunc(13)) - s = f(40) - assert repr(s) == "<cdata 'struct test13' owning 12 bytes>" - assert s.a1 == 40 - assert s.a2 == 40 * 40 - assert s.a3 == 40 * 40 * 40 - # - BStruct14 = new_struct_type("struct test14") - complete_struct_or_union(BStruct14, [('a1', BFloat, -1), - ]) - BFunc14 = new_function_type((BInt,), BStruct14) - f = cast(BFunc14, _testfunc(14)) - s = f(40) - assert repr(s) == "<cdata 'struct test14' owning 4 bytes>" - assert s.a1 == 40.0 - # - BStruct15 = new_struct_type("struct test15") - complete_struct_or_union(BStruct15, [('a1', BFloat, -1), - ('a2', BInt, -1)]) - BFunc15 = new_function_type((BInt,), BStruct15) - f = cast(BFunc15, _testfunc(15)) - s = f(40) - assert repr(s) == "<cdata 'struct test15' owning 8 bytes>" - assert s.a1 == 40.0 - assert s.a2 == 40 * 40 - # - BStruct16 = new_struct_type("struct test16") - complete_struct_or_union(BStruct16, [('a1', BFloat, -1), - ('a2', BFloat, -1)]) - BFunc16 = new_function_type((BInt,), BStruct16) - f = cast(BFunc16, _testfunc(16)) - s = f(40) - assert repr(s) == "<cdata 'struct test16' owning 8 bytes>" - assert s.a1 == 40.0 - assert s.a2 == -40.0 - # - BStruct17 = new_struct_type("struct test17") - complete_struct_or_union(BStruct17, [('a1', BInt, -1), - ('a2', BFloat, -1)]) - BFunc17 = new_function_type((BInt,), BStruct17) - f = cast(BFunc17, _testfunc(17)) - s = f(40) - assert repr(s) == "<cdata 'struct test17' owning 8 bytes>" - assert s.a1 == 40 - assert s.a2 == 40.0 * 40.0 - # - BStruct17Ptr = new_pointer_type(BStruct17) - BFunc18 = new_function_type((BStruct17Ptr,), BInt) - f = cast(BFunc18, _testfunc(18)) - x = f([[40, 2.5]]) - assert x == 42 - x = f([{'a2': 43.1}]) - assert x == 43 - -def test_cast_with_functionptr(): - BFunc = new_function_type((), new_void_type()) - BFunc2 = new_function_type((), new_primitive_type("short")) - BCharP = new_pointer_type(new_primitive_type("char")) - BIntP = new_pointer_type(new_primitive_type("int")) - BStruct = new_struct_type("struct foo") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a1', BFunc, -1)]) - newp(BStructPtr, [cast(BFunc, 0)]) - newp(BStructPtr, [cast(BCharP, 0)]) - py.test.raises(TypeError, newp, BStructPtr, [cast(BIntP, 0)]) - py.test.raises(TypeError, newp, BStructPtr, [cast(BFunc2, 0)]) - -def test_wchar(): - _test_wchar_variant("wchar_t") - if sys.platform.startswith("linux"): - BWChar = new_primitive_type("wchar_t") - assert sizeof(BWChar) == 4 - # wchar_t is often signed on Linux, but not always (e.g. on ARM) - assert int(cast(BWChar, -1)) in (-1, 4294967295) - -def test_char16(): - BChar16 = new_primitive_type("char16_t") - assert sizeof(BChar16) == 2 - _test_wchar_variant("char16_t") - assert int(cast(BChar16, -1)) == 0xffff # always unsigned - -def test_char32(): - BChar32 = new_primitive_type("char32_t") - assert sizeof(BChar32) == 4 - _test_wchar_variant("char32_t") - assert int(cast(BChar32, -1)) == 0xffffffff # always unsigned - -def _test_wchar_variant(typename): - BWChar = new_primitive_type(typename) - BInt = new_primitive_type("int") - pyuni4 = {1: True, 2: False}[len(u+'\U00012345')] - wchar4 = {2: False, 4: True}[sizeof(BWChar)] - assert str(cast(BWChar, 0x45)) == "<cdata '%s' %s'E'>" % ( - typename, mandatory_u_prefix) - assert str(cast(BWChar, 0x1234)) == "<cdata '%s' %s'\u1234'>" % ( - typename, mandatory_u_prefix) - if not _hacked_pypy_uni4(): - if wchar4: - x = cast(BWChar, 0x12345) - assert str(x) == "<cdata '%s' %s'\U00012345'>" % ( - typename, mandatory_u_prefix) - assert int(x) == 0x12345 - else: - x = cast(BWChar, 0x18345) - assert str(x) == "<cdata '%s' %s'\u8345'>" % ( - typename, mandatory_u_prefix) - assert int(x) == 0x8345 - # - BWCharP = new_pointer_type(BWChar) - BStruct = new_struct_type("struct foo_s") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a1', BWChar, -1), - ('a2', BWCharP, -1)]) - s = newp(BStructPtr) - s.a1 = u+'\x00' - assert s.a1 == u+'\x00' - 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: - if wchar4: - s.a1 = u+'\U00012345' - assert s.a1 == u+'\U00012345' - elif wchar4: - if not _hacked_pypy_uni4(): - s.a1 = cast(BWChar, 0x12345) - assert s.a1 == u+'\ud808\udf45' - s.a1 = u+'\ud807\udf44' - assert s.a1 == u+'\U00011f44' - else: - with pytest.raises(TypeError): - s.a1 = u+'\U00012345' - # - BWCharArray = new_array_type(BWCharP, None) - a = newp(BWCharArray, u+'hello \u1234 world') - assert len(a) == 14 # including the final null - assert string(a) == u+'hello \u1234 world' - a[13] = u+'!' - assert string(a) == u+'hello \u1234 world!' - assert str(a) == repr(a) - assert a[6] == u+'\u1234' - a[6] = u+'-' - assert string(a) == u+'hello - world!' - assert str(a) == repr(a) - # - if wchar4 and not _hacked_pypy_uni4(): - u1 = u+'\U00012345\U00012346\U00012347' - a = newp(BWCharArray, u1) - assert len(a) == 4 - assert string(a) == u1 - assert len(list(a)) == 4 - expected = [u+'\U00012345', u+'\U00012346', u+'\U00012347', unichr(0)] - assert list(a) == expected - got = [a[i] for i in range(4)] - assert got == expected - with pytest.raises(IndexError): - a[4] - # - w = cast(BWChar, 'a') - assert repr(w) == "<cdata '%s' %s'a'>" % (typename, mandatory_u_prefix) - assert str(w) == repr(w) - assert string(w) == u+'a' - assert int(w) == ord('a') - w = cast(BWChar, 0x1234) - assert repr(w) == "<cdata '%s' %s'\u1234'>" % (typename, mandatory_u_prefix) - assert str(w) == repr(w) - assert string(w) == u+'\u1234' - assert int(w) == 0x1234 - w = cast(BWChar, u+'\u8234') - assert repr(w) == "<cdata '%s' %s'\u8234'>" % (typename, mandatory_u_prefix) - assert str(w) == repr(w) - assert string(w) == u+'\u8234' - assert int(w) == 0x8234 - w = cast(BInt, u+'\u1234') - assert repr(w) == "<cdata 'int' 4660>" - if wchar4 and not _hacked_pypy_uni4(): - w = cast(BWChar, u+'\U00012345') - assert repr(w) == "<cdata '%s' %s'\U00012345'>" % ( - typename, mandatory_u_prefix) - assert str(w) == repr(w) - assert string(w) == u+'\U00012345' - assert int(w) == 0x12345 - w = cast(BInt, u+'\U00012345') - assert repr(w) == "<cdata 'int' 74565>" - py.test.raises(TypeError, cast, BInt, u+'') - py.test.raises(TypeError, cast, BInt, u+'XX') - assert int(cast(BInt, u+'a')) == ord('a') - # - a = newp(BWCharArray, u+'hello - world') - p = cast(BWCharP, a) - assert string(p) == u+'hello - world' - p[6] = u+'\u2345' - assert string(p) == u+'hello \u2345 world' - # - s = newp(BStructPtr, [u+'\u1234', p]) - assert s.a1 == u+'\u1234' - assert s.a2 == p - assert str(s.a2) == repr(s.a2) - assert string(s.a2) == u+'hello \u2345 world' - # - q = cast(BWCharP, 0) - assert str(q) == repr(q) - py.test.raises(RuntimeError, string, q) - # - def cb(p): - assert repr(p).startswith("<cdata '%s *' 0x" % typename) - return len(string(p)) - BFunc = new_function_type((BWCharP,), BInt, False) - f = callback(BFunc, cb, -42) - assert f(u+'a\u1234b') == 3 - # - if wchar4 and not pyuni4 and not _hacked_pypy_uni4(): - # try out-of-range wchar_t values - x = cast(BWChar, 1114112) - py.test.raises(ValueError, string, x) - x = cast(BWChar, -1) - py.test.raises(ValueError, string, x) - -def test_wchar_variants_mix(): - BWChar = new_primitive_type("wchar_t") - BChar16 = new_primitive_type("char16_t") - BChar32 = new_primitive_type("char32_t") - assert int(cast(BChar32, cast(BChar16, -2))) == 0xfffe - assert int(cast(BWChar, cast(BChar16, -2))) == 0xfffe - assert int(cast(BChar16, cast(BChar32, 0x0001f345))) == 0xf345 - assert int(cast(BChar16, cast(BWChar, 0x0001f345))) == 0xf345 - # - BChar16A = new_array_type(new_pointer_type(BChar16), None) - BChar32A = new_array_type(new_pointer_type(BChar32), None) - x = cast(BChar32, 'A') - py.test.raises(TypeError, newp, BChar16A, [x]) - x = cast(BChar16, 'A') - py.test.raises(TypeError, newp, BChar32A, [x]) - # - a = newp(BChar16A, u+'\U00012345') - assert len(a) == 3 - a = newp(BChar32A, u+'\U00012345') - assert len(a) == 2 # even if the Python unicode string above is 2 chars - -def test_keepalive_struct(): - # exception to the no-keepalive rule: p=newp(BStructPtr) returns a - # pointer owning the memory, and p[0] returns a pointer to the - # struct that *also* owns the memory - BStruct = new_struct_type("struct foo") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a1', new_primitive_type("int"), -1), - ('a2', new_primitive_type("int"), -1), - ('a3', new_primitive_type("int"), -1)]) - p = newp(BStructPtr) - assert repr(p) == "<cdata 'struct foo *' owning 12 bytes>" - q = p[0] - assert repr(q) == "<cdata 'struct foo' owning 12 bytes>" - q.a1 = 123456 - assert p.a1 == 123456 - r = cast(BStructPtr, p) - assert repr(r[0]).startswith("<cdata 'struct foo &' 0x") - del p - import gc; gc.collect() - assert q.a1 == 123456 - assert repr(q) == "<cdata 'struct foo' owning 12 bytes>" - assert q.a1 == 123456 - -def test_nokeepalive_struct(): - BStruct = new_struct_type("struct foo") - BStructPtr = new_pointer_type(BStruct) - BStructPtrPtr = new_pointer_type(BStructPtr) - complete_struct_or_union(BStruct, [('a1', new_primitive_type("int"), -1)]) - p = newp(BStructPtr) - pp = newp(BStructPtrPtr) - pp[0] = p - s = pp[0][0] - assert repr(s).startswith("<cdata 'struct foo &' 0x") - -def test_owning_repr(): - BInt = new_primitive_type("int") - BArray = new_array_type(new_pointer_type(BInt), None) # int[] - p = newp(BArray, 7) - assert repr(p) == "<cdata 'int[]' owning 28 bytes>" - assert sizeof(p) == 28 - # - BArray = new_array_type(new_pointer_type(BInt), 7) # int[7] - p = newp(BArray, None) - assert repr(p) == "<cdata 'int[7]' owning 28 bytes>" - assert sizeof(p) == 28 - -def test_cannot_dereference_void(): - BVoidP = new_pointer_type(new_void_type()) - p = cast(BVoidP, 123456) - with pytest.raises(TypeError): - p[0] - p = cast(BVoidP, 0) - with pytest.raises((TypeError, RuntimeError)): - p[0] - -def test_iter(): - BInt = new_primitive_type("int") - BIntP = new_pointer_type(BInt) - BArray = new_array_type(BIntP, None) # int[] - p = newp(BArray, 7) - assert list(p) == list(iter(p)) == [0] * 7 - # - py.test.raises(TypeError, iter, cast(BInt, 5)) - py.test.raises(TypeError, iter, cast(BIntP, 123456)) - -def test_cmp(): - BInt = new_primitive_type("int") - BIntP = new_pointer_type(BInt) - BVoidP = new_pointer_type(new_void_type()) - p = newp(BIntP, 123) - q = cast(BInt, 124) - assert (p == q) is False - assert (p != q) is True - assert (q == p) is False - assert (q != p) is True - if strict_compare: - 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 - assert (p == r) is True - assert (p != r) is False - assert (p > r) is False - assert (p >= r) is True - s = newp(BIntP, 125) - assert (p == s) is False - assert (p != s) is True - assert (p < s) is (p <= s) is (s > p) is (s >= p) - assert (p > s) is (p >= s) is (s < p) is (s <= p) - assert (p < s) ^ (p > s) - -def test_buffer(): - try: - import __builtin__ - except ImportError: - import builtins as __builtin__ - BShort = new_primitive_type("short") - s = newp(new_pointer_type(BShort), 100) - assert sizeof(s) == size_of_ptr() - assert sizeof(BShort) == 2 - assert len(buffer(s)) == 2 - # - BChar = new_primitive_type("char") - BCharArray = new_array_type(new_pointer_type(BChar), None) - c = newp(BCharArray, b"hi there") - # - buf = buffer(c) - assert repr(buf).startswith('<_cffi_backend.buffer object at 0x') - assert bytes(buf) == b"hi there\x00" - assert type(buf) is buffer - if sys.version_info < (3,): - assert str(buf) == "hi there\x00" - assert unicode(buf) == u+"hi there\x00" - else: - assert str(buf) == repr(buf) - # --mb_length-- - assert len(buf) == len(b"hi there\x00") - # --mb_item-- - for i in range(-12, 12): - try: - expected = b"hi there\x00"[i] - except IndexError: - with pytest.raises(IndexError): - buf[i] - else: - assert buf[i] == bitem2bchr(expected) - # --mb_slice-- - assert buf[:] == b"hi there\x00" - for i in range(-12, 12): - assert buf[i:] == b"hi there\x00"[i:] - assert buf[:i] == b"hi there\x00"[:i] - for j in range(-12, 12): - assert buf[i:j] == b"hi there\x00"[i:j] - # --misc-- - assert list(buf) == list(map(bitem2bchr, b"hi there\x00")) - # --mb_as_buffer-- - if hasattr(__builtin__, 'buffer'): # Python <= 2.7 - py.test.raises(TypeError, __builtin__.buffer, c) - bf1 = __builtin__.buffer(buf) - assert len(bf1) == len(buf) and bf1[3] == "t" - if hasattr(__builtin__, 'memoryview'): # Python >= 2.7 - py.test.raises(TypeError, memoryview, c) - mv1 = memoryview(buf) - assert len(mv1) == len(buf) and mv1[3] in (b"t", ord(b"t")) - # --mb_ass_item-- - expected = list(map(bitem2bchr, b"hi there\x00")) - for i in range(-12, 12): - try: - expected[i] = bytechr(i & 0xff) - except IndexError: - 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")) - 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" - assert buf[:] == b"HI there\x00" - buf[:2] = b"hi" - expected = list(map(bitem2bchr, b"hi there\x00")) - x = 0 - for i in range(-12, 12): - for j in range(-12, 12): - start = i if i >= 0 else i + len(buf) - stop = j if j >= 0 else j + len(buf) - start = max(0, min(len(buf), start)) - stop = max(0, min(len(buf), stop)) - sample = bytechr(x & 0xff) * (stop - start) - x += 1 - buf[i:j] = sample - expected[i:j] = map(bitem2bchr, sample) - assert list(buf) == expected - -def test_getcname(): - BUChar = new_primitive_type("unsigned char") - BArray = new_array_type(new_pointer_type(BUChar), 123) - assert getcname(BArray, "<-->") == "unsigned char<-->[123]" - -def test_errno(): - BVoid = new_void_type() - BFunc5 = new_function_type((), BVoid) - f = cast(BFunc5, _testfunc(5)) - set_errno(50) - f() - assert get_errno() == 65 - f(); f() - assert get_errno() == 95 - -def test_errno_callback(): - 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() - set_errno(e - 6) - BVoid = new_void_type() - BFunc5 = new_function_type((), BVoid) - f = callback(BFunc5, cb) - f() - assert get_errno() == 89 - f(); f() - assert get_errno() == 77 - -def test_cast_to_array(): - # not valid in C! extension to get a non-owning <cdata 'int[3]'> - BInt = new_primitive_type("int") - BIntP = new_pointer_type(BInt) - BArray = new_array_type(BIntP, 3) - x = cast(BArray, 0) - assert repr(x) == "<cdata 'int[3]' NULL>" - -def test_cast_invalid(): - BStruct = new_struct_type("struct foo") - complete_struct_or_union(BStruct, []) - p = cast(new_pointer_type(BStruct), 123456) - s = p[0] - py.test.raises(TypeError, cast, BStruct, s) - -def test_bug_float_convertion(): - BDouble = new_primitive_type("double") - BDoubleP = new_pointer_type(BDouble) - py.test.raises(TypeError, newp, BDoubleP, "foobar") - -def test_bug_delitem(): - BChar = new_primitive_type("char") - BCharP = new_pointer_type(BChar) - x = newp(BCharP) - 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)) - with pytest.raises(AttributeError): - del x.a1 - -def test_variable_length_struct(): - py.test.skip("later") - BLong = new_primitive_type("long") - BArray = new_array_type(new_pointer_type(BLong), None) - BStruct = new_struct_type("struct foo") - BStructP = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a1', BLong, -1), - ('a2', BArray, -1)]) - assert sizeof(BStruct) == size_of_long() - assert alignof(BStruct) == alignof(BLong) - # - py.test.raises(TypeError, newp, BStructP, None) - x = newp(BStructP, 5) - assert sizeof(x) == 6 * size_of_long() - x[4] = 123 - assert x[4] == 123 - with pytest.raises(IndexError): - x[5] - assert len(x.a2) == 5 - # - py.test.raises(TypeError, newp, BStructP, [123]) - x = newp(BStructP, [123, 5]) - assert x.a1 == 123 - assert len(x.a2) == 5 - assert list(x.a2) == [0] * 5 - # - x = newp(BStructP, {'a2': 5}) - assert x.a1 == 0 - assert len(x.a2) == 5 - assert list(x.a2) == [0] * 5 - # - x = newp(BStructP, [123, (4, 5)]) - assert x.a1 == 123 - assert len(x.a2) == 2 - assert list(x.a2) == [4, 5] - # - x = newp(BStructP, {'a2': (4, 5)}) - assert x.a1 == 0 - assert len(x.a2) == 2 - assert list(x.a2) == [4, 5] - -def test_autocast_int(): - BInt = new_primitive_type("int") - BIntPtr = new_pointer_type(BInt) - BLongLong = new_primitive_type("long long") - BULongLong = new_primitive_type("unsigned long long") - BULongLongPtr = new_pointer_type(BULongLong) - x = newp(BIntPtr, cast(BInt, 42)) - assert x[0] == 42 - x = newp(BIntPtr, cast(BLongLong, 42)) - assert x[0] == 42 - x = newp(BIntPtr, cast(BULongLong, 42)) - assert x[0] == 42 - x = newp(BULongLongPtr, cast(BInt, 42)) - assert x[0] == 42 - py.test.raises(OverflowError, newp, BULongLongPtr, cast(BInt, -42)) - x = cast(BInt, cast(BInt, 42)) - assert int(x) == 42 - x = cast(BInt, cast(BLongLong, 42)) - assert int(x) == 42 - x = cast(BInt, cast(BULongLong, 42)) - assert int(x) == 42 - x = cast(BULongLong, cast(BInt, 42)) - assert int(x) == 42 - x = cast(BULongLong, cast(BInt, -42)) - assert int(x) == 2 ** 64 - 42 - x = cast(BIntPtr, cast(BInt, 42)) - assert int(cast(BInt, x)) == 42 - -def test_autocast_float(): - BFloat = new_primitive_type("float") - BDouble = new_primitive_type("float") - BFloatPtr = new_pointer_type(BFloat) - x = newp(BFloatPtr, cast(BDouble, 12.5)) - assert x[0] == 12.5 - x = cast(BFloat, cast(BDouble, 12.5)) - assert float(x) == 12.5 - -def test_longdouble(): - py_py = 'PY_DOT_PY' in globals() - BInt = new_primitive_type("int") - BLongDouble = new_primitive_type("long double") - BLongDoublePtr = new_pointer_type(BLongDouble) - BLongDoubleArray = new_array_type(BLongDoublePtr, None) - a = newp(BLongDoubleArray, 1) - x = a[0] - if not py_py: - assert repr(x).startswith("<cdata 'long double' 0.0") - assert float(x) == 0.0 - assert int(x) == 0 - # - b = newp(BLongDoubleArray, [1.23]) - x = b[0] - if not py_py: - assert repr(x).startswith("<cdata 'long double' 1.23") - assert float(x) == 1.23 - assert int(x) == 1 - # - BFunc19 = new_function_type((BLongDouble, BInt), BLongDouble) - f = cast(BFunc19, _testfunc(19)) - start = lstart = 1.5 - for i in range(107): - start = 4 * start - start * start - lstart = f(lstart, 1) - lother = f(1.5, 107) - if not py_py: - assert float(lstart) == float(lother) - assert repr(lstart) == repr(lother) - if sizeof(BLongDouble) > sizeof(new_primitive_type("double")): - assert float(lstart) != start - assert repr(lstart).startswith("<cdata 'long double' ") - # - c = newp(BLongDoubleArray, [lstart]) - x = c[0] - assert float(f(lstart, 107)) == float(f(x, 107)) - -def test_get_array_of_length_zero(): - for length in [0, 5, 10]: - BLong = new_primitive_type("long") - BLongP = new_pointer_type(BLong) - BArray0 = new_array_type(BLongP, length) - BStruct = new_struct_type("struct foo") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a1', BArray0, -1)]) - p = newp(BStructPtr, None) - if length == 0: - assert repr(p.a1).startswith("<cdata 'long *' 0x") - else: - assert repr(p.a1).startswith("<cdata 'long[%d]' 0x" % length) - -def test_nested_anonymous_struct(): - BInt = new_primitive_type("int") - BChar = new_primitive_type("char") - BStruct = new_struct_type("struct foo") - BInnerStruct = new_struct_type("struct foo") - complete_struct_or_union(BInnerStruct, [('a1', BInt, -1), - ('a2', BChar, -1)]) - complete_struct_or_union(BStruct, [('', BInnerStruct, -1), - ('a3', BChar, -1)]) - assert sizeof(BInnerStruct) == sizeof(BInt) * 2 # with alignment - assert sizeof(BStruct) == sizeof(BInt) * 3 # 'a3' is placed after - d = BStruct.fields - assert len(d) == 3 - assert d[0][0] == 'a1' - assert d[0][1].type is BInt - assert d[0][1].offset == 0 - assert d[0][1].bitshift == -1 - assert d[0][1].bitsize == -1 - assert d[1][0] == 'a2' - assert d[1][1].type is BChar - assert d[1][1].offset == sizeof(BInt) - assert d[1][1].bitshift == -1 - assert d[1][1].bitsize == -1 - assert d[2][0] == 'a3' - assert d[2][1].type is BChar - assert d[2][1].offset == sizeof(BInt) * 2 - assert d[2][1].bitshift == -1 - assert d[2][1].bitsize == -1 - -def test_nested_anonymous_struct_2(): - BInt = new_primitive_type("int") - BStruct = new_struct_type("struct foo") - BInnerUnion = new_union_type("union bar") - complete_struct_or_union(BInnerUnion, [('a1', BInt, -1), - ('a2', BInt, -1)]) - complete_struct_or_union(BStruct, [('b1', BInt, -1), - ('', BInnerUnion, -1), - ('b2', BInt, -1)]) - assert sizeof(BInnerUnion) == sizeof(BInt) - assert sizeof(BStruct) == sizeof(BInt) * 3 - fields = [(name, fld.offset, fld.flags) for (name, fld) in BStruct.fields] - assert fields == [ - ('b1', 0 * sizeof(BInt), 0), - ('a1', 1 * sizeof(BInt), 0), - ('a2', 1 * sizeof(BInt), 1), - ('b2', 2 * sizeof(BInt), 0), - ] - -def test_sizeof_union(): - # a union has the largest alignment of its members, and a total size - # that is the largest of its items *possibly further aligned* if - # another smaller item has a larger alignment... - BChar = new_primitive_type("char") - BShort = new_primitive_type("short") - assert sizeof(BShort) == alignof(BShort) == 2 - BStruct = new_struct_type("struct foo") - complete_struct_or_union(BStruct, [('a1', BChar), - ('a2', BChar), - ('a3', BChar)]) - assert sizeof(BStruct) == 3 and alignof(BStruct) == 1 - BUnion = new_union_type("union u") - complete_struct_or_union(BUnion, [('s', BStruct), - ('i', BShort)]) - assert sizeof(BUnion) == 4 - assert alignof(BUnion) == 2 - -def test_unaligned_struct(): - BInt = new_primitive_type("int") - BStruct = new_struct_type("struct foo") - complete_struct_or_union(BStruct, [('b', BInt, -1, 1)], - None, 5, 1) - -def test_CData_CType(): - CData, CType = _get_types() - BChar = new_primitive_type("char") - BCharP = new_pointer_type(BChar) - nullchr = cast(BChar, 0) - chrref = newp(BCharP, None) - assert isinstance(nullchr, CData) - assert isinstance(chrref, CData) - assert not isinstance(BChar, CData) - assert not isinstance(nullchr, CType) - assert not isinstance(chrref, CType) - assert isinstance(BChar, CType) - -def test_no_cdata_float(): - BInt = new_primitive_type("int") - BIntP = new_pointer_type(BInt) - BUInt = new_primitive_type("unsigned int") - BUIntP = new_pointer_type(BUInt) - BFloat = new_primitive_type("float") - py.test.raises(TypeError, newp, BIntP, cast(BFloat, 0.0)) - py.test.raises(TypeError, newp, BUIntP, cast(BFloat, 0.0)) - -def test_bool(): - BBool = new_primitive_type("_Bool") - BBoolP = new_pointer_type(BBool) - assert int(cast(BBool, False)) == 0 - assert int(cast(BBool, True)) == 1 - assert bool(cast(BBool, False)) is False # since 1.7 - assert bool(cast(BBool, True)) is True - assert int(cast(BBool, 3)) == 1 - assert int(cast(BBool, long(3))) == 1 - assert int(cast(BBool, long(10)**4000)) == 1 - assert int(cast(BBool, -0.1)) == 1 - assert int(cast(BBool, -0.0)) == 0 - assert int(cast(BBool, '\x00')) == 0 - assert int(cast(BBool, '\xff')) == 1 - assert newp(BBoolP, False)[0] == 0 - assert newp(BBoolP, True)[0] == 1 - assert newp(BBoolP, 0)[0] == 0 - assert newp(BBoolP, 1)[0] == 1 - py.test.raises(TypeError, newp, BBoolP, 1.0) - py.test.raises(TypeError, newp, BBoolP, '\x00') - py.test.raises(OverflowError, newp, BBoolP, 2) - py.test.raises(OverflowError, newp, BBoolP, -1) - BCharP = new_pointer_type(new_primitive_type("char")) - p = newp(BCharP, b'\x01') - q = cast(BBoolP, p) - assert q[0] is True - p = newp(BCharP, b'\x00') - q = cast(BBoolP, p) - assert q[0] is False - py.test.raises(TypeError, string, cast(BBool, False)) - BDouble = new_primitive_type("double") - assert int(cast(BBool, cast(BDouble, 0.1))) == 1 - assert int(cast(BBool, cast(BDouble, 0.0))) == 0 - BBoolA = new_array_type(BBoolP, None) - p = newp(BBoolA, b'\x01\x00') - assert p[0] is True - assert p[1] is False - -def test_bool_forbidden_cases(): - BBool = new_primitive_type("_Bool") - BBoolP = new_pointer_type(BBool) - BBoolA = new_array_type(BBoolP, None) - BCharP = new_pointer_type(new_primitive_type("char")) - p = newp(BCharP, b'X') - q = cast(BBoolP, p) - 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 - py.test.raises(OverflowError, newp, BBoolP, 2) - py.test.raises(OverflowError, newp, BBoolP, -1) - py.test.raises(ValueError, newp, BBoolA, b'\x00\x01\x02') - py.test.raises(OverflowError, newp, BBoolA, [0, 1, 2]) - py.test.raises(TypeError, string, newp(BBoolP, 1)) - py.test.raises(TypeError, string, newp(BBoolA, [1])) - -def test_typeoffsetof(): - BChar = new_primitive_type("char") - BStruct = new_struct_type("struct foo") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a1', BChar, -1), - ('a2', BChar, -1), - ('a3', BChar, -1)]) - py.test.raises(TypeError, typeoffsetof, BStructPtr, None) - py.test.raises(TypeError, typeoffsetof, BStruct, None) - assert typeoffsetof(BStructPtr, 'a1') == (BChar, 0) - assert typeoffsetof(BStruct, 'a1') == (BChar, 0) - assert typeoffsetof(BStructPtr, 'a2') == (BChar, 1) - assert typeoffsetof(BStruct, 'a3') == (BChar, 2) - assert typeoffsetof(BStructPtr, 'a2', 0) == (BChar, 1) - assert typeoffsetof(BStruct, u+'a3') == (BChar, 2) - py.test.raises(TypeError, typeoffsetof, BStructPtr, 'a2', 1) - py.test.raises(KeyError, typeoffsetof, BStructPtr, 'a4') - py.test.raises(KeyError, typeoffsetof, BStruct, 'a5') - py.test.raises(TypeError, typeoffsetof, BStruct, 42) - py.test.raises(TypeError, typeoffsetof, BChar, 'a1') - -def test_typeoffsetof_array(): - BInt = new_primitive_type("int") - BIntP = new_pointer_type(BInt) - BArray = new_array_type(BIntP, None) - py.test.raises(TypeError, typeoffsetof, BArray, None) - py.test.raises(TypeError, typeoffsetof, BArray, 'a1') - assert typeoffsetof(BArray, 51) == (BInt, 51 * size_of_int()) - assert typeoffsetof(BIntP, 51) == (BInt, 51 * size_of_int()) - assert typeoffsetof(BArray, -51) == (BInt, -51 * size_of_int()) - MAX = sys.maxsize // size_of_int() - assert typeoffsetof(BArray, MAX) == (BInt, MAX * size_of_int()) - assert typeoffsetof(BIntP, MAX) == (BInt, MAX * size_of_int()) - py.test.raises(OverflowError, typeoffsetof, BArray, MAX + 1) - -def test_typeoffsetof_no_bitfield(): - BInt = new_primitive_type("int") - BStruct = new_struct_type("struct foo") - complete_struct_or_union(BStruct, [('a1', BInt, 4)]) - py.test.raises(TypeError, typeoffsetof, BStruct, 'a1') - -def test_rawaddressof(): - BChar = new_primitive_type("char") - BCharP = new_pointer_type(BChar) - BStruct = new_struct_type("struct foo") - BStructPtr = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('a1', BChar, -1), - ('a2', BChar, -1), - ('a3', BChar, -1)]) - p = newp(BStructPtr) - assert repr(p) == "<cdata 'struct foo *' owning 3 bytes>" - s = p[0] - assert repr(s) == "<cdata 'struct foo' owning 3 bytes>" - a = rawaddressof(BStructPtr, s, 0) - assert repr(a).startswith("<cdata 'struct foo *' 0x") - py.test.raises(TypeError, rawaddressof, BStruct, s, 0) - b = rawaddressof(BCharP, s, 0) - assert b == cast(BCharP, p) - c = rawaddressof(BStructPtr, a, 0) - assert c == a - py.test.raises(TypeError, rawaddressof, BStructPtr, cast(BChar, '?'), 0) - # - d = rawaddressof(BCharP, s, 1) - assert d == cast(BCharP, p) + 1 - # - e = cast(BCharP, 109238) - f = rawaddressof(BCharP, e, 42) - assert f == e + 42 - # - BCharA = new_array_type(BCharP, None) - e = newp(BCharA, 50) - f = rawaddressof(BCharP, e, 42) - assert f == e + 42 - -def test_newp_signed_unsigned_char(): - BCharArray = new_array_type( - new_pointer_type(new_primitive_type("char")), None) - p = newp(BCharArray, b"foo") - assert len(p) == 4 - assert list(p) == [b"f", b"o", b"o", b"\x00"] - # - BUCharArray = new_array_type( - new_pointer_type(new_primitive_type("unsigned char")), None) - p = newp(BUCharArray, b"fo\xff") - assert len(p) == 4 - assert list(p) == [ord("f"), ord("o"), 0xff, 0] - # - BSCharArray = new_array_type( - new_pointer_type(new_primitive_type("signed char")), None) - p = newp(BSCharArray, b"fo\xff") - assert len(p) == 4 - assert list(p) == [ord("f"), ord("o"), -1, 0] - -def test_newp_from_bytearray_doesnt_work(): - BCharArray = new_array_type( - new_pointer_type(new_primitive_type("char")), None) - py.test.raises(TypeError, newp, BCharArray, bytearray(b"foo")) - p = newp(BCharArray, 5) - buffer(p)[:] = bytearray(b"foo.\x00") - assert len(p) == 5 - assert list(p) == [b"f", b"o", b"o", b".", b"\x00"] - p[1:3] = bytearray(b"XY") - assert list(p) == [b"f", b"X", b"Y", b".", b"\x00"] - -def test_string_assignment_to_byte_array(): - BByteArray = new_array_type( - new_pointer_type(new_primitive_type("unsigned char")), None) - p = newp(BByteArray, 5) - p[0:3] = bytearray(b"XYZ") - assert list(p) == [ord("X"), ord("Y"), ord("Z"), 0, 0] - -# XXX hack -if sys.version_info >= (3,): - try: - import posix, io - posix.fdopen = io.open - except ImportError: - pass # win32 - -def test_FILE(): - if sys.platform == "win32": - py.test.skip("testing FILE not implemented") - # - BFILE = new_struct_type("struct _IO_FILE") - BFILEP = new_pointer_type(BFILE) - BChar = new_primitive_type("char") - BCharP = new_pointer_type(BChar) - BInt = new_primitive_type("int") - BFunc = new_function_type((BCharP, BFILEP), BInt, False) - BFunc2 = new_function_type((BFILEP, BCharP), BInt, True) - ll = find_and_load_library('c') - fputs = ll.load_function(BFunc, "fputs") - fscanf = ll.load_function(BFunc2, "fscanf") - # - import posix - fdr, fdw = posix.pipe() - fr1 = posix.fdopen(fdr, 'rb', 256) - fw1 = posix.fdopen(fdw, 'wb', 256) - # - fw1.write(b"X") - res = fputs(b"hello world\n", fw1) - assert res >= 0 - fw1.flush() # should not be needed - # - p = newp(new_array_type(BCharP, 100), None) - res = fscanf(fr1, b"%s\n", p) - assert res == 1 - assert string(p) == b"Xhello" - fr1.close() - fw1.close() - -def test_FILE_only_for_FILE_arg(): - if sys.platform == "win32": - py.test.skip("testing FILE not implemented") - # - B_NOT_FILE = new_struct_type("struct NOT_FILE") - B_NOT_FILEP = new_pointer_type(B_NOT_FILE) - BChar = new_primitive_type("char") - BCharP = new_pointer_type(BChar) - BInt = new_primitive_type("int") - BFunc = new_function_type((BCharP, B_NOT_FILEP), BInt, False) - ll = find_and_load_library('c') - fputs = ll.load_function(BFunc, "fputs") - # - import posix - fdr, fdw = posix.pipe() - fr1 = posix.fdopen(fdr, 'r') - fw1 = posix.fdopen(fdw, 'w') - # - e = py.test.raises(TypeError, fputs, b"hello world\n", fw1) - assert str(e.value).startswith( - "initializer for ctype 'struct NOT_FILE *' must " - "be a cdata pointer, not ") - -def test_FILE_object(): - if sys.platform == "win32": - py.test.skip("testing FILE not implemented") - # - BFILE = new_struct_type("FILE") - BFILEP = new_pointer_type(BFILE) - BChar = new_primitive_type("char") - BCharP = new_pointer_type(BChar) - BInt = new_primitive_type("int") - BFunc = new_function_type((BCharP, BFILEP), BInt, False) - BFunc2 = new_function_type((BFILEP,), BInt, False) - ll = find_and_load_library('c') - fputs = ll.load_function(BFunc, "fputs") - fileno = ll.load_function(BFunc2, "fileno") - # - import posix - fdr, fdw = posix.pipe() - fw1 = posix.fdopen(fdw, 'wb', 256) - # - fw1p = cast(BFILEP, fw1) - fw1.write(b"X") - fw1.flush() - res = fputs(b"hello\n", fw1p) - assert res >= 0 - res = fileno(fw1p) - assert (res == fdw) == (sys.version_info < (3,)) - fw1.close() - # - data = posix.read(fdr, 256) - assert data == b"Xhello\n" - posix.close(fdr) - -def test_errno_saved(): - set_errno(42) - # a random function that will reset errno to 0 (at least on non-windows) - import os; os.stat('.') - # - res = get_errno() - assert res == 42 - -def test_GetLastError(): - if sys.platform != "win32": - py.test.skip("GetLastError(): only for Windows") - # - lib = find_and_load_library('KERNEL32.DLL') - BInt = new_primitive_type("int") - BVoid = new_void_type() - BFunc1 = new_function_type((BInt,), BVoid, False) - BFunc2 = new_function_type((), BInt, False) - SetLastError = lib.load_function(BFunc1, "SetLastError") - GetLastError = lib.load_function(BFunc2, "GetLastError") - # - SetLastError(42) - # a random function that will reset the real GetLastError() to 0 - import nt; nt.stat('.') - # - res = GetLastError() - assert res == 42 - # - SetLastError(2) - code, message = getwinerror() - assert code == 2 - assert message == "The system cannot find the file specified" - # - code, message = getwinerror(1155) - assert code == 1155 - assert message == ("No application is associated with the " - "specified file for this operation") - -def test_nonstandard_integer_types(): - for typename in ['int8_t', 'uint8_t', 'int16_t', 'uint16_t', 'int32_t', - 'uint32_t', 'int64_t', 'uint64_t', 'intptr_t', - 'uintptr_t', 'ptrdiff_t', 'size_t', 'ssize_t', - 'int_least8_t', 'uint_least8_t', - 'int_least16_t', 'uint_least16_t', - 'int_least32_t', 'uint_least32_t', - 'int_least64_t', 'uint_least64_t', - 'int_fast8_t', 'uint_fast8_t', - 'int_fast16_t', 'uint_fast16_t', - 'int_fast32_t', 'uint_fast32_t', - 'int_fast64_t', 'uint_fast64_t', - 'intmax_t', 'uintmax_t']: - new_primitive_type(typename) # works - -def test_cannot_convert_unicode_to_charp(): - BCharP = new_pointer_type(new_primitive_type("char")) - BCharArray = new_array_type(BCharP, None) - py.test.raises(TypeError, newp, BCharArray, u+'foobar') - -def test_buffer_keepalive(): - BCharP = new_pointer_type(new_primitive_type("char")) - BCharArray = new_array_type(BCharP, None) - buflist = [] - for i in range(20): - c = newp(BCharArray, str2bytes("hi there %d" % i)) - buflist.append(buffer(c)) - import gc; gc.collect() - for i in range(20): - buf = buflist[i] - assert buf[:] == str2bytes("hi there %d\x00" % i) - -def test_slice(): - BIntP = new_pointer_type(new_primitive_type("int")) - BIntArray = new_array_type(BIntP, None) - c = newp(BIntArray, 5) - assert len(c) == 5 - assert repr(c) == "<cdata 'int[]' owning 20 bytes>" - d = c[1:4] - assert len(d) == 3 - assert repr(d) == "<cdata 'int[]' sliced length 3>" - d[0] = 123 - d[2] = 456 - assert c[1] == 123 - assert c[3] == 456 - assert d[2] == 456 - with pytest.raises(IndexError): - d[3] - with pytest.raises(IndexError): - d[-1] - -def test_slice_ptr(): - BIntP = new_pointer_type(new_primitive_type("int")) - BIntArray = new_array_type(BIntP, None) - c = newp(BIntArray, 5) - d = (c+1)[0:2] - assert len(d) == 2 - assert repr(d) == "<cdata 'int[]' sliced length 2>" - d[1] += 50 - assert c[2] == 50 - -def test_slice_array_checkbounds(): - BIntP = new_pointer_type(new_primitive_type("int")) - BIntArray = new_array_type(BIntP, None) - c = newp(BIntArray, 5) - c[0:5] - assert len(c[5:5]) == 0 - with pytest.raises(IndexError): - c[-1:1] - cp = c + 0 - cp[-1:1] - -def test_nonstandard_slice(): - BIntP = new_pointer_type(new_primitive_type("int")) - BIntArray = new_array_type(BIntP, None) - c = newp(BIntArray, 5) - with pytest.raises(IndexError) as e: - c[:5] - assert str(e.value) == "slice start must be specified" - with pytest.raises(IndexError) as e: - c[4:] - assert str(e.value) == "slice stop must be specified" - with pytest.raises(IndexError) as e: - c[1:2:3] - assert str(e.value) == "slice with step not supported" - with pytest.raises(IndexError) as e: - c[1:2:1] - assert str(e.value) == "slice with step not supported" - with pytest.raises(IndexError) as e: - c[4:2] - assert str(e.value) == "slice start > stop" - with pytest.raises(IndexError) as e: - c[6:6] - assert str(e.value) == "index too large (expected 6 <= 5)" - -def test_setslice(): - BIntP = new_pointer_type(new_primitive_type("int")) - BIntArray = new_array_type(BIntP, None) - c = newp(BIntArray, 5) - c[1:3] = [100, 200] - assert list(c) == [0, 100, 200, 0, 0] - cp = c + 3 - cp[-1:1] = [300, 400] - assert list(c) == [0, 100, 300, 400, 0] - cp[-1:1] = iter([500, 600]) - assert list(c) == [0, 100, 500, 600, 0] - with pytest.raises(ValueError): - cp[-1:1] = [1000] - assert list(c) == [0, 100, 1000, 600, 0] - with pytest.raises(ValueError): - cp[-1:1] = (700, 800, 900) - assert list(c) == [0, 100, 700, 800, 0] - -def test_setslice_array(): - BIntP = new_pointer_type(new_primitive_type("int")) - BIntArray = new_array_type(BIntP, None) - c = newp(BIntArray, 5) - d = newp(BIntArray, [10, 20, 30]) - c[1:4] = d - assert list(c) == [0, 10, 20, 30, 0] - # - BShortP = new_pointer_type(new_primitive_type("short")) - BShortArray = new_array_type(BShortP, None) - d = newp(BShortArray, [40, 50]) - c[1:3] = d - assert list(c) == [0, 40, 50, 30, 0] - -def test_cdata_name_module_doc(): - p = new_primitive_type("signed char") - x = cast(p, 17) - assert x.__module__ == '_cffi_backend' - assert x.__name__ == '<cdata>' - assert hasattr(x, '__doc__') - -def test_different_types_of_ptr_equality(): - BVoidP = new_pointer_type(new_void_type()) - BIntP = new_pointer_type(new_primitive_type("int")) - x = cast(BVoidP, 12345) - assert x == cast(BIntP, 12345) - assert x != cast(BIntP, 12344) - assert hash(x) == hash(cast(BIntP, 12345)) - -def test_new_handle(): - import _weakref - BVoidP = new_pointer_type(new_void_type()) - BCharP = new_pointer_type(new_primitive_type("char")) - class mylist(list): - pass - o = mylist([2, 3, 4]) - x = newp_handle(BVoidP, o) - assert repr(x) == "<cdata 'void *' handle to [2, 3, 4]>" - assert x - assert from_handle(x) is o - assert from_handle(cast(BCharP, x)) is o - wr = _weakref.ref(o) - del o - import gc; gc.collect() - assert wr() is not None - assert from_handle(x) == list((2, 3, 4)) - assert from_handle(cast(BCharP, x)) == list((2, 3, 4)) - del x - for i in range(3): - if wr() is not None: - import gc; gc.collect() - assert wr() is None - py.test.raises(RuntimeError, from_handle, cast(BCharP, 0)) - -def test_new_handle_cycle(): - import _weakref - BVoidP = new_pointer_type(new_void_type()) - class A(object): - pass - o = A() - o.cycle = newp_handle(BVoidP, o) - wr = _weakref.ref(o) - del o - for i in range(3): - if wr() is not None: - import gc; gc.collect() - assert wr() is None - -def _test_bitfield_details(flag): - BChar = new_primitive_type("char") - BShort = new_primitive_type("short") - BInt = new_primitive_type("int") - BUInt = new_primitive_type("unsigned int") - BStruct = new_struct_type("struct foo1") - complete_struct_or_union(BStruct, [('a', BChar, -1), - ('b1', BInt, 9), - ('b2', BUInt, 7), - ('c', BChar, -1)], -1, -1, -1, flag) - if not (flag & SF_MSVC_BITFIELDS): # gcc, any variant - assert typeoffsetof(BStruct, 'c') == (BChar, 3) - assert sizeof(BStruct) == 4 - else: # msvc - assert typeoffsetof(BStruct, 'c') == (BChar, 8) - assert sizeof(BStruct) == 12 - assert alignof(BStruct) == 4 - # - p = newp(new_pointer_type(BStruct), None) - p.a = b'A' - p.b1 = -201 - p.b2 = 99 - p.c = b'\x9D' - raw = buffer(p)[:] - if sys.byteorder == 'little': - if flag & SF_MSVC_BITFIELDS: - assert raw == b'A\x00\x00\x007\xC7\x00\x00\x9D\x00\x00\x00' - elif flag & SF_GCC_LITTLE_ENDIAN: - assert raw == b'A7\xC7\x9D' - elif flag & SF_GCC_BIG_ENDIAN: - assert raw == b'A\xE3\x9B\x9D' - else: - raise AssertionError("bad flag") - else: - if flag & SF_MSVC_BITFIELDS: - assert raw == b'A\x00\x00\x00\x00\x00\xC77\x9D\x00\x00\x00' - elif flag & SF_GCC_LITTLE_ENDIAN: - assert raw == b'A\xC77\x9D' - elif flag & SF_GCC_BIG_ENDIAN: - assert raw == b'A\x9B\xE3\x9D' - else: - raise AssertionError("bad flag") - # - BStruct = new_struct_type("struct foo2") - complete_struct_or_union(BStruct, [('a', BChar, -1), - ('', BShort, 9), - ('c', BChar, -1)], -1, -1, -1, flag) - assert typeoffsetof(BStruct, 'c') == (BChar, 4) - if flag & SF_MSVC_BITFIELDS: - assert sizeof(BStruct) == 6 - assert alignof(BStruct) == 2 - elif flag & SF_GCC_X86_BITFIELDS: - assert sizeof(BStruct) == 5 - assert alignof(BStruct) == 1 - elif flag & SF_GCC_ARM_BITFIELDS: - assert sizeof(BStruct) == 6 - assert alignof(BStruct) == 2 - else: - raise AssertionError("bad flag") - # - BStruct = new_struct_type("struct foo2") - complete_struct_or_union(BStruct, [('a', BChar, -1), - ('', BInt, 0), - ('', BInt, 0), - ('c', BChar, -1)], -1, -1, -1, flag) - if flag & SF_MSVC_BITFIELDS: - assert typeoffsetof(BStruct, 'c') == (BChar, 1) - assert sizeof(BStruct) == 2 - assert alignof(BStruct) == 1 - elif flag & SF_GCC_X86_BITFIELDS: - assert typeoffsetof(BStruct, 'c') == (BChar, 4) - assert sizeof(BStruct) == 5 - assert alignof(BStruct) == 1 - elif flag & SF_GCC_ARM_BITFIELDS: - assert typeoffsetof(BStruct, 'c') == (BChar, 4) - assert sizeof(BStruct) == 8 - assert alignof(BStruct) == 4 - else: - raise AssertionError("bad flag") - - -SF_MSVC_BITFIELDS = 0x01 -SF_GCC_ARM_BITFIELDS = 0x02 -SF_GCC_X86_BITFIELDS = 0x10 - -SF_GCC_BIG_ENDIAN = 0x04 -SF_GCC_LITTLE_ENDIAN = 0x40 - -SF_PACKED = 0x08 - -def test_bitfield_as_x86_gcc(): - _test_bitfield_details(flag=SF_GCC_X86_BITFIELDS|SF_GCC_LITTLE_ENDIAN) - -def test_bitfield_as_msvc(): - _test_bitfield_details(flag=SF_MSVC_BITFIELDS|SF_GCC_LITTLE_ENDIAN) - -def test_bitfield_as_arm_gcc(): - _test_bitfield_details(flag=SF_GCC_ARM_BITFIELDS|SF_GCC_LITTLE_ENDIAN) - -def test_bitfield_as_ppc_gcc(): - # PowerPC uses the same format as X86, but is big-endian - _test_bitfield_details(flag=SF_GCC_X86_BITFIELDS|SF_GCC_BIG_ENDIAN) - - -def test_struct_array_no_length(): - BInt = new_primitive_type("int") - BIntP = new_pointer_type(BInt) - BArray = new_array_type(BIntP, None) - BStruct = new_struct_type("foo") - py.test.raises(TypeError, complete_struct_or_union, - BStruct, [('x', BArray), - ('y', BInt)]) - # - BStruct = new_struct_type("foo") - complete_struct_or_union(BStruct, [('x', BInt), - ('y', BArray)]) - assert sizeof(BStruct) == size_of_int() - d = BStruct.fields - assert len(d) == 2 - assert d[0][0] == 'x' - assert d[0][1].type is BInt - assert d[0][1].offset == 0 - assert d[0][1].bitshift == -1 - assert d[0][1].bitsize == -1 - assert d[1][0] == 'y' - assert d[1][1].type is BArray - assert d[1][1].offset == size_of_int() - assert d[1][1].bitshift == -2 - assert d[1][1].bitsize == -1 - # - p = newp(new_pointer_type(BStruct)) - p.x = 42 - assert p.x == 42 - assert typeof(p.y) is BArray - assert len(p.y) == 0 - assert p.y == cast(BIntP, p) + 1 - # - p = newp(new_pointer_type(BStruct), [100]) - assert p.x == 100 - assert len(p.y) == 0 - # - # Tests for - # ffi.new("struct_with_var_array *", [field.., [the_array_items..]]) - # ffi.new("struct_with_var_array *", [field.., array_size]) - plist = [] - for i in range(20): - if i % 2 == 0: - p = newp(new_pointer_type(BStruct), [100, [200, i, 400]]) - else: - p = newp(new_pointer_type(BStruct), [100, 3]) - p.y[1] = i - p.y[0] = 200 - assert p.y[2] == 0 - p.y[2] = 400 - assert len(p.y) == 3 - assert len(p[0].y) == 3 - assert len(buffer(p)) == sizeof(BInt) * 4 - assert sizeof(p[0]) == sizeof(BInt) * 4 - plist.append(p) - for i in range(20): - p = plist[i] - assert p.x == 100 - assert p.y[0] == 200 - assert p.y[1] == i - assert p.y[2] == 400 - assert list(p.y) == [200, i, 400] - # - # the following assignment works, as it normally would, for any array field - p.y = [501, 601] - assert list(p.y) == [501, 601, 400] - p[0].y = [500, 600] - assert list(p[0].y) == [500, 600, 400] - assert repr(p) == "<cdata 'foo *' owning %d bytes>" % ( - sizeof(BStruct) + 3 * sizeof(BInt),) - assert repr(p[0]) == "<cdata 'foo' owning %d bytes>" % ( - sizeof(BStruct) + 3 * sizeof(BInt),) - assert sizeof(p[0]) == sizeof(BStruct) + 3 * sizeof(BInt) - # - # from a non-owning pointer, we can't get the length - q = cast(new_pointer_type(BStruct), p) - assert q.y[0] == 500 - assert q[0].y[0] == 500 - py.test.raises(TypeError, len, q.y) - py.test.raises(TypeError, len, q[0].y) - assert typeof(q.y) is BIntP - assert typeof(q[0].y) is BIntP - assert sizeof(q[0]) == sizeof(BStruct) - # - # error cases - 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... - BStruct2 = new_struct_type("bar") - complete_struct_or_union(BStruct2, [('f', BStruct), - ('n', BInt)]) - p = newp(new_pointer_type(BStruct2), {'n': 42}) - assert p.n == 42 - # - # more error cases - py.test.raises(TypeError, newp, new_pointer_type(BStruct), [100, None]) - BArray4 = new_array_type(BIntP, 4) - BStruct4 = new_struct_type("test4") - complete_struct_or_union(BStruct4, [('a', BArray4)]) # not varsized - py.test.raises(TypeError, newp, new_pointer_type(BStruct4), [None]) - py.test.raises(TypeError, newp, new_pointer_type(BStruct4), [4]) - p = newp(new_pointer_type(BStruct4), [[10, 20, 30]]) - assert p.a[0] == 10 - 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") - BIntP = new_pointer_type(BInt) - BArray = new_array_type(BIntP, None) - BStruct = new_struct_type("foo") - complete_struct_or_union(BStruct, [('x', BArray, -1, 0), # actually 3 items - ('y', BInt, -1, 12)]) - p = newp(new_pointer_type(BStruct), [[10, 20], 30]) - assert p.x[0] == 10 - assert p.x[1] == 20 - assert p.x[2] == 0 - assert p.y == 30 - p = newp(new_pointer_type(BStruct), {'x': [40], 'y': 50}) - assert p.x[0] == 40 - assert p.x[1] == 0 - assert p.x[2] == 0 - assert p.y == 50 - p = newp(new_pointer_type(BStruct), {'y': 60}) - assert p.x[0] == 0 - assert p.x[1] == 0 - assert p.x[2] == 0 - assert p.y == 60 - # - # This "should" work too, allocating a larger structure - # (a bit strange in this case, but useful in general) - plist = [] - for i in range(20): - p = newp(new_pointer_type(BStruct), [[10, 20, 30, 40, 50, 60, 70]]) - plist.append(p) - for i in range(20): - p = plist[i] - assert p.x[0] == 10 - assert p.x[1] == 20 - assert p.x[2] == 30 - assert p.x[3] == 40 == p.y - assert p.x[4] == 50 - assert p.x[5] == 60 - assert p.x[6] == 70 - -def test_struct_array_not_aligned(): - # struct a { int x; char y; char z[]; }; - # ends up of size 8, but 'z' is at offset 5 - BChar = new_primitive_type("char") - BInt = new_primitive_type("int") - BCharP = new_pointer_type(BChar) - BArray = new_array_type(BCharP, None) - BStruct = new_struct_type("foo") - complete_struct_or_union(BStruct, [('x', BInt), - ('y', BChar), - ('z', BArray)]) - assert sizeof(BStruct) == 2 * size_of_int() - def offsetof(BType, fieldname): - return typeoffsetof(BType, fieldname)[1] - base = offsetof(BStruct, 'z') - assert base == size_of_int() + 1 - # - p = newp(new_pointer_type(BStruct), {'z': 3}) - assert sizeof(p[0]) == base + 3 - q = newp(new_pointer_type(BStruct), {'z': size_of_int()}) - assert sizeof(q) == size_of_ptr() - assert sizeof(q[0]) == base + size_of_int() - assert len(p.z) == 3 - assert len(p[0].z) == 3 - assert len(q.z) == size_of_int() - assert len(q[0].z) == size_of_int() - -def test_ass_slice(): - BChar = new_primitive_type("char") - BArray = new_array_type(new_pointer_type(BChar), None) - p = newp(BArray, b"foobar") - 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"] - 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) - BArray = new_array_type(new_pointer_type(BUniChar), None) - p = newp(BArray, u+"foobar") - 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"] - 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() - BInt = new_primitive_type("intptr_t") - p = cast(new_pointer_type(BVoid), 100000) - assert int(cast(BInt, p)) == 100000 - assert int(cast(BInt, p + 42)) == 100042 - assert int(cast(BInt, p - (-42))) == 100042 - assert (p + 42) - p == 42 - q = cast(new_pointer_type(new_primitive_type("char")), 100000) - 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") - BArray = new_array_type(new_pointer_type(BInt), 10) - p = newp(BArray, None) - assert sizeof(p[2:9]) == 7 * sizeof(BInt) - -def test_packed(): - BLong = new_primitive_type("long") - BChar = new_primitive_type("char") - BShort = new_primitive_type("short") - for extra_args in [(SF_PACKED,), (0, 1)]: - BStruct = new_struct_type("struct foo") - complete_struct_or_union(BStruct, [('a1', BLong, -1), - ('a2', BChar, -1), - ('a3', BShort, -1)], - None, -1, -1, *extra_args) - d = BStruct.fields - assert len(d) == 3 - assert d[0][0] == 'a1' - assert d[0][1].type is BLong - assert d[0][1].offset == 0 - assert d[0][1].bitshift == -1 - assert d[0][1].bitsize == -1 - assert d[1][0] == 'a2' - assert d[1][1].type is BChar - assert d[1][1].offset == sizeof(BLong) - assert d[1][1].bitshift == -1 - assert d[1][1].bitsize == -1 - assert d[2][0] == 'a3' - assert d[2][1].type is BShort - assert d[2][1].offset == sizeof(BLong) + sizeof(BChar) - assert d[2][1].bitshift == -1 - assert d[2][1].bitsize == -1 - assert sizeof(BStruct) == sizeof(BLong) + sizeof(BChar) + sizeof(BShort) - assert alignof(BStruct) == 1 - # - BStruct2 = new_struct_type("struct foo") - complete_struct_or_union(BStruct2, [('b1', BChar, -1), - ('b2', BLong, -1)], - None, -1, -1, 0, 2) - d = BStruct2.fields - assert len(d) == 2 - assert d[0][0] == 'b1' - assert d[0][1].type is BChar - assert d[0][1].offset == 0 - assert d[0][1].bitshift == -1 - assert d[0][1].bitsize == -1 - assert d[1][0] == 'b2' - assert d[1][1].type is BLong - assert d[1][1].offset == 2 - assert d[1][1].bitshift == -1 - assert d[1][1].bitsize == -1 - assert sizeof(BStruct2) == 2 + sizeof(BLong) - assert alignof(BStruct2) == 2 - -def test_packed_with_bitfields(): - if sys.platform == "win32": - py.test.skip("testing gcc behavior") - BLong = new_primitive_type("long") - BChar = new_primitive_type("char") - BStruct = new_struct_type("struct foo") - py.test.raises(NotImplementedError, - complete_struct_or_union, - BStruct, [('a1', BLong, 30), - ('a2', BChar, 5)], - None, -1, -1, SF_PACKED) - -def test_from_buffer(): - import array - a = array.array('H', [10000, 20000, 30000]) - BChar = new_primitive_type("char") - BCharP = new_pointer_type(BChar) - BCharA = new_array_type(BCharP, None) - c = from_buffer(BCharA, a) - assert typeof(c) is BCharA - assert len(c) == 6 - assert repr(c) == "<cdata 'char[]' buffer len 6 from 'array.array' object>" - p = new_pointer_type(new_primitive_type("unsigned short")) - cast(p, c)[1] += 500 - assert list(a) == [10000, 20500, 30000] - -def test_from_buffer_not_str_unicode(): - BChar = new_primitive_type("char") - BCharP = new_pointer_type(BChar) - BCharA = new_array_type(BCharP, None) - p1 = from_buffer(BCharA, b"foo") - assert p1 == from_buffer(BCharA, b"foo") - import gc; gc.collect() - assert p1 == from_buffer(BCharA, b"foo") - py.test.raises(TypeError, from_buffer, BCharA, u+"foo") - try: - from __builtin__ import buffer - except ImportError: - pass - else: - # Python 2 only - contents = from_buffer(BCharA, buffer(b"foo")) - assert len(contents) == len(p1) - for i in range(len(contents)): - assert contents[i] == p1[i] - p4 = buffer(u+"foo") - contents = from_buffer(BCharA, buffer(u+"foo")) - assert len(contents) == len(p4) - for i in range(len(contents)): - assert contents[i] == p4[i] - try: - from __builtin__ import memoryview - except ImportError: - pass - else: - contents = from_buffer(BCharA, memoryview(b"foo")) - assert len(contents) == len(p1) - for i in range(len(contents)): - assert contents[i] == p1[i] - - -def test_from_buffer_bytearray(): - a = bytearray(b"xyz") - BChar = new_primitive_type("char") - BCharP = new_pointer_type(BChar) - BCharA = new_array_type(BCharP, None) - p = from_buffer(BCharA, a) - assert typeof(p) is BCharA - assert len(p) == 3 - assert repr(p) == "<cdata 'char[]' buffer len 3 from 'bytearray' object>" - assert p[2] == b"z" - p[2] = b"." - assert a[2] == ord(".") - a[2] = ord("?") - assert p[2] == b"?" - -def test_from_buffer_more_cases(): - try: - from _cffi_backend import _testbuff - except ImportError: - py.test.skip("not for pypy") - BChar = new_primitive_type("char") - BCharP = new_pointer_type(BChar) - BCharA = new_array_type(BCharP, None) - # - def check1(bufobj, expected): - c = from_buffer(BCharA, bufobj) - assert typeof(c) is BCharA - if sys.version_info >= (3,): - expected = [bytes(c, "ascii") for c in expected] - assert list(c) == list(expected) - # - def check(methods, expected, expected_for_memoryview=None): - if sys.version_info >= (3,): - if methods <= 7: - return - if expected_for_memoryview is not None: - expected = expected_for_memoryview - class X(object): - pass - _testbuff(X, methods) - bufobj = X() - check1(bufobj, expected) - try: - from __builtin__ import buffer - bufobjb = buffer(bufobj) - except (TypeError, ImportError): - pass - else: - check1(bufobjb, expected) - try: - bufobjm = memoryview(bufobj) - except (TypeError, NameError): - pass - else: - check1(bufobjm, expected_for_memoryview or expected) - # - check(1, "RDB") - check(2, "WRB") - check(4, "CHB") - check(8, "GTB") - check(16, "ROB") - # - check(1 | 2, "RDB") - check(1 | 4, "RDB") - check(2 | 4, "CHB") - check(1 | 8, "RDB", "GTB") - check(1 | 16, "RDB", "ROB") - check(2 | 8, "WRB", "GTB") - check(2 | 16, "WRB", "ROB") - check(4 | 8, "CHB", "GTB") - check(4 | 16, "CHB", "ROB") - -def test_from_buffer_require_writable(): - BChar = new_primitive_type("char") - BCharP = new_pointer_type(BChar) - BCharA = new_array_type(BCharP, None) - p1 = from_buffer(BCharA, b"foo", False) - assert p1 == from_buffer(BCharA, b"foo", False) - py.test.raises((TypeError, BufferError), from_buffer, BCharA, b"foo", True) - ba = bytearray(b"foo") - p1 = from_buffer(BCharA, ba, True) - p1[0] = b"g" - assert ba == b"goo" - -def test_from_buffer_types(): - BInt = new_primitive_type("int") - BIntP = new_pointer_type(BInt) - BIntA = new_array_type(BIntP, None) - lst = [-12345678, 87654321, 489148] - 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 - assert len(p1) == 3 - assert p1[0] == lst[0] - assert p1[1] == lst[1] - assert p1[2] == lst[2] - with pytest.raises(IndexError): - p1[3] - with pytest.raises(IndexError): - p1[-1] - # - py.test.raises(TypeError, from_buffer, BInt, 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] - assert typeof(p2) is BIntA2 - assert len(p2) == 2 - assert p2[0] == lst[0] - assert p2[1] == lst[1] - 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) - # - BStruct = new_struct_type("foo") - complete_struct_or_union(BStruct, [('a1', BInt, -1), - ('a2', BInt, -1)]) - BStructP = new_pointer_type(BStruct) - BStructA = new_array_type(BStructP, None) - p1 = from_buffer(BStructA, bytestring2) # struct[] - assert len(p1) == 2 - assert typeof(p1) is BStructA - 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) - assert sizeof(BEmptyStruct) == 0 - BEmptyStructP = new_pointer_type(BEmptyStruct) - BEmptyStructA = new_array_type(BEmptyStructP, None) - py.test.raises(ZeroDivisionError, from_buffer, # empty[] - BEmptyStructA, bytestring) - # - BEmptyStructA5 = new_array_type(BEmptyStructP, 5) - 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) - 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") - ShortA = new_array_type(new_pointer_type(Short), None) - Char = new_primitive_type("char") - CharA = new_array_type(new_pointer_type(Char), None) - p = newp(ShortA, [-1234, -2345, -3456, -4567, -5678]) - memmove(p, p + 1, 4) - assert list(p) == [-2345, -3456, -3456, -4567, -5678] - p[2] = 999 - memmove(p + 2, p, 6) - assert list(p) == [-2345, -3456, -2345, -3456, 999] - memmove(p + 4, newp(CharA, b"\x71\x72"), 2) - if sys.byteorder == 'little': - assert list(p) == [-2345, -3456, -2345, -3456, 0x7271] - else: - assert list(p) == [-2345, -3456, -2345, -3456, 0x7172] - -def test_memmove_buffer(): - import array - Short = new_primitive_type("short") - ShortA = new_array_type(new_pointer_type(Short), None) - a = array.array('H', [10000, 20000, 30000]) - p = newp(ShortA, 5) - memmove(p, a, 6) - assert list(p) == [10000, 20000, 30000, 0, 0] - memmove(p + 1, a, 6) - assert list(p) == [10000, 10000, 20000, 30000, 0] - b = array.array('h', [-1000, -2000, -3000]) - memmove(b, a, 4) - assert b.tolist() == [10000, 20000, -3000] - assert a.tolist() == [10000, 20000, 30000] - p[0] = 999 - p[1] = 998 - p[2] = 997 - p[3] = 996 - p[4] = 995 - memmove(b, p, 2) - assert b.tolist() == [999, 20000, -3000] - memmove(b, p + 2, 4) - assert b.tolist() == [997, 996, -3000] - p[2] = -p[2] - p[3] = -p[3] - memmove(b, p + 2, 6) - assert b.tolist() == [-997, -996, 995] - -def test_memmove_readonly_readwrite(): - SignedChar = new_primitive_type("signed char") - SignedCharA = new_array_type(new_pointer_type(SignedChar), None) - p = newp(SignedCharA, 5) - memmove(p, b"abcde", 3) - assert list(p) == [ord("a"), ord("b"), ord("c"), 0, 0] - memmove(p, bytearray(b"ABCDE"), 2) - assert list(p) == [ord("A"), ord("B"), ord("c"), 0, 0] - py.test.raises((TypeError, BufferError), memmove, b"abcde", p, 3) - ba = bytearray(b"xxxxx") - memmove(dest=ba, src=p, n=3) - assert ba == bytearray(b"ABcxx") - memmove(ba, b"EFGH", 4) - assert ba == bytearray(b"EFGHx") - -def test_memmove_sign_check(): - SignedChar = new_primitive_type("signed char") - SignedCharA = new_array_type(new_pointer_type(SignedChar), None) - p = newp(SignedCharA, 5) - py.test.raises(ValueError, memmove, p, p + 1, -1) # not segfault - -def test_memmove_bad_cdata(): - BInt = new_primitive_type("int") - p = cast(BInt, 42) - py.test.raises(TypeError, memmove, p, bytearray(b'a'), 1) - py.test.raises(TypeError, memmove, bytearray(b'a'), p, 1) - -def test_dereference_null_ptr(): - BInt = new_primitive_type("int") - BIntPtr = new_pointer_type(BInt) - p = cast(BIntPtr, 0) - 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") - BStruct2 = new_struct_type("foo") # <= same name as BStruct1 - BStruct3 = new_struct_type("bar") - BStruct1Ptr = new_pointer_type(BStruct1) - BStruct2Ptr = new_pointer_type(BStruct2) - BStruct3Ptr = new_pointer_type(BStruct3) - BStruct1PtrPtr = new_pointer_type(BStruct1Ptr) - BStruct2PtrPtr = new_pointer_type(BStruct2Ptr) - BStruct3PtrPtr = new_pointer_type(BStruct3Ptr) - pp1 = newp(BStruct1PtrPtr) - pp2 = newp(BStruct2PtrPtr) - pp3 = newp(BStruct3PtrPtr) - pp1[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 *'") - 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 " - "instances)") - -def test_stdcall_function_type(): - assert FFI_CDECL == FFI_DEFAULT_ABI - try: - stdcall = FFI_STDCALL - except NameError: - stdcall = FFI_DEFAULT_ABI - BInt = new_primitive_type("int") - BFunc = new_function_type((BInt, BInt), BInt, False, stdcall) - if stdcall != FFI_DEFAULT_ABI: - assert repr(BFunc) == "<ctype 'int(__stdcall *)(int, int)'>" - else: - assert repr(BFunc) == "<ctype 'int(*)(int, int)'>" - -def test_get_common_types(): - d = {} - _get_common_types(d) - assert d['bool'] == '_Bool' - -def test_unpack(): - BChar = new_primitive_type("char") - BArray = new_array_type(new_pointer_type(BChar), 10) # char[10] - p = newp(BArray, b"abc\x00def") - p0 = p - assert unpack(p, 10) == b"abc\x00def\x00\x00\x00" - assert unpack(p+1, 5) == b"bc\x00de" - - for typename in ["wchar_t", "char16_t", "char32_t"]: - BWChar = new_primitive_type(typename) - BArray = new_array_type(new_pointer_type(BWChar), 10) # wchar_t[10] - p = newp(BArray, u"abc\x00def") - assert unpack(p, 10) == u"abc\x00def\x00\x00\x00" - - for typename, samples in [ - ("uint8_t", [0, 2**8-1]), - ("uint16_t", [0, 2**16-1]), - ("uint32_t", [0, 2**32-1]), - ("uint64_t", [0, 2**64-1]), - ("int8_t", [-2**7, 2**7-1]), - ("int16_t", [-2**15, 2**15-1]), - ("int32_t", [-2**31, 2**31-1]), - ("int64_t", [-2**63, 2**63-1]), - ("_Bool", [False, True]), - ("float", [0.0, 10.5]), - ("double", [12.34, 56.78]), - ]: - BItem = new_primitive_type(typename) - BArray = new_array_type(new_pointer_type(BItem), 10) - p = newp(BArray, samples) - result = unpack(p, len(samples)) - assert result == samples - for i in range(len(samples)): - assert result[i] == p[i] and type(result[i]) is type(p[i]) - assert (type(result[i]) is bool) == (type(samples[i]) is bool) - # - BInt = new_primitive_type("int") - py.test.raises(TypeError, unpack, p) - py.test.raises(TypeError, unpack, b"foobar", 6) - py.test.raises(TypeError, unpack, cast(BInt, 42), 1) - # - BPtr = new_pointer_type(BInt) - random_ptr = cast(BPtr, -424344) - other_ptr = cast(BPtr, 54321) - BArray = new_array_type(new_pointer_type(BPtr), None) - lst = unpack(newp(BArray, [random_ptr, other_ptr]), 2) - assert lst == [random_ptr, other_ptr] - # - BFunc = new_function_type((BInt, BInt), BInt, False) - BFuncPtr = new_pointer_type(BFunc) - lst = unpack(newp(new_array_type(BFuncPtr, None), 2), 2) - assert len(lst) == 2 - assert not lst[0] and not lst[1] - assert typeof(lst[0]) is BFunc - # - BStruct = new_struct_type("foo") - BStructPtr = new_pointer_type(BStruct) - e = py.test.raises(ValueError, unpack, cast(BStructPtr, 42), 5) - assert str(e.value) == "'foo *' points to items of unknown size" - complete_struct_or_union(BStruct, [('a1', BInt, -1), - ('a2', BInt, -1)]) - array_of_structs = newp(new_array_type(BStructPtr, None), [[4,5], [6,7]]) - lst = unpack(array_of_structs, 2) - assert typeof(lst[0]) is BStruct - assert lst[0].a1 == 4 and lst[1].a2 == 7 - # - py.test.raises(RuntimeError, unpack, cast(new_pointer_type(BChar), 0), 0) - py.test.raises(RuntimeError, unpack, cast(new_pointer_type(BChar), 0), 10) - # - py.test.raises(ValueError, unpack, p0, -1) - py.test.raises(ValueError, unpack, p, -1) - -def test_cdata_dir(): - BInt = new_primitive_type("int") - p = cast(BInt, 42) - check_dir(p, []) - p = newp(new_array_type(new_pointer_type(BInt), None), 5) - check_dir(p, []) - BStruct = new_struct_type("foo") - p = cast(new_pointer_type(BStruct), 0) - check_dir(p, []) # opaque - complete_struct_or_union(BStruct, [('a2', BInt, -1), - ('a1', BInt, -1)]) - check_dir(p, ['a1', 'a2']) # always sorted - p = newp(new_pointer_type(BStruct), None) - check_dir(p, ['a1', 'a2']) - check_dir(p[0], ['a1', 'a2']) - pp = newp(new_pointer_type(new_pointer_type(BStruct)), p) - check_dir(pp, []) - check_dir(pp[0], ['a1', 'a2']) - check_dir(pp[0][0], ['a1', 'a2']) - -def test_char_pointer_conversion(): - import warnings - assert __version__.startswith("1."), ( - "the warning will be an error if we ever release cffi 2.x") - BCharP = new_pointer_type(new_primitive_type("char")) - BIntP = new_pointer_type(new_primitive_type("int")) - BVoidP = new_pointer_type(new_void_type()) - BUCharP = new_pointer_type(new_primitive_type("unsigned char")) - z1 = cast(BCharP, 0) - z2 = cast(BIntP, 0) - z3 = cast(BVoidP, 0) - z4 = cast(BUCharP, 0) - with warnings.catch_warnings(record=True) as w: - warnings.simplefilter("always") - newp(new_pointer_type(BIntP), z1) # warn - assert len(w) == 1 - newp(new_pointer_type(BVoidP), z1) # fine - assert len(w) == 1 - newp(new_pointer_type(BCharP), z2) # warn - assert len(w) == 2 - newp(new_pointer_type(BVoidP), z2) # fine - assert len(w) == 2 - newp(new_pointer_type(BCharP), z3) # fine - assert len(w) == 2 - newp(new_pointer_type(BIntP), z3) # fine - assert len(w) == 2 - newp(new_pointer_type(BCharP), z4) # fine (ignore signedness here) - assert len(w) == 2 - newp(new_pointer_type(BUCharP), z1) # fine (ignore signedness here) - assert len(w) == 2 - newp(new_pointer_type(BUCharP), z3) # fine - assert len(w) == 2 - # check that the warnings are associated with lines in this file - assert w[1].lineno == w[0].lineno + 4 - -def test_primitive_comparison(): - def assert_eq(a, b): - assert (a == b) is True - assert (b == a) is True - assert (a != b) is False - assert (b != a) is False - assert (a < b) is False - assert (a <= b) is True - assert (a > b) is False - assert (a >= b) is True - assert (b < a) is False - assert (b <= a) is True - assert (b > a) is False - assert (b >= a) is True - assert hash(a) == hash(b) - def assert_lt(a, b, check_hash=True): - assert (a == b) is False - assert (b == a) is False - assert (a != b) is True - assert (b != a) is True - assert (a < b) is True - assert (a <= b) is True - assert (a > b) is False - assert (a >= b) is False - assert (b < a) is False - assert (b <= a) is False - assert (b > a) is True - assert (b >= a) is True - if check_hash: - assert hash(a) != hash(b) # (or at least, it is unlikely) - def assert_gt(a, b, check_hash=True): - assert_lt(b, a, check_hash) - def assert_ne(a, b): - assert (a == b) is False - assert (b == a) is False - assert (a != b) is True - assert (b != a) is True - if strict_compare: - 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: - assert_lt(b, a) - assert_eq(5, 5) - assert_lt(3, 5) - assert_ne('5', 5) - # - t1 = new_primitive_type("char") - t2 = new_primitive_type("int") - t3 = new_primitive_type("unsigned char") - t4 = new_primitive_type("unsigned int") - t5 = new_primitive_type("float") - t6 = new_primitive_type("double") - assert_eq(cast(t1, 65), b'A') - assert_lt(cast(t1, 64), b'\x99') - assert_gt(cast(t1, 200), b'A') - assert_ne(cast(t1, 65), 65) - assert_eq(cast(t2, -25), -25) - assert_lt(cast(t2, -25), -24) - assert_gt(cast(t2, -25), -26) - assert_eq(cast(t3, 65), 65) - assert_ne(cast(t3, 65), b'A') - assert_ne(cast(t3, 65), cast(t1, 65)) - assert_gt(cast(t4, -1), -1, check_hash=False) - assert_gt(cast(t4, -1), cast(t2, -1), check_hash=False) - assert_gt(cast(t4, -1), 99999) - assert_eq(cast(t4, -1), 256 ** size_of_int() - 1) - assert_eq(cast(t5, 3.0), 3) - assert_eq(cast(t5, 3.5), 3.5) - assert_lt(cast(t5, 3.3), 3.3) # imperfect rounding - assert_eq(cast(t6, 3.3), 3.3) - assert_eq(cast(t5, 3.5), cast(t6, 3.5)) - assert_lt(cast(t5, 3.1), cast(t6, 3.1)) # imperfect rounding - assert_eq(cast(t5, 7.0), cast(t3, 7)) - assert_lt(cast(t5, 3.1), 3.101) - assert_gt(cast(t5, 3.1), 3) - -def test_explicit_release_new(): - # release() on a ffi.new() object has no effect on CPython, but - # really releases memory on PyPy. We can't test that effect - # though, because a released cdata is not marked. - BIntP = new_pointer_type(new_primitive_type("int")) - p = newp(BIntP) - p[0] = 42 - with pytest.raises(IndexError): - p[1] - release(p) - # here, reading p[0] might give garbage or segfault... - release(p) # no effect - # - BStruct = new_struct_type("struct foo") - BStructP = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('p', BIntP, -1)]) - pstruct = newp(BStructP) - assert pstruct.p == cast(BIntP, 0) - release(pstruct) - # here, reading pstruct.p might give garbage or segfault... - release(pstruct) # no effect - -def test_explicit_release_new_contextmgr(): - BIntP = new_pointer_type(new_primitive_type("int")) - with newp(BIntP) as p: - p[0] = 42 - assert p[0] == 42 - # here, reading p[0] might give garbage or segfault... - release(p) # no effect - -def test_explicit_release_badtype(): - BIntP = new_pointer_type(new_primitive_type("int")) - p = cast(BIntP, 12345) - py.test.raises(ValueError, release, p) - py.test.raises(ValueError, release, p) - BStruct = new_struct_type("struct foo") - BStructP = new_pointer_type(BStruct) - complete_struct_or_union(BStruct, [('p', BIntP, -1)]) - pstruct = newp(BStructP) - py.test.raises(ValueError, release, pstruct[0]) - -def test_explicit_release_badtype_contextmgr(): - BIntP = new_pointer_type(new_primitive_type("int")) - p = cast(BIntP, 12345) - 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")) - seen = [] - intp1 = newp(BIntP, 12345) - p1 = cast(BIntP, intp1) - p = gcp(p1, seen.append) - assert seen == [] - release(p) - assert seen == [p1] - assert p1[0] == 12345 - assert p[0] == 12345 # true so far, but might change to raise RuntimeError - release(p) # no effect - -def test_explicit_release_gc_contextmgr(): - BIntP = new_pointer_type(new_primitive_type("int")) - seen = [] - intp1 = newp(BIntP, 12345) - p1 = cast(BIntP, intp1) - p = gcp(p1, seen.append) - with p: - assert p[0] == 12345 - assert seen == [] - assert seen == [p1] - assert p1[0] == 12345 - assert p[0] == 12345 # true so far, but might change to raise RuntimeError - release(p) # no effect - -def test_explicit_release_from_buffer(): - a = bytearray(b"xyz") - BChar = new_primitive_type("char") - BCharP = new_pointer_type(BChar) - 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(): - a = bytearray(b"xyz") - BChar = new_primitive_type("char") - BCharP = new_pointer_type(BChar) - BCharA = new_array_type(BCharP, None) - p = from_buffer(BCharA, a) - 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(): - if '__pypy__' in sys.builtin_module_names: - py.test.skip("pypy's bytearray are never locked") - a = bytearray(b"xyz") - BChar = new_primitive_type("char") - BCharP = new_pointer_type(BChar) - BCharA = new_array_type(BCharP, None) - a += b't' * 10 - p = from_buffer(BCharA, a) - 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' diff --git a/c/wchar_helper.h b/c/wchar_helper.h deleted file mode 100644 index 8e6ea58..0000000 --- a/c/wchar_helper.h +++ /dev/null @@ -1,246 +0,0 @@ -/* - * wchar_t helpers - */ - -typedef uint16_t cffi_char16_t; -typedef uint32_t cffi_char32_t; - - -#if Py_UNICODE_SIZE == 2 - -/* Before Python 2.7, PyUnicode_FromWideChar is not able to convert - wchar_t values greater than 65535 into two-unicode-characters surrogates. - But even the Python 2.7 version doesn't detect wchar_t values that are - out of range(1114112), and just returns nonsense. - - From cffi 1.11 we can't use it anyway, because we need a version - with char32_t input types. -*/ -static PyObject * -_my_PyUnicode_FromChar32(const cffi_char32_t *w, Py_ssize_t size) -{ - PyObject *unicode; - register Py_ssize_t i; - Py_ssize_t alloc; - const cffi_char32_t *orig_w; - - alloc = size; - orig_w = w; - for (i = size; i > 0; i--) { - if (*w > 0xFFFF) - alloc++; - w++; - } - w = orig_w; - unicode = PyUnicode_FromUnicode(NULL, alloc); - if (!unicode) - return NULL; - - /* Copy the wchar_t data into the new object */ - { - register Py_UNICODE *u; - u = PyUnicode_AS_UNICODE(unicode); - for (i = size; i > 0; i--) { - if (*w > 0xFFFF) { - cffi_char32_t ordinal; - if (*w > 0x10FFFF) { - PyErr_Format(PyExc_ValueError, - "char32_t out of range for " - "conversion to unicode: 0x%x", (int)*w); - Py_DECREF(unicode); - return NULL; - } - ordinal = *w++; - ordinal -= 0x10000; - *u++ = 0xD800 | (ordinal >> 10); - *u++ = 0xDC00 | (ordinal & 0x3FF); - } - else - *u++ = *w++; - } - } - return unicode; -} - -static PyObject * -_my_PyUnicode_FromChar16(const cffi_char16_t *w, Py_ssize_t size) -{ - return PyUnicode_FromUnicode((const Py_UNICODE *)w, size); -} - -#else /* Py_UNICODE_SIZE == 4 */ - -static PyObject * -_my_PyUnicode_FromChar32(const cffi_char32_t *w, Py_ssize_t size) -{ - return PyUnicode_FromUnicode((const Py_UNICODE *)w, size); -} - -static PyObject * -_my_PyUnicode_FromChar16(const cffi_char16_t *w, Py_ssize_t size) -{ - /* 'size' is the length of the 'w' array */ - PyObject *result = PyUnicode_FromUnicode(NULL, size); - - if (result != NULL) { - Py_UNICODE *u_base = PyUnicode_AS_UNICODE(result); - Py_UNICODE *u = u_base; - - if (size == 1) { /* performance only */ - *u = (cffi_char32_t)*w; - } - else { - while (size > 0) { - cffi_char32_t ch = *w++; - size--; - if (0xD800 <= ch && ch <= 0xDBFF && size > 0) { - cffi_char32_t ch2 = *w; - if (0xDC00 <= ch2 && ch2 <= 0xDFFF) { - ch = (((ch & 0x3FF)<<10) | (ch2 & 0x3FF)) + 0x10000; - w++; - size--; - } - } - *u++ = ch; - } - if (PyUnicode_Resize(&result, u - u_base) < 0) { - Py_DECREF(result); - return NULL; - } - } - } - return result; -} - -#endif - - -#define IS_SURROGATE(u) (0xD800 <= (u)[0] && (u)[0] <= 0xDBFF && \ - 0xDC00 <= (u)[1] && (u)[1] <= 0xDFFF) -#define AS_SURROGATE(u) (0x10000 + (((u)[0] - 0xD800) << 10) + \ - ((u)[1] - 0xDC00)) - -static int -_my_PyUnicode_AsSingleChar16(PyObject *unicode, cffi_char16_t *result, - char *err_got) -{ - Py_UNICODE *u = PyUnicode_AS_UNICODE(unicode); - if (PyUnicode_GET_SIZE(unicode) != 1) { - sprintf(err_got, "unicode string of length %zd", - PyUnicode_GET_SIZE(unicode)); - return -1; - } -#if Py_UNICODE_SIZE == 4 - if (((unsigned int)u[0]) > 0xFFFF) - { - sprintf(err_got, "larger-than-0xFFFF character"); - return -1; - } -#endif - *result = (cffi_char16_t)u[0]; - return 0; -} - -static int -_my_PyUnicode_AsSingleChar32(PyObject *unicode, cffi_char32_t *result, - char *err_got) -{ - Py_UNICODE *u = PyUnicode_AS_UNICODE(unicode); - if (PyUnicode_GET_SIZE(unicode) == 1) { - *result = (cffi_char32_t)u[0]; - return 0; - } -#if Py_UNICODE_SIZE == 2 - if (PyUnicode_GET_SIZE(unicode) == 2 && IS_SURROGATE(u)) { - *result = AS_SURROGATE(u); - return 0; - } -#endif - sprintf(err_got, "unicode string of length %zd", - PyUnicode_GET_SIZE(unicode)); - return -1; -} - -static Py_ssize_t _my_PyUnicode_SizeAsChar16(PyObject *unicode) -{ - Py_ssize_t length = PyUnicode_GET_SIZE(unicode); - Py_ssize_t result = length; - -#if Py_UNICODE_SIZE == 4 - Py_UNICODE *u = PyUnicode_AS_UNICODE(unicode); - Py_ssize_t i; - - for (i=0; i<length; i++) { - if (u[i] > 0xFFFF) - result++; - } -#endif - return result; -} - -static Py_ssize_t _my_PyUnicode_SizeAsChar32(PyObject *unicode) -{ - Py_ssize_t length = PyUnicode_GET_SIZE(unicode); - Py_ssize_t result = length; - -#if Py_UNICODE_SIZE == 2 - Py_UNICODE *u = PyUnicode_AS_UNICODE(unicode); - Py_ssize_t i; - - for (i=0; i<length-1; i++) { - if (IS_SURROGATE(u+i)) - result--; - } -#endif - return result; -} - -static int _my_PyUnicode_AsChar16(PyObject *unicode, - cffi_char16_t *result, - Py_ssize_t resultlen) -{ - Py_ssize_t len = PyUnicode_GET_SIZE(unicode); - Py_UNICODE *u = PyUnicode_AS_UNICODE(unicode); - Py_ssize_t i; - for (i=0; i<len; i++) { -#if Py_UNICODE_SIZE == 2 - cffi_char16_t ordinal = u[i]; -#else - cffi_char32_t ordinal = u[i]; - if (ordinal > 0xFFFF) { - if (ordinal > 0x10FFFF) { - PyErr_Format(PyExc_ValueError, - "unicode character out of range for " - "conversion to char16_t: 0x%x", (int)ordinal); - return -1; - } - ordinal -= 0x10000; - *result++ = 0xD800 | (ordinal >> 10); - *result++ = 0xDC00 | (ordinal & 0x3FF); - continue; - } -#endif - *result++ = ordinal; - } - return 0; -} - -static int _my_PyUnicode_AsChar32(PyObject *unicode, - cffi_char32_t *result, - Py_ssize_t resultlen) -{ - Py_UNICODE *u = PyUnicode_AS_UNICODE(unicode); - Py_ssize_t i; - for (i=0; i<resultlen; i++) { - cffi_char32_t ordinal = *u; -#if Py_UNICODE_SIZE == 2 - if (IS_SURROGATE(u)) { - ordinal = AS_SURROGATE(u); - u++; - } -#endif - result[i] = ordinal; - u++; - } - return 0; -} diff --git a/c/wchar_helper_3.h b/c/wchar_helper_3.h deleted file mode 100644 index f15464e..0000000 --- a/c/wchar_helper_3.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - * wchar_t helpers, version CPython >= 3.3. - * - * CPython 3.3 added support for sys.maxunicode == 0x10FFFF on all - * platforms, even ones with wchar_t limited to 2 bytes. As such, - * this code here works from the outside like wchar_helper.h in the - * case Py_UNICODE_SIZE == 4, but the implementation is very different. - */ - -typedef uint16_t cffi_char16_t; -typedef uint32_t cffi_char32_t; - - -static PyObject * -_my_PyUnicode_FromChar32(const cffi_char32_t *w, Py_ssize_t size) -{ - return PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, w, size); -} - -static PyObject * -_my_PyUnicode_FromChar16(const cffi_char16_t *w, Py_ssize_t size) -{ - /* are there any surrogate pairs, and if so, how many? */ - Py_ssize_t i, count_surrogates = 0; - for (i = 0; i < size - 1; i++) { - if (0xD800 <= w[i] && w[i] <= 0xDBFF && - 0xDC00 <= w[i+1] && w[i+1] <= 0xDFFF) - count_surrogates++; - } - if (count_surrogates == 0) { - /* no, fast path */ - return PyUnicode_FromKindAndData(PyUnicode_2BYTE_KIND, w, size); - } - else - { - PyObject *result = PyUnicode_New(size - count_surrogates, 0x10FFFF); - Py_UCS4 *data; - assert(PyUnicode_KIND(result) == PyUnicode_4BYTE_KIND); - data = PyUnicode_4BYTE_DATA(result); - - for (i = 0; i < size; i++) - { - cffi_char32_t ch = w[i]; - if (0xD800 <= ch && ch <= 0xDBFF && i < size - 1) { - cffi_char32_t ch2 = w[i + 1]; - if (0xDC00 <= ch2 && ch2 <= 0xDFFF) { - ch = (((ch & 0x3FF)<<10) | (ch2 & 0x3FF)) + 0x10000; - i++; - } - } - *data++ = ch; - } - return result; - } -} - -static int -_my_PyUnicode_AsSingleChar16(PyObject *unicode, cffi_char16_t *result, - char *err_got) -{ - cffi_char32_t ch; - if (PyUnicode_GET_LENGTH(unicode) != 1) { - sprintf(err_got, "unicode string of length %zd", - PyUnicode_GET_LENGTH(unicode)); - return -1; - } - ch = PyUnicode_READ_CHAR(unicode, 0); - - if (ch > 0xFFFF) - { - sprintf(err_got, "larger-than-0xFFFF character"); - return -1; - } - *result = (cffi_char16_t)ch; - return 0; -} - -static int -_my_PyUnicode_AsSingleChar32(PyObject *unicode, cffi_char32_t *result, - char *err_got) -{ - if (PyUnicode_GET_LENGTH(unicode) != 1) { - sprintf(err_got, "unicode string of length %zd", - PyUnicode_GET_LENGTH(unicode)); - return -1; - } - *result = PyUnicode_READ_CHAR(unicode, 0); - return 0; -} - -static Py_ssize_t _my_PyUnicode_SizeAsChar16(PyObject *unicode) -{ - Py_ssize_t length = PyUnicode_GET_LENGTH(unicode); - Py_ssize_t result = length; - unsigned int kind = PyUnicode_KIND(unicode); - - if (kind == PyUnicode_4BYTE_KIND) - { - Py_UCS4 *data = PyUnicode_4BYTE_DATA(unicode); - Py_ssize_t i; - for (i = 0; i < length; i++) { - if (data[i] > 0xFFFF) - result++; - } - } - return result; -} - -static Py_ssize_t _my_PyUnicode_SizeAsChar32(PyObject *unicode) -{ - return PyUnicode_GET_LENGTH(unicode); -} - -static int _my_PyUnicode_AsChar16(PyObject *unicode, - cffi_char16_t *result, - Py_ssize_t resultlen) -{ - Py_ssize_t len = PyUnicode_GET_LENGTH(unicode); - unsigned int kind = PyUnicode_KIND(unicode); - void *data = PyUnicode_DATA(unicode); - Py_ssize_t i; - - for (i = 0; i < len; i++) { - cffi_char32_t ordinal = PyUnicode_READ(kind, data, i); - if (ordinal > 0xFFFF) { - if (ordinal > 0x10FFFF) { - PyErr_Format(PyExc_ValueError, - "unicode character out of range for " - "conversion to char16_t: 0x%x", (int)ordinal); - return -1; - } - ordinal -= 0x10000; - *result++ = 0xD800 | (ordinal >> 10); - *result++ = 0xDC00 | (ordinal & 0x3FF); - } - else - *result++ = ordinal; - } - return 0; -} - -static int _my_PyUnicode_AsChar32(PyObject *unicode, - cffi_char32_t *result, - Py_ssize_t resultlen) -{ - if (PyUnicode_AsUCS4(unicode, (Py_UCS4 *)result, resultlen, 0) == NULL) - return -1; - return 0; -} |