summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2021-01-18 17:24:29 (GMT)
committerGitHub <noreply@github.com>2021-01-18 17:24:29 (GMT)
commite232025025c8bd07c1d1b12a583a80c4a673f077 (patch)
tree4e933d341363bcefedf7ca25f51cd35549ac86d0
parent998ae1fa3fb05a790071217cf8f6ae3a928da13f (diff)
downloadcpython-e232025025c8bd07c1d1b12a583a80c4a673f077.zip
cpython-e232025025c8bd07c1d1b12a583a80c4a673f077.tar.gz
cpython-e232025025c8bd07c1d1b12a583a80c4a673f077.tar.bz2
bpo-42923: Add Py_FatalError() test in test_capi (GH-24240)
Move faulthandler._fatal_error() to _testcapi.fatal_error().
-rw-r--r--Lib/test/test_capi.py9
-rw-r--r--Lib/test/test_faulthandler.py30
-rw-r--r--Modules/_testcapimodule.c23
-rw-r--r--Modules/faulthandler.c25
4 files changed, 48 insertions, 39 deletions
diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py
index a4ebe4a..0d5c97dcc 100644
--- a/Lib/test/test_capi.py
+++ b/Lib/test/test_capi.py
@@ -547,6 +547,15 @@ class CAPITest(unittest.TestCase):
self.assertRaises(TypeError, pynumber_tobase, '123', 10)
self.assertRaises(SystemError, pynumber_tobase, 123, 0)
+ def test_fatal_error(self):
+ code = 'import _testcapi; _testcapi.fatal_error(b"MESSAGE")'
+ with support.SuppressCrashReport():
+ rc, out, err = assert_python_failure('-sSI', '-c', code)
+
+ err = err.replace(b'\r', b'').decode('ascii', 'replace')
+ self.assertIn('Fatal Python error: test_fatal_error: MESSAGE\n',
+ err)
+
class TestPendingCalls(unittest.TestCase):
diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py
index 80c1f7d..bc61aab 100644
--- a/Lib/test/test_faulthandler.py
+++ b/Lib/test/test_faulthandler.py
@@ -227,25 +227,23 @@ class FaultHandlerTests(unittest.TestCase):
5,
'Illegal instruction')
+ def check_fatal_error_func(self, release_gil):
+ # Test that Py_FatalError() dumps a traceback
+ with support.SuppressCrashReport():
+ self.check_fatal_error(f"""
+ import _testcapi
+ _testcapi.fatal_error(b'xyz', {release_gil})
+ """,
+ 2,
+ 'xyz',
+ func='test_fatal_error',
+ py_fatal_error=True)
+
def test_fatal_error(self):
- self.check_fatal_error("""
- import faulthandler
- faulthandler._fatal_error(b'xyz')
- """,
- 2,
- 'xyz',
- func='faulthandler_fatal_error_py',
- py_fatal_error=True)
+ self.check_fatal_error_func(False)
def test_fatal_error_without_gil(self):
- self.check_fatal_error("""
- import faulthandler
- faulthandler._fatal_error(b'xyz', True)
- """,
- 2,
- 'xyz',
- func='faulthandler_fatal_error_py',
- py_fatal_error=True)
+ self.check_fatal_error_func(True)
@unittest.skipIf(sys.platform.startswith('openbsd'),
"Issue #12868: sigaltstack() doesn't work on "
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index 4f97927..2a5b3d9 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -5665,6 +5665,27 @@ test_refcount(PyObject *self, PyObject *Py_UNUSED(ignored))
}
+static PyObject *
+test_fatal_error(PyObject *self, PyObject *args)
+{
+ char *message;
+ int release_gil = 0;
+ if (!PyArg_ParseTuple(args, "y|i:fatal_error", &message, &release_gil))
+ return NULL;
+ if (release_gil) {
+ Py_BEGIN_ALLOW_THREADS
+ Py_FatalError(message);
+ Py_END_ALLOW_THREADS
+ }
+ else {
+ Py_FatalError(message);
+ }
+ // Py_FatalError() does not return, but exits the process.
+ Py_RETURN_NONE;
+}
+
+
+
static PyMethodDef TestMethods[] = {
{"raise_exception", raise_exception, METH_VARARGS},
{"raise_memoryerror", raise_memoryerror, METH_NOARGS},
@@ -5938,6 +5959,8 @@ static PyMethodDef TestMethods[] = {
{"without_gc", without_gc, METH_O},
{"test_set_type_size", test_set_type_size, METH_NOARGS},
{"test_refcount", test_refcount, METH_NOARGS},
+ {"fatal_error", test_fatal_error, METH_VARARGS,
+ PyDoc_STR("fatal_error(message, release_gil=False): call Py_FatalError(message)")},
{NULL, NULL} /* sentinel */
};
diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c
index 67fe1ca..fe5dbc1 100644
--- a/Modules/faulthandler.c
+++ b/Modules/faulthandler.c
@@ -1,6 +1,6 @@
#include "Python.h"
-#include "pycore_initconfig.h"
-#include "pycore_traceback.h"
+#include "pycore_initconfig.h" // _PyStatus_ERR
+#include "pycore_traceback.h" // _Py_DumpTracebackThreads
#include <signal.h>
#include <object.h>
#include <frameobject.h>
@@ -1123,25 +1123,6 @@ faulthandler_sigabrt(PyObject *self, PyObject *args)
Py_RETURN_NONE;
}
-static PyObject *
-faulthandler_fatal_error_py(PyObject *self, PyObject *args)
-{
- char *message;
- int release_gil = 0;
- if (!PyArg_ParseTuple(args, "y|i:fatal_error", &message, &release_gil))
- return NULL;
- faulthandler_suppress_crash_report();
- if (release_gil) {
- Py_BEGIN_ALLOW_THREADS
- Py_FatalError(message);
- Py_END_ALLOW_THREADS
- }
- else {
- Py_FatalError(message);
- }
- Py_RETURN_NONE;
-}
-
#if defined(FAULTHANDLER_USE_ALT_STACK)
#define FAULTHANDLER_STACK_OVERFLOW
@@ -1278,8 +1259,6 @@ static PyMethodDef module_methods[] = {
PyDoc_STR("_sigabrt(): raise a SIGABRT signal")},
{"_sigfpe", (PyCFunction)faulthandler_sigfpe, METH_NOARGS,
PyDoc_STR("_sigfpe(): raise a SIGFPE signal")},
- {"_fatal_error", faulthandler_fatal_error_py, METH_VARARGS,
- PyDoc_STR("_fatal_error(message): call Py_FatalError(message)")},
#ifdef FAULTHANDLER_STACK_OVERFLOW
{"_stack_overflow", faulthandler_stack_overflow, METH_NOARGS,
PyDoc_STR("_stack_overflow(): recursive call to raise a stack overflow")},