Author: Michal Vyskocil <[email protected]>
Branch:
Changeset: r3196:48ca9a578dac
Date: 2019-01-08 10:29 +0100
http://bitbucket.org/cffi/cffi/changeset/48ca9a578dac/
Log: merge with latest tip
diff too long, truncating to 2000 out of 8938 lines
diff --git a/.hgtags b/.hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -12,3 +12,8 @@
0000000000000000000000000000000000000000 release-0.2
ca6e81df7f1ea58d891129ad016a8888c08f238b release-0.1
0000000000000000000000000000000000000000 release-0.1
+ada126bd7d1e96cc76303c1fca64a556912549d8 v1.11.1
+5f9690f5832b0292056df45f72314d69c191f75a v1.11.2
+1aafccb9255dbb36f8e785b65624e39628cee63a v1.11.3
+e08abd4703fef26f036e82255f4070277a9e03bd v1.11.4
+48416163071ed48300c3ae4358cc7fd841912413 v1.11.5
diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -2,7 +2,7 @@
#include <Python.h>
#include "structmember.h"
-#define CFFI_VERSION "1.10.0"
+#define CFFI_VERSION "1.12.0"
#ifdef MS_WIN32
#include <windows.h>
@@ -60,7 +60,38 @@
# endif
#endif
-#include "malloc_closure.h"
+
+/* 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() only on NetBSD. It is
+ * known that on the NetBSD kernel, a different strategy is used which
+ * should not be open to the fork() bug.
+ */
+#ifdef __NetBSD__
+# define CFFI_TRUST_LIBFFI
+#endif
+
+#ifndef CFFI_TRUST_LIBFFI
+# include "malloc_closure.h"
+#endif
+
#if PY_MAJOR_VERSION >= 3
# define STR_OR_BYTES "bytes"
@@ -70,7 +101,11 @@
# define PyText_FromFormat PyUnicode_FromFormat
# define PyText_AsUTF8 _PyUnicode_AsString /* PyUnicode_AsUTF8 in Py3.3 */
# define PyText_AS_UTF8 _PyUnicode_AsString
-# define PyText_GetSize PyUnicode_GetSize
+# 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
@@ -116,36 +151,39 @@
/************************************************************/
/* base type flag: exactly one of the following: */
-#define CT_PRIMITIVE_SIGNED 1 /* signed integer */
-#define CT_PRIMITIVE_UNSIGNED 2 /* unsigned integer */
-#define CT_PRIMITIVE_CHAR 4 /* char, wchar_t */
-#define CT_PRIMITIVE_FLOAT 8 /* float, double, long double */
-#define CT_POINTER 16 /* pointer, excluding ptr-to-func */
-#define CT_ARRAY 32 /* array */
-#define CT_STRUCT 64 /* struct */
-#define CT_UNION 128 /* union */
-#define CT_FUNCTIONPTR 256 /* pointer to function */
-#define CT_VOID 512 /* void */
+#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 1024
-#define CT_PRIMITIVE_FITS_LONG 2048
-#define CT_IS_OPAQUE 4096
-#define CT_IS_ENUM 8192
-#define CT_IS_PTR_TO_OWNED 16384 /* only owned if CDataOwning_Type */
-#define CT_CUSTOM_FIELD_POS 32768
-#define CT_IS_LONGDOUBLE 65536
-#define CT_IS_BOOL 131072
-#define CT_IS_FILE 262144
-#define CT_IS_VOID_PTR 524288
-#define CT_WITH_VAR_ARRAY 1048576
-#define CT_IS_UNSIZED_CHAR_A 2097152
-#define CT_LAZY_FIELD_LIST 4194304
-#define CT_WITH_PACKED_CHANGE 8388608
+#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
+/* 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_FLOAT | \
+ CT_PRIMITIVE_COMPLEX)
typedef struct _ctypedescr {
PyObject_VAR_HEAD
@@ -256,6 +294,11 @@
} 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
@@ -283,10 +326,14 @@
# include "file_emulator.h"
#endif
-#ifdef HAVE_WCHAR_H
+#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;
@@ -845,11 +892,21 @@
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; \
- memcpy(target, &r, sizeof(type)); \
+ _cffi_memcpy(target, &r, sizeof(type)); \
return; \
} \
} while(0)
@@ -883,6 +940,26 @@
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)
{
@@ -898,6 +975,25 @@
_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)
{
@@ -1008,12 +1104,18 @@
}
else if (ct->ct_flags & CT_PRIMITIVE_CHAR) {
/*READ(data, ct->ct_size)*/
- if (ct->ct_size == sizeof(char))
+ switch (ct->ct_size) {
+ case sizeof(char):
return PyBytes_FromStringAndSize(data, 1);
-#ifdef HAVE_WCHAR_H
- else
- return _my_PyUnicode_FromWideChar((wchar_t *)data, 1);
-#endif
+ 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,
@@ -1088,39 +1190,65 @@
return -1;
}
-#ifdef HAVE_WCHAR_H
-static wchar_t _convert_to_wchar_t(PyObject *init)
-{
+static cffi_char16_t _convert_to_char16_t(PyObject *init)
+{
+ char err_got[80];
+ err_got[0] = 0;
+
if (PyUnicode_Check(init)) {
- wchar_t ordinal;
- if (_my_PyUnicode_AsSingleWideChar(init, &ordinal) == 0)
+ 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 == sizeof(wchar_t))) {
+ (((CDataObject *)init)->c_type->ct_size == 2)) {
char *data = ((CDataObject *)init)->c_data;
- /*READ(data, sizeof(wchar_t))*/
- return *(wchar_t *)data;
+ /*READ(data, 2)*/
+ return *(cffi_char16_t *)data;
}
PyErr_Format(PyExc_TypeError,
- "initializer for ctype 'wchar_t' must be a unicode string "
- "of length 1, not %.200s", Py_TYPE(init)->tp_name);
- return (wchar_t)-1;
-}
-#endif
-
-static int _convert_error(PyObject *init, const char *ct_name,
+ "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)) {
- const char *ct_name_2 = ((CDataObject *)init)->c_type->ct_name;
- if (strcmp(ct_name, ct_name_2) != 0)
+ 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_name, expected, ct_name_2);
- else {
+ 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
@@ -1129,14 +1257,21 @@
"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_name, ct_name_2);
+ 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_name, expected, Py_TYPE(init)->tp_name);
+ ct->ct_name, expected, Py_TYPE(init)->tp_name);
return -1;
}
@@ -1146,7 +1281,7 @@
convert_from_object_bitfield(char *data, CFieldObject *cf, PyObject *init);
static Py_ssize_t
-get_new_array_length(PyObject **pvalue)
+get_new_array_length(CTypeDescrObject *ctitem, PyObject **pvalue)
{
PyObject *value = *pvalue;
@@ -1159,13 +1294,24 @@
}
else if (PyUnicode_Check(value)) {
/* from a unicode, we add the null terminator */
- return _my_PyUnicode_SizeAsWideChar(value) + 1;
+ 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_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;
}
@@ -1190,7 +1336,8 @@
{
/* 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(&value);
+ Py_ssize_t varsizelength = get_new_array_length(
+ cf->cf_type->ct_itemdescr, &value);
if (varsizelength < 0)
return -1;
if (optvarsize != NULL) {
@@ -1238,6 +1385,15 @@
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)
{
@@ -1291,14 +1447,18 @@
memcpy(data, srcdata, n);
return 0;
}
-#ifdef HAVE_WCHAR_H
else {
Py_ssize_t n;
if (!PyUnicode_Check(init)) {
expected = "unicode or list or tuple";
goto cannot_convert;
}
- n = _my_PyUnicode_SizeAsWideChar(init);
+
+ 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' "
@@ -1307,10 +1467,11 @@
}
if (n != ct->ct_length)
n++;
- _my_PyUnicode_AsWideChar(init, (wchar_t *)data, n);
- return 0;
- }
-#endif
+ 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";
@@ -1318,13 +1479,24 @@
}
cannot_convert:
- return _convert_error(init, ct->ct_name, expected);
+ 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) {
@@ -1371,7 +1543,7 @@
}
expected = optvarsize == NULL ? "list or tuple or dict or struct-cdata"
: "list or tuple or dict";
- return _convert_error(init, ct->ct_name, expected);
+ return _convert_error(init, ct, expected);
}
#ifdef __GNUC__
@@ -1421,7 +1593,8 @@
/* 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. */
+ 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 "
@@ -1431,7 +1604,12 @@
"will be forbidden in the future (check that the types "
"are as you expect; use an explicit ffi.cast() if they "
"are correct)");
- if (PyErr_WarnEx(PyExc_UserWarning, msg, 1))
+ 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 {
@@ -1492,22 +1670,29 @@
return 0;
}
if (ct->ct_flags & CT_PRIMITIVE_CHAR) {
- if (ct->ct_size == sizeof(char)) {
+ switch (ct->ct_size) {
+ case sizeof(char): {
int res = _convert_to_char(init);
if (res < 0)
return -1;
data[0] = res;
return 0;
}
-#ifdef HAVE_WCHAR_H
- else {
- wchar_t res = _convert_to_wchar_t(init);
- if (res == (wchar_t)-1 && PyErr_Occurred())
+ case 2: {
+ cffi_char16_t res = _convert_to_char16_t(init);
+ if (res == (cffi_char16_t)-1 && PyErr_Occurred())
return -1;
- *(wchar_t *)data = res;
+ *(cffi_char16_t *)data = res;
return 0;
}
-#endif
+ 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)) {
@@ -1519,6 +1704,13 @@
}
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;
@@ -1527,7 +1719,7 @@
return _convert_overflow(init, ct->ct_name);
cannot_convert:
- return _convert_error(init, ct->ct_name, expected);
+ return _convert_error(init, ct, expected);
}
static int
@@ -1587,15 +1779,6 @@
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
get_alignment(CTypeDescrObject *ct)
{
@@ -1678,12 +1861,16 @@
Py_DECREF(x);
}
else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) { /* a callback */
- ffi_closure *closure = (ffi_closure *)cd->c_data;
+ ffi_closure *closure = ((CDataObject_closure *)cd)->closure;
PyObject *args = (PyObject *)(closure->user_data);
Py_XDECREF(args);
+#ifdef CFFI_TRUST_LIBFFI
+ ffi_closure_free(closure);
+#else
cffi_closure_free(closure);
- }
- else if (cd->c_type->ct_flags & CT_IS_UNSIZED_CHAR_A) { /* from_buffer */
+#endif
+ }
+ else if (cd->c_type->ct_flags & CT_ARRAY) { /* from_buffer */
Py_buffer *view = ((CDataObject_owngc_frombuf *)cd)->bufferview;
PyBuffer_Release(view);
PyObject_Free(view);
@@ -1698,11 +1885,11 @@
Py_VISIT(x);
}
else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) { /* a callback */
- ffi_closure *closure = (ffi_closure *)cd->c_data;
+ ffi_closure *closure = ((CDataObject_closure *)cd)->closure;
PyObject *args = (PyObject *)(closure->user_data);
Py_VISIT(args);
}
- else if (cd->c_type->ct_flags & CT_IS_UNSIZED_CHAR_A) { /* from_buffer */
+ else if (cd->c_type->ct_flags & CT_ARRAY) { /* from_buffer */
Py_buffer *view = ((CDataObject_owngc_frombuf *)cd)->bufferview;
Py_VISIT(view->obj);
}
@@ -1719,12 +1906,12 @@
Py_DECREF(x);
}
else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) { /* a callback */
- ffi_closure *closure = (ffi_closure *)cd->c_data;
+ ffi_closure *closure = ((CDataObject_closure *)cd)->closure;
PyObject *args = (PyObject *)(closure->user_data);
closure->user_data = NULL;
Py_XDECREF(args);
}
- else if (cd->c_type->ct_flags & CT_IS_UNSIZED_CHAR_A) { /* from_buffer */
+ else if (cd->c_type->ct_flags & CT_ARRAY) { /* from_buffer */
Py_buffer *view = ((CDataObject_owngc_frombuf *)cd)->bufferview;
PyBuffer_Release(view);
}
@@ -1732,7 +1919,8 @@
}
/* forward */
-static void _my_PyErr_WriteUnraisable(char *objdescr, PyObject *obj,
+static void _my_PyErr_WriteUnraisable(PyObject *t, PyObject *v, PyObject *tb,
+ char *objdescr, PyObject *obj,
char *extra_error_line);
@@ -1752,8 +1940,15 @@
Py_DECREF(result);
}
else {
- _my_PyErr_WriteUnraisable("From callback for ffi.gc ",
+ 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);
@@ -1763,7 +1958,6 @@
Py_XDECREF(origobj);
}
-#ifdef Py_TPFLAGS_HAVE_FINALIZE /* CPython >= 3.4 */
static void cdatagcp_finalize(CDataObject_gcp *cd)
{
PyObject *destructor = cd->destructor;
@@ -1772,7 +1966,6 @@
cd->origobj = NULL;
gcp_finalize(destructor, origobj);
}
-#endif
static void cdatagcp_dealloc(CDataObject_gcp *cd)
{
@@ -1925,13 +2118,14 @@
return _cdata_repr2(cd, "handle to", x);
}
else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) { /* a callback */
- PyObject *args = (PyObject *)((ffi_closure *)cd->c_data)->user_data;
+ 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));
}
- else if (cd->c_type->ct_flags & CT_IS_UNSIZED_CHAR_A) { /* from_buffer */
+ else if (cd->c_type->ct_flags & CT_ARRAY) { /* from_buffer */
Py_buffer *view = ((CDataObject_owngc_frombuf *)cd)->bufferview;
Py_ssize_t buflen = get_array_length(cd);
return PyText_FromFormat(
@@ -1956,6 +2150,11 @@
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;
}
@@ -1976,12 +2175,19 @@
}
else if (cd->c_type->ct_flags & CT_PRIMITIVE_CHAR) {
/*READ(cd->c_data, cd->c_type->ct_size)*/
- if (cd->c_type->ct_size == sizeof(char))
+ switch (cd->c_type->ct_size) {
+ case sizeof(char):
return PyInt_FromLong((unsigned char)cd->c_data[0]);
-#ifdef HAVE_WCHAR_H
- else
- return PyInt_FromLong((long)*(wchar_t *)cd->c_data);
-#endif
+ 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);
@@ -2163,7 +2369,7 @@
else if (cd->c_type->ct_flags & CT_ARRAY) {
if (i < 0) {
PyErr_SetString(PyExc_IndexError,
- "negative index not supported");
+ "negative index");
return NULL;
}
if (i >= get_array_length(cd)) {
@@ -2216,7 +2422,7 @@
if (ct->ct_flags & CT_ARRAY) {
if (start < 0) {
PyErr_SetString(PyExc_IndexError,
- "negative index not supported");
+ "negative index");
return NULL;
}
if (stop > get_array_length(cd)) {
@@ -2507,7 +2713,7 @@
static void
_cdata_attr_errmsg(char *errmsg, CDataObject *cd, PyObject *attr)
{
- char *text;
+ const char *text;
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
return;
PyErr_Clear();
@@ -2673,7 +2879,11 @@
}
else if (PyUnicode_Check(init)) {
/* from a unicode, we add the null terminator */
- length = _my_PyUnicode_SizeAsWideChar(init) + 1;
+ 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);
@@ -2904,6 +3114,93 @@
}
}
+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) == &CDataOwningGC_Type) {
+ if (ct->ct_flags & CT_ARRAY) /* ffi.from_buffer() */
+ return 1;
+ }
+ 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_owngc_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 = {
@@ -2953,8 +3250,11 @@
};
static PyMethodDef cdata_methods[] = {
- {"__dir__", cdata_dir, METH_NOARGS},
- {NULL, NULL} /* sentinel */
+ {"__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 = {
@@ -3010,24 +3310,24 @@
0, /* tp_setattr */
0, /* tp_compare */
(reprfunc)cdataowning_repr, /* tp_repr */
- 0, /* tp_as_number */
+ 0, /* inherited */ /* tp_as_number */
0, /* tp_as_sequence */
&CDataOwn_as_mapping, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
+ 0, /* inherited */ /* tp_hash */
+ 0, /* inherited */ /* tp_call */
0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
+ 0, /* inherited */ /* tp_getattro */
+ 0, /* inherited */ /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
0, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
+ 0, /* inherited */ /* tp_richcompare */
+ 0, /* inherited */ /* tp_weaklistoffset */
+ 0, /* inherited */ /* tp_iter */
0, /* tp_iternext */
- 0, /* tp_methods */
+ 0, /* inherited */ /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
&CData_Type, /* tp_base */
@@ -3052,25 +3352,25 @@
0, /* tp_setattr */
0, /* tp_compare */
(reprfunc)cdataowninggc_repr, /* tp_repr */
- 0, /* tp_as_number */
+ 0, /* inherited */ /* tp_as_number */
0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
+ 0, /* inherited */ /* tp_as_mapping */
+ 0, /* inherited */ /* tp_hash */
+ 0, /* inherited */ /* tp_call */
0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
+ 0, /* inherited */ /* tp_getattro */
+ 0, /* inherited */ /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES /* tp_flags */
| Py_TPFLAGS_HAVE_GC,
0, /* tp_doc */
(traverseproc)cdataowninggc_traverse, /* tp_traverse */
(inquiry)cdataowninggc_clear, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
+ 0, /* inherited */ /* tp_richcompare */
+ 0, /* inherited */ /* tp_weaklistoffset */
+ 0, /* inherited */ /* tp_iter */
0, /* tp_iternext */
- 0, /* tp_methods */
+ 0, /* inherited */ /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
&CDataOwning_Type, /* tp_base */
@@ -3094,15 +3394,15 @@
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
- 0, /* tp_repr */
- 0, /* tp_as_number */
+ 0, /* inherited */ /* tp_repr */
+ 0, /* inherited */ /* tp_as_number */
0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
+ 0, /* inherited */ /* tp_as_mapping */
+ 0, /* inherited */ /* tp_hash */
+ 0, /* inherited */ /* tp_call */
0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
+ 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
@@ -3112,11 +3412,11 @@
0, /* tp_doc */
(traverseproc)cdatagcp_traverse, /* tp_traverse */
0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
+ 0, /* inherited */ /* tp_richcompare */
+ 0, /* inherited */ /* tp_weaklistoffset */
+ 0, /* inherited */ /* tp_iter */
0, /* tp_iternext */
- 0, /* tp_methods */
+ 0, /* inherited */ /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
&CData_Type, /* tp_base */
@@ -3128,7 +3428,7 @@
0, /* tp_init */
0, /* tp_alloc */
0, /* tp_new */
- 0, /* tp_free */
+ 0, /* inherited */ /* tp_free */
0, /* tp_is_gc */
0, /* tp_bases */
0, /* tp_mro */
@@ -3228,6 +3528,8 @@
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);
@@ -3258,6 +3560,7 @@
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)
@@ -3380,7 +3683,7 @@
dataoffset = offsetof(CDataObject_own_nolength, alignment);
datasize = ct->ct_size;
if (datasize < 0) {
- explicitlength = get_new_array_length(&init);
+ explicitlength = get_new_array_length(ct->ct_itemdescr, &init);
if (explicitlength < 0)
return NULL;
ctitem = ct->ct_itemdescr;
@@ -3550,18 +3853,24 @@
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
- else if (PyUnicode_Check(ob)) {
- wchar_t ordinal;
- if (_my_PyUnicode_AsSingleWideChar(ob, &ordinal) < 0) {
- PyErr_Format(PyExc_TypeError,
- "cannot cast unicode string of length %zd to ctype '%s'",
- PyUnicode_GET_SIZE(ob), ct->ct_name);
- return NULL;
- }
- value = (long)ordinal;
- }
+ 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)
@@ -3587,6 +3896,35 @@
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;
@@ -3628,6 +3966,7 @@
/* cast to a float */
double value;
PyObject *io;
+ int res;
if (CData_Check(ob)) {
CDataObject *cdsrc = (CDataObject *)ob;
@@ -3643,37 +3982,23 @@
Py_INCREF(io);
}
- if (PyBytes_Check(io)) {
- if (PyBytes_GET_SIZE(io) != 1) {
- Py_DECREF(io);
- goto cannot_cast;
- }
- value = (unsigned char)PyBytes_AS_STRING(io)[0];
- }
-#if HAVE_WCHAR_H
- else if (PyUnicode_Check(io)) {
- wchar_t ordinal;
- if (_my_PyUnicode_AsSingleWideChar(io, &ordinal) < 0) {
- Py_DECREF(io);
- goto cannot_cast;
- }
- value = (long)ordinal;
- }
-#endif
- else if ((ct->ct_flags & CT_IS_LONGDOUBLE) &&
+ 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;
- }
- else {
+ 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);
@@ -3689,6 +4014,45 @@
}
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);
@@ -3726,7 +4090,8 @@
static void dl_dealloc(DynLibObject *dlobj)
{
- dlclose(dlobj->dl_handle);
+ if (dlobj->dl_handle != NULL)
+ dlclose(dlobj->dl_handle);
free(dlobj->dl_name);
PyObject_Del(dlobj);
}
@@ -3736,6 +4101,17 @@
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;
@@ -3746,6 +4122,9 @@
&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'",
@@ -3778,6 +4157,9 @@
&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) {
@@ -3803,6 +4185,9 @@
&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) {
@@ -3818,10 +4203,22 @@
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 */
};
@@ -3857,44 +4254,103 @@
dl_methods, /* tp_methods */
};
-static PyObject *b_load_library(PyObject *self, PyObject *args)
-{
- char *filename_or_null, *printable_filename;
+static void *b_do_dlopen(PyObject *args, const char **p_printable_filename,
+ PyObject **p_temp)
+{
+ /* 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;
- DynLibObject *dlobj;
+ char *filename_or_null;
int flags = 0;
-
+ *p_temp = NULL;
+
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;
- }
- else if (!PyArg_ParseTuple(args, "et|i:load_library",
- Py_FileSystemDefaultEncoding, &filename_or_null,
- &flags))
- return NULL;
-
+ *p_printable_filename = "<None>";
+ }
+ else
+ {
+ PyObject *s = PyTuple_GET_ITEM(args, 0);
+#ifdef MS_WIN32
+ Py_UNICODE *filenameW;
+ if (PyArg_ParseTuple(args, "u|i:load_library", &filenameW, &flags))
+ {
+#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;
+
+ handle = dlopenW(filenameW);
+ 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)
+ return NULL;
+ *p_temp = s;
+ }
+#endif
+ *p_printable_filename = PyText_AsUTF8(s);
+ if (*p_printable_filename == NULL)
+ return NULL;
+ }
if ((flags & (RTLD_NOW | RTLD_LAZY)) == 0)
flags |= RTLD_NOW;
- printable_filename = filename_or_null ? filename_or_null : "<None>";
handle = dlopen(filename_or_null, flags);
+
+#ifdef MS_WIN32
+ got_handle:
+#endif
if (handle == NULL) {
const char *error = dlerror();
- PyErr_Format(PyExc_OSError, "cannot load library %s: %s",
- printable_filename, error);
+ 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;
+
+ handle = b_do_dlopen(args, &printable_filename, &temp);
+ if (handle == NULL)
+ goto error;
dlobj = PyObject_New(DynLibObject, &dl_type);
if (dlobj == NULL) {
dlclose(handle);
- return NULL;
+ goto error;
}
dlobj->dl_handle = handle;
dlobj->dl_name = strdup(printable_filename);
+
+ error:
+ Py_XDECREF(temp);
return (PyObject *)dlobj;
}
@@ -3946,7 +4402,10 @@
assert(x->ct_unique_key == NULL);
x->ct_unique_key = key; /* the key will be freed in ctypedescr_dealloc() */
- Py_DECREF(x); /* the 'value' in unique_cache doesn't count as 1 */
+ /* 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:
@@ -3954,6 +4413,11 @@
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 \
@@ -3971,7 +4435,11 @@
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) \
@@ -4008,7 +4476,8 @@
#ifdef HAVE_WCHAR_H
# define ENUM_PRIMITIVE_TYPES_WCHAR \
- EPTYPE(wc, wchar_t, CT_PRIMITIVE_CHAR )
+ EPTYPE(wc, wchar_t, CT_PRIMITIVE_CHAR | \
+ (((wchar_t)-1) > 0 ? 0 : CT_IS_SIGNED_WCHAR))
#else
# define ENUM_PRIMITIVE_TYPES_WCHAR /* nothing */
#endif
@@ -4081,6 +4550,13 @@
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;
@@ -4215,9 +4691,6 @@
sprintf(extra_text, "[]");
length = -1;
arraysize = -1;
- if ((ctitem->ct_flags & CT_PRIMITIVE_CHAR) &&
- ctitem->ct_size == sizeof(char))
- flags |= CT_IS_UNSIZED_CHAR_A;
}
else {
sprintf(extra_text, "[%llu]", (unsigned PY_LONG_LONG)length);
@@ -4344,6 +4817,12 @@
#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 */
@@ -4403,14 +4882,22 @@
CFieldObject **previous;
int prev_bitfield_size, prev_bitfield_free;
int sflags = 0, fflags;
-
- if (!PyArg_ParseTuple(args, "O!O!|Onii:complete_struct_or_union",
+ int pack = 0;
+
+ if (!PyArg_ParseTuple(args, "O!O!|Oniii:complete_struct_or_union",
&CTypeDescr_Type, &ct,
&PyList_Type, &fields,
- &ignored, &totalsize, &totalalignment, &sflags))
+ &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)) {
@@ -4471,9 +4958,9 @@
/* update the total alignment requirement, but skip it if the
field is an anonymous bitfield or if SF_PACKED */
falignorg = get_alignment(ftype);
- falign = (sflags & SF_PACKED) ? 1 : falignorg;
- if (falign < 0)
+ if (falignorg < 0)
goto error;
+ falign = (pack < falignorg) ? pack : falignorg;
do_align = 1;
if (!(sflags & SF_GCC_ARM_BITFIELDS) && fbitsize >= 0) {
@@ -4520,7 +5007,6 @@
if (PyText_GetSize(fname) == 0 &&
ftype->ct_flags & (CT_STRUCT|CT_UNION)) {
/* a nested anonymous struct or union */
- /* note: it seems we only get here with ffi.verify() */
CFieldObject *cfsrc = (CFieldObject *)ftype->ct_extra;
for (; cfsrc != NULL; cfsrc = cfsrc->cf_next) {
/* broken complexity in the call to get_field_name(),
@@ -4773,7 +5259,7 @@
{
const char *place = is_result_type ? "return value" : "argument";
- if (ct->ct_flags & CT_PRIMITIVE_ANY) {
+ 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)) {
@@ -4899,9 +5385,16 @@
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",
- ct->ct_name, ct->ct_size, place);
+ "ctype '%s' (size %zd) not supported as %s%s",
+ ct->ct_name, ct->ct_size, place, extra);
return NULL;
}
}
@@ -5269,9 +5762,14 @@
return 0;
}
else if (ctype->ct_flags & (CT_PRIMITIVE_CHAR | CT_PRIMITIVE_SIGNED |
- CT_PRIMITIVE_UNSIGNED)) {
+ 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 */
+ 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);
@@ -5282,12 +5780,12 @@
return convert_from_object(result, ctype, pyobj);
}
-static void _my_PyErr_WriteUnraisable(char *objdescr, PyObject *obj,
+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 */
- PyObject *f, *t, *v, *tb;
- PyErr_Fetch(&t, &v, &tb);
+ 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);
@@ -5377,8 +5875,12 @@
}
onerror_cb = PyTuple_GET_ITEM(cb_args, 3);
if (onerror_cb == Py_None) {
- _my_PyErr_WriteUnraisable("From cffi callback ", py_ob,
+ 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;
@@ -5402,14 +5904,17 @@
}
else {
/* double exception! print a double-traceback... */
+ PyObject *ecap;
PyErr_Fetch(&exc2, &val2, &tb2);
- PyErr_Restore(exc1, val1, tb1);
- _my_PyErr_WriteUnraisable("From cffi callback ", py_ob,
+ ecap = _cffi_start_error_capture();
+ _my_PyErr_WriteUnraisable(exc1, val1, tb1,
+ "From cffi callback ", py_ob,
extra_error_line);
- PyErr_Restore(exc2, val2, tb2);
extra_error_line = ("\nDuring the call to 'onerror', "
"another exception occurred:\n\n");
- _my_PyErr_WriteUnraisable(NULL, NULL, extra_error_line);
+ _my_PyErr_WriteUnraisable(exc2, val2, tb2,
+ NULL, NULL, extra_error_line);
+ _cffi_stop_error_capture(ecap);
}
}
goto done;
@@ -5488,11 +5993,12 @@
static PyObject *b_callback(PyObject *self, PyObject *args)
{
CTypeDescrObject *ct;
- CDataObject *cd;
+ CDataObject_closure *cd;
PyObject *ob, *error_ob = Py_None, *onerror_ob = Py_None;
PyObject *infotuple;
cif_description_t *cif_descr;
ffi_closure *closure;
+ void *closure_exec;
if (!PyArg_ParseTuple(args, "O!O|OO:callback", &CTypeDescr_Type, &ct, &ob,
&error_ob, &onerror_ob))
@@ -5502,15 +6008,24 @@
if (infotuple == NULL)
return NULL;
+#ifdef CFFI_TRUST_LIBFFI
+ closure = ffi_closure_alloc(sizeof(ffi_closure), &closure_exec);
+#else
closure = cffi_closure_alloc();
-
- cd = PyObject_GC_New(CDataObject, &CDataOwningGC_Type);
+ closure_exec = closure;
+#endif
+ if (closure == NULL) {
+ Py_DECREF(infotuple);
+ return NULL;
+ }
+ cd = PyObject_GC_New(CDataObject_closure, &CDataOwningGC_Type);
if (cd == NULL)
goto error;
Py_INCREF(ct);
- cd->c_type = ct;
- cd->c_data = (char *)closure;
- cd->c_weakreflist = NULL;
+ cd->head.c_type = ct;
+ cd->head.c_data = (char *)closure_exec;
+ cd->head.c_weakreflist = NULL;
+ cd->closure = closure;
PyObject_GC_Track(cd);
cif_descr = (cif_description_t *)ct->ct_extra;
@@ -5520,8 +6035,13 @@
"return type or with '...'", ct->ct_name);
goto error;
}
+#ifdef CFFI_TRUST_LIBFFI
+ if (ffi_prep_closure_loc(closure, &cif_descr->cif,
+ invoke_callback, infotuple, closure_exec) != FFI_OK) {
+#else
if (ffi_prep_closure(closure, &cif_descr->cif,
invoke_callback, infotuple) != FFI_OK) {
+#endif
PyErr_SetString(PyExc_SystemError,
"libffi failed to build this callback");
goto error;
@@ -5544,8 +6064,13 @@
error:
closure->user_data = NULL;
- if (cd == NULL)
+ if (cd == NULL) {
+#ifdef CFFI_TRUST_LIBFFI
+ ffi_closure_free(closure);
+#else
cffi_closure_free(closure);
+#endif
+ }
else
Py_DECREF(cd);
Py_XDECREF(infotuple);
@@ -5596,7 +6121,7 @@
if (!PyText_Check(tmpkey)) {
#if PY_MAJOR_VERSION < 3
if (PyUnicode_Check(tmpkey)) {
- char *text = PyText_AsUTF8(tmpkey);
+ const char *text = PyText_AsUTF8(tmpkey);
if (text == NULL)
goto error;
Py_DECREF(tmpkey);
@@ -5888,27 +6413,46 @@
}
return PyBytes_FromStringAndSize(start, length);
}
-#ifdef HAVE_WCHAR_H
else if (cd->c_type->ct_itemdescr->ct_flags & CT_PRIMITIVE_CHAR) {
- const wchar_t *start = (wchar_t *)cd->c_data;
- assert(cd->c_type->ct_itemdescr->ct_size == sizeof(wchar_t));
- if (length < 0) {
- /*READ(start, sizeof(wchar_t))*/
- length = 0;
- while (start[length])
- length++;
- /*READ(start, sizeof(wchar_t) * length)*/
+ 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);
}
- else {
- /*READ(start, sizeof(wchar_t) * length)*/
- maxlen = length;
- length = 0;
- while (length < maxlen && start[length])
- 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);
}
- return _my_PyUnicode_FromWideChar(start, length);
- }
-#endif
+ }
+ }
}
else if (cd->c_type->ct_flags & CT_IS_ENUM) {
return convert_cdata_to_enum_string(cd, 0);
@@ -5922,12 +6466,14 @@
/*READ(cd->c_data, cd->c_type->ct_size)*/
if (cd->c_type->ct_size == sizeof(char))
return PyBytes_FromStringAndSize(cd->c_data, 1);
-#ifdef HAVE_WCHAR_H
else if (cd->c_type->ct_flags & CT_PRIMITIVE_CHAR) {
- assert(cd->c_type->ct_size == sizeof(wchar_t));
- return _my_PyUnicode_FromWideChar((wchar_t *)cd->c_data, 1);
- }
-#endif
+ 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);
@@ -5972,12 +6518,14 @@
/* byte- and unicode strings */
ctitem = cd->c_type->ct_itemdescr;
if (ctitem->ct_flags & CT_PRIMITIVE_CHAR) {
- if (ctitem->ct_size == sizeof(char))
+ switch (ctitem->ct_size) {
+ case sizeof(char):
return PyBytes_FromStringAndSize(cd->c_data, length);
-#ifdef HAVE_WCHAR_H
- else if (ctitem->ct_size == sizeof(wchar_t))
- return _my_PyUnicode_FromWideChar((wchar_t *)cd->c_data, length);
-#endif
+ 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
@@ -5993,6 +6541,7 @@
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;
@@ -6261,10 +6810,18 @@
return 0;
}
-static PyObject *direct_from_buffer(CTypeDescrObject *ct, PyObject *x)
+static PyObject *direct_from_buffer(CTypeDescrObject *ct, PyObject *x,
+ int require_writable)
{
CDataObject *cd;
Py_buffer *view;
+ Py_ssize_t arraylength;
+
+ if (!(ct->ct_flags & CT_ARRAY)) {
+ PyErr_Format(PyExc_TypeError, "expected an 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.
@@ -6281,9 +6838,44 @@
PyErr_NoMemory();
return NULL;
}
- if (_my_PyObject_GetContiguousBuffer(x, view, 0) < 0)
+ if (_my_PyObject_GetContiguousBuffer(x, view, require_writable) < 0)
goto error1;
+ if (ct->ct_length >= 0) {
+ /* it's an array with a fixed length; make sure that the
+ buffer contains enough bytes. */
+ if (view->len < ct->ct_size) {
+ PyErr_Format(PyExc_ValueError,
+ "buffer is too small (%zd bytes) for '%s' (%zd bytes)",
+ view->len, ct->ct_name, ct->ct_size);
+ goto error2;
+ }
+ arraylength = ct->ct_length;
+ }
+ 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;
+ }
+ }
+
cd = (CDataObject *)PyObject_GC_New(CDataObject_owngc_frombuf,
&CDataOwningGC_Type);
if (cd == NULL)
@@ -6293,7 +6885,7 @@
cd->c_type = ct;
cd->c_data = view->buf;
cd->c_weakreflist = NULL;
- ((CDataObject_owngc_frombuf *)cd)->length = view->len;
+ ((CDataObject_owngc_frombuf *)cd)->length = arraylength;
((CDataObject_owngc_frombuf *)cd)->bufferview = view;
PyObject_GC_Track(cd);
return (PyObject *)cd;
@@ -6309,15 +6901,13 @@
{
CTypeDescrObject *ct;
PyObject *x;
-
- if (!PyArg_ParseTuple(args, "O!O", &CTypeDescr_Type, &ct, &x))
+ int require_writable = 0;
+
+ if (!PyArg_ParseTuple(args, "O!O|i", &CTypeDescr_Type, &ct, &x,
+ &require_writable))
return NULL;
- if (!(ct->ct_flags & CT_IS_UNSIZED_CHAR_A)) {
- PyErr_Format(PyExc_TypeError, "needs 'char[]', got '%s'", ct->ct_name);
- return NULL;
- }
- return direct_from_buffer(ct, x);
+ return direct_from_buffer(ct, x, require_writable);
}
static int _fetch_as_buffer(PyObject *x, Py_buffer *view, int writable_only)
@@ -6384,10 +6974,12 @@
CDataObject *cd;
CDataObject *origobj;
PyObject *destructor;
- static char *keywords[] = {"cdata", "destructor", NULL};
-
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!O:gc", keywords,
- &CData_Type, &origobj, &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) {
@@ -6405,6 +6997,15 @@
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)
@@ -6579,6 +7180,20 @@
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 */
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit