summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArmin Rigo <arigo@tunes.org>2021-06-20 21:14:08 +0200
committerArmin Rigo <arigo@tunes.org>2021-06-20 21:14:08 +0200
commit8f7155f8820223ed46fb4259fc688abad5ac9c25 (patch)
tree35f184cc2ebdb0b9cf0186e3a3748977669b75f1
parent25ba410f60e9150e0f0f1fb4dbac239534d4e51e (diff)
parentb9cbd7792003f9a262cfaf5ff6a1bc553e5ab6e4 (diff)
downloadcffi-8f7155f8820223ed46fb4259fc688abad5ac9c25.tar.gz
hg merge default
-rw-r--r--c/_cffi_backend.c66
-rw-r--r--c/ffi_obj.c2
-rw-r--r--c/test_c.py46
-rw-r--r--cffi/verifier.py3
-rw-r--r--doc/source/goals.rst4
-rw-r--r--doc/source/whatsnew.rst11
-rw-r--r--setup.py2
-rw-r--r--testing/cffi0/test_function.py10
-rw-r--r--testing/cffi1/test_recompiler.py7
-rw-r--r--testing/support.py5
10 files changed, 135 insertions, 21 deletions
diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
index 23304d3..6652803 100644
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -180,6 +180,10 @@
# 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: */
@@ -4516,14 +4520,18 @@ static void *b_do_dlopen(PyObject *args, const char **p_printable_filename,
if (PyUnicode_Check(s))
{
s = PyUnicode_AsUTF8String(s);
- if (s == NULL)
+ if (s == NULL) {
+ PyMem_Free(filename_or_null);
return NULL;
+ }
*p_temp = s;
}
#endif
*p_printable_filename = PyText_AsUTF8(s);
- if (*p_printable_filename == NULL)
+ if (*p_printable_filename == NULL) {
+ PyMem_Free(filename_or_null);
return NULL;
+ }
}
if ((flags & (RTLD_NOW | RTLD_LAZY)) == 0)
flags |= RTLD_NOW;
@@ -4536,6 +4544,7 @@ static void *b_do_dlopen(PyObject *args, const char **p_printable_filename,
#endif
handle = dlopen(filename_or_null, flags);
+ PyMem_Free(filename_or_null);
#ifdef MS_WIN32
got_handle:
@@ -5849,7 +5858,7 @@ static cif_description_t *fb_prepare_cif(PyObject *fargs,
char *buffer;
cif_description_t *cif_descr;
struct funcbuilder_s funcbuffer;
- ffi_status status = -1;
+ ffi_status status = (ffi_status)-1;
funcbuffer.nb_bytes = 0;
funcbuffer.bufferp = NULL;
@@ -5884,7 +5893,7 @@ static cif_description_t *fb_prepare_cif(PyObject *fargs,
}
#endif
- if (status == -1) {
+ if (status == (ffi_status)-1) {
status = ffi_prep_cif(&cif_descr->cif, fabi, funcbuffer.nargs,
funcbuffer.rtype, funcbuffer.atypes);
}
@@ -6061,6 +6070,43 @@ static void _my_PyErr_WriteUnraisable(PyObject *t, PyObject *v, PyObject *tb,
char *extra_error_line)
{
/* like PyErr_WriteUnraisable(), but write a full traceback */
+#ifdef USE_WRITEUNRAISABLEMSG
+
+ /* PyErr_WriteUnraisable actually writes the full traceback anyway
+ from Python 3.4, but we can't really get the formatting of the
+ custom text to be what we want. We can do better from Python
+ 3.8 by calling the new _PyErr_WriteUnraisableMsg().
+ Luckily it's also Python 3.8 that adds new functionality that
+ people might want: the new sys.unraisablehook().
+ */
+ PyObject *s;
+ int first_char;
+ assert(objdescr != NULL && objdescr[0] != 0); /* non-empty */
+ first_char = objdescr[0];
+ if (first_char >= 'A' && first_char <= 'Z')
+ first_char += 'a' - 'A'; /* lower() the very first character */
+ if (extra_error_line == NULL)
+ extra_error_line = "";
+
+ if (obj != NULL)
+ s = PyUnicode_FromFormat("%c%s%R%s",
+ first_char, objdescr + 1, obj, extra_error_line);
+ else
+ s = PyUnicode_FromFormat("%c%s%s",
+ first_char, objdescr + 1, extra_error_line);
+
+ PyErr_Restore(t, v, tb);
+ if (s != NULL) {
+ _PyErr_WriteUnraisableMsg(PyText_AS_UTF8(s), NULL);
+ Py_DECREF(s);
+ }
+ else
+ PyErr_WriteUnraisable(obj); /* best effort */
+ PyErr_Clear();
+
+#else
+
+ /* version for Python 2.7 and < 3.8 */
PyObject *f;
#if PY_MAJOR_VERSION >= 3
/* jump through hoops to ensure the tb is attached to v, on Python 3 */
@@ -6085,6 +6131,8 @@ static void _my_PyErr_WriteUnraisable(PyObject *t, PyObject *v, PyObject *tb,
Py_XDECREF(t);
Py_XDECREF(v);
Py_XDECREF(tb);
+
+#endif
}
static void general_invoke_callback(int decode_args_from_libffi,
@@ -6134,7 +6182,11 @@ static void general_invoke_callback(int decode_args_from_libffi,
goto error;
if (convert_from_object_fficallback(result, SIGNATURE(1), py_res,
decode_args_from_libffi) < 0) {
+#ifdef USE_WRITEUNRAISABLEMSG
+ extra_error_line = ", trying to convert the result back to C";
+#else
extra_error_line = "Trying to convert the result back to C:\n";
+#endif
goto error;
}
done:
@@ -6186,10 +6238,16 @@ static void general_invoke_callback(int decode_args_from_libffi,
_my_PyErr_WriteUnraisable(exc1, val1, tb1,
"From cffi callback ", py_ob,
extra_error_line);
+#ifdef USE_WRITEUNRAISABLEMSG
+ _my_PyErr_WriteUnraisable(exc2, val2, tb2,
+ "during handling of the above exception by 'onerror'",
+ NULL, NULL);
+#else
extra_error_line = ("\nDuring the call to 'onerror', "
"another exception occurred:\n\n");
_my_PyErr_WriteUnraisable(exc2, val2, tb2,
NULL, NULL, extra_error_line);
+#endif
_cffi_stop_error_capture(ecap);
}
}
diff --git a/c/ffi_obj.c b/c/ffi_obj.c
index 05c3a6d..f154146 100644
--- a/c/ffi_obj.c
+++ b/c/ffi_obj.c
@@ -1070,10 +1070,10 @@ static PyObject *ffi_init_once(FFIObject *self, PyObject *args, PyObject *kwds)
if (res != NULL) {
tup = PyTuple_Pack(2, Py_True, res);
if (tup == NULL || PyDict_SetItem(cache, tag, tup) < 0) {
- Py_XDECREF(tup);
Py_DECREF(res);
res = NULL;
}
+ Py_XDECREF(tup);
}
}
diff --git a/c/test_c.py b/c/test_c.py
index 69ad15e..6c2e5a7 100644
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -1331,7 +1331,9 @@ def test_callback_exception():
except ImportError:
import io as cStringIO # Python 3
import linecache
- def matches(istr, ipattern):
+ def matches(istr, ipattern, ipattern38):
+ if sys.version_info >= (3, 8):
+ ipattern = ipattern38
str, pattern = istr, ipattern
while '$' in pattern:
i = pattern.index('$')
@@ -1364,6 +1366,8 @@ def test_callback_exception():
try:
linecache.getline = lambda *args: 'LINE' # hack: speed up PyPy tests
sys.stderr = cStringIO.StringIO()
+ if hasattr(sys, '__unraisablehook__'): # work around pytest
+ sys.unraisablehook = sys.__unraisablehook__ # on recent CPythons
assert f(100) == 300
assert sys.stderr.getvalue() == ''
assert f(10000) == -42
@@ -1375,6 +1379,14 @@ Traceback (most recent call last):
File "$", line $, in check_value
$
ValueError: 42
+""", """\
+Exception ignored from cffi callback <function$Zcb1 at 0x$>:
+Traceback (most recent call last):
+ File "$", line $, in Zcb1
+ $
+ File "$", line $, in check_value
+ $
+ValueError: 42
""")
sys.stderr = cStringIO.StringIO()
bigvalue = 20000
@@ -1383,6 +1395,12 @@ ValueError: 42
From cffi callback <function$Zcb1 at 0x$>:
Trying to convert the result back to C:
OverflowError: integer 60000 does not fit 'short'
+""", """\
+Exception ignored from cffi callback <function$Zcb1 at 0x$>, trying to convert the result back to C:
+Traceback (most recent call last):
+ File "$", line $, in test_callback_exception
+ $
+OverflowError: integer 60000 does not fit 'short'
""")
sys.stderr = cStringIO.StringIO()
bigvalue = 20000
@@ -1420,11 +1438,24 @@ OverflowError: integer 60000 does not fit 'short'
During the call to 'onerror', another exception occurred:
TypeError: $integer$
+""", """\
+Exception ignored from cffi callback <function$Zcb1 at 0x$>, trying to convert the result back to C:
+Traceback (most recent call last):
+ File "$", line $, in test_callback_exception
+ $
+OverflowError: integer 60000 does not fit 'short'
+Exception ignored during handling of the above exception by 'onerror':
+Traceback (most recent call last):
+ File "$", line $, in test_callback_exception
+ $
+TypeError: $integer$
""")
#
sys.stderr = cStringIO.StringIO()
seen = "not a list" # this makes the oops() function crash
assert ff(bigvalue) == -42
+ # the $ after the AttributeError message are for the suggestions that
+ # will be added in Python 3.10
assert matches(sys.stderr.getvalue(), """\
From cffi callback <function$Zcb1 at 0x$>:
Trying to convert the result back to C:
@@ -1435,7 +1466,18 @@ During the call to 'onerror', another exception occurred:
Traceback (most recent call last):
File "$", line $, in oops
$
-AttributeError: 'str' object has no attribute 'append'
+AttributeError: 'str' object has no attribute 'append$
+""", """\
+Exception ignored from cffi callback <function$Zcb1 at 0x$>, trying to convert the result back to C:
+Traceback (most recent call last):
+ File "$", line $, in test_callback_exception
+ $
+OverflowError: integer 60000 does not fit 'short'
+Exception ignored during handling of the above exception by 'onerror':
+Traceback (most recent call last):
+ File "$", line $, in oops
+ $
+AttributeError: 'str' object has no attribute 'append$
""")
finally:
sys.stderr = orig_stderr
diff --git a/cffi/verifier.py b/cffi/verifier.py
index 59b78c2..a500c78 100644
--- a/cffi/verifier.py
+++ b/cffi/verifier.py
@@ -50,7 +50,8 @@ class Verifier(object):
if tag:
raise TypeError("can't specify both 'modulename' and 'tag'")
else:
- key = '\x00'.join([sys.version[:3], __version_verifier_modules__,
+ key = '\x00'.join(['%d.%d' % sys.version_info[:2],
+ __version_verifier_modules__,
preamble, flattened_kwds] +
ffi._cdefsources)
if sys.version_info >= (3,):
diff --git a/doc/source/goals.rst b/doc/source/goals.rst
index f66df21..df4877c 100644
--- a/doc/source/goals.rst
+++ b/doc/source/goals.rst
@@ -55,8 +55,8 @@ Get started by reading `the overview`__.
Comments and bugs
-----------------
-The best way to contact us is on the IRC ``#pypy`` channel of
-``irc.freenode.net``. Feel free to discuss matters either there or in
+The best way to contact us is on the IRC ``#cffi`` or ``#pypy`` channels of
+``irc.libera.chat``. Feel free to discuss matters either there or in
the `mailing list`_. Please report to the `issue tracker`_ any bugs.
As a general rule, when there is a design issue to resolve, we pick the
diff --git a/doc/source/whatsnew.rst b/doc/source/whatsnew.rst
index f6111d5..ff09168 100644
--- a/doc/source/whatsnew.rst
+++ b/doc/source/whatsnew.rst
@@ -2,6 +2,17 @@
What's New
======================
+v1.14.6
+=======
+
+* Test fixes for CPython 3.10.0b3
+
+* Support for `sys.unraisablehook()` on Python >= 3.8
+
+* Fix two minor memory leaks (thanks Sebastian!)
+
+* Like many projects that had an IRC channel on freenode, we moved it to
+ ``irc.libera.chat``.
v1.14.5
=======
diff --git a/setup.py b/setup.py
index c5c07b2..6b9ed98 100644
--- a/setup.py
+++ b/setup.py
@@ -56,7 +56,7 @@ def no_working_compiler_found():
tries to compile C code. (Hints: on OS/X 10.8, for errors about
-mno-fused-madd see http://stackoverflow.com/questions/22313407/
Otherwise, see https://wiki.python.org/moin/CompLangPython or
- the IRC channel #python on irc.freenode.net.)
+ the IRC channel #python on irc.libera.chat.)
Trying to continue anyway. If you are trying to install CFFI from
a build done in a different context, you can ignore this warning.
diff --git a/testing/cffi0/test_function.py b/testing/cffi0/test_function.py
index 4f2c864..b4bb23d 100644
--- a/testing/cffi0/test_function.py
+++ b/testing/cffi0/test_function.py
@@ -5,7 +5,7 @@ import math, os, sys
import ctypes.util
from cffi.backend_ctypes import CTypesBackend
from testing.udir import udir
-from testing.support import FdWriteCapture
+from testing.support import FdWriteCapture, StdErrCapture
from .backend_tests import needs_dlopen_none
try:
@@ -227,13 +227,9 @@ class TestFunction(object):
def cb():
return returnvalue
fptr = ffi.callback("void(*)(void)", cb)
- old_stderr = sys.stderr
- try:
- sys.stderr = StringIO()
+ with StdErrCapture() as f:
returned = fptr()
- printed = sys.stderr.getvalue()
- finally:
- sys.stderr = old_stderr
+ printed = f.getvalue()
assert returned is None
if returnvalue is None:
assert printed == ''
diff --git a/testing/cffi1/test_recompiler.py b/testing/cffi1/test_recompiler.py
index b35c3eb..fdb4d5a 100644
--- a/testing/cffi1/test_recompiler.py
+++ b/testing/cffi1/test_recompiler.py
@@ -1669,9 +1669,10 @@ def test_extern_python_bogus_result_type():
with StdErrCapture() as f:
res = lib.bar(321)
assert res is None
- assert f.getvalue() == (
- "From cffi callback %r:\n" % (bar,) +
- "Trying to convert the result back to C:\n"
+ msg = f.getvalue()
+ assert "rom cffi callback %r" % (bar,) in msg
+ assert "rying to convert the result back to C:\n" in msg
+ assert msg.endswith(
"TypeError: callback with the return type 'void' must return None\n")
def test_extern_python_redefine():
diff --git a/testing/support.py b/testing/support.py
index de8131c..6339a94 100644
--- a/testing/support.py
+++ b/testing/support.py
@@ -33,9 +33,14 @@ class StdErrCapture(object):
from io import StringIO
self.old_stderr = sys.stderr
sys.stderr = f = StringIO()
+ if hasattr(sys, '__unraisablehook__'): # work around pytest
+ self.old_unraisablebook = sys.unraisablehook # on recent CPythons
+ sys.unraisablehook = sys.__unraisablehook__
return f
def __exit__(self, *args):
sys.stderr = self.old_stderr
+ if hasattr(self, 'old_unraisablebook'):
+ sys.unraisablehook = self.old_unraisablebook
class FdWriteCapture(object):