diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index 672537bfedc9af..09767b8b7306b7 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -835,6 +835,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(c_exception)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(c_parameter_type)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(c_return)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(c_stack)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(cached_datetime_module)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(cached_statements)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(cadata)); @@ -849,6 +850,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(category)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(cb_type)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(certfile)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(chain)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(check_same_thread)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(clear)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(close)); @@ -943,6 +945,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(excepthook)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(exception)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(existing_file_name)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(exit)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(exp)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(expression)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(extend)); @@ -1203,6 +1206,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(rel_tol)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(release)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(reload)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(repeat)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(repl)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(replace)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(reqrefs)); @@ -1241,6 +1245,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(shared)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(show_cmd)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(signed)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(signum)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(size)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(sizehint)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(skip_file_prefixes)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index ed767206ee7322..c621caedbdb1d4 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -326,6 +326,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(c_exception) STRUCT_FOR_ID(c_parameter_type) STRUCT_FOR_ID(c_return) + STRUCT_FOR_ID(c_stack) STRUCT_FOR_ID(cached_datetime_module) STRUCT_FOR_ID(cached_statements) STRUCT_FOR_ID(cadata) @@ -340,6 +341,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(category) STRUCT_FOR_ID(cb_type) STRUCT_FOR_ID(certfile) + STRUCT_FOR_ID(chain) STRUCT_FOR_ID(check_same_thread) STRUCT_FOR_ID(clear) STRUCT_FOR_ID(close) @@ -434,6 +436,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(excepthook) STRUCT_FOR_ID(exception) STRUCT_FOR_ID(existing_file_name) + STRUCT_FOR_ID(exit) STRUCT_FOR_ID(exp) STRUCT_FOR_ID(expression) STRUCT_FOR_ID(extend) @@ -694,6 +697,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(rel_tol) STRUCT_FOR_ID(release) STRUCT_FOR_ID(reload) + STRUCT_FOR_ID(repeat) STRUCT_FOR_ID(repl) STRUCT_FOR_ID(replace) STRUCT_FOR_ID(reqrefs) @@ -732,6 +736,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(shared) STRUCT_FOR_ID(show_cmd) STRUCT_FOR_ID(signed) + STRUCT_FOR_ID(signum) STRUCT_FOR_ID(size) STRUCT_FOR_ID(sizehint) STRUCT_FOR_ID(skip_file_prefixes) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index 2f24a138fdbf0c..e3ec849fd6306e 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -833,6 +833,7 @@ extern "C" { INIT_ID(c_exception), \ INIT_ID(c_parameter_type), \ INIT_ID(c_return), \ + INIT_ID(c_stack), \ INIT_ID(cached_datetime_module), \ INIT_ID(cached_statements), \ INIT_ID(cadata), \ @@ -847,6 +848,7 @@ extern "C" { INIT_ID(category), \ INIT_ID(cb_type), \ INIT_ID(certfile), \ + INIT_ID(chain), \ INIT_ID(check_same_thread), \ INIT_ID(clear), \ INIT_ID(close), \ @@ -941,6 +943,7 @@ extern "C" { INIT_ID(excepthook), \ INIT_ID(exception), \ INIT_ID(existing_file_name), \ + INIT_ID(exit), \ INIT_ID(exp), \ INIT_ID(expression), \ INIT_ID(extend), \ @@ -1201,6 +1204,7 @@ extern "C" { INIT_ID(rel_tol), \ INIT_ID(release), \ INIT_ID(reload), \ + INIT_ID(repeat), \ INIT_ID(repl), \ INIT_ID(replace), \ INIT_ID(reqrefs), \ @@ -1239,6 +1243,7 @@ extern "C" { INIT_ID(shared), \ INIT_ID(show_cmd), \ INIT_ID(signed), \ + INIT_ID(signum), \ INIT_ID(size), \ INIT_ID(sizehint), \ INIT_ID(skip_file_prefixes), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index 4f8866e729c51e..1782874278ee89 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -1092,6 +1092,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(c_stack); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(cached_datetime_module); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -1148,6 +1152,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(chain); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(check_same_thread); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -1524,6 +1532,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(exit); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(exp); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2564,6 +2576,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(repeat); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(repl); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2716,6 +2732,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(signum); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(size); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py index 2fb963f52e5138..874f52af857b94 100644 --- a/Lib/test/test_faulthandler.py +++ b/Lib/test/test_faulthandler.py @@ -360,6 +360,17 @@ def test_enable_single_thread(self): 'Segmentation fault', all_threads=False) + @skip_segfault_on_android + def test_enable_without_c_stack(self): + self.check_fatal_error(""" + import faulthandler + faulthandler.enable(c_stack=False) + faulthandler._sigsegv() + """, + 3, + 'Segmentation fault', + c_stack=False) + @skip_segfault_on_android def test_disable(self): code = """ diff --git a/Modules/clinic/faulthandler.c.h b/Modules/clinic/faulthandler.c.h new file mode 100644 index 00000000000000..de8280ce26b9ce --- /dev/null +++ b/Modules/clinic/faulthandler.c.h @@ -0,0 +1,688 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +# include "pycore_gc.h" // PyGC_Head +# include "pycore_runtime.h" // _Py_ID() +#endif +#include "pycore_long.h" // _PyLong_UnsignedInt_Converter() +#include "pycore_modsupport.h" // _PyArg_UnpackKeywords() + +PyDoc_STRVAR(faulthandler_dump_traceback_py__doc__, +"dump_traceback($module, /, file=sys.stderr, all_threads=True)\n" +"--\n" +"\n" +"Dump the traceback of the current thread into file.\n" +"\n" +"Dump the traceback of all threads if all_threads is true."); + +#define FAULTHANDLER_DUMP_TRACEBACK_PY_METHODDEF \ + {"dump_traceback", _PyCFunction_CAST(faulthandler_dump_traceback_py), METH_FASTCALL|METH_KEYWORDS, faulthandler_dump_traceback_py__doc__}, + +static PyObject * +faulthandler_dump_traceback_py_impl(PyObject *module, PyObject *file, + int all_threads); + +static PyObject * +faulthandler_dump_traceback_py(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(file), &_Py_ID(all_threads), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"file", "all_threads", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "dump_traceback", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *file = NULL; + int all_threads = 1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 0, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (args[0]) { + file = args[0]; + if (!--noptargs) { + goto skip_optional_pos; + } + } + all_threads = PyObject_IsTrue(args[1]); + if (all_threads < 0) { + goto exit; + } +skip_optional_pos: + return_value = faulthandler_dump_traceback_py_impl(module, file, all_threads); + +exit: + return return_value; +} + +PyDoc_STRVAR(faulthandler_dump_c_stack_py__doc__, +"dump_c_stack($module, /, file=sys.stderr)\n" +"--\n" +"\n" +"Dump the C stack of the current thread."); + +#define FAULTHANDLER_DUMP_C_STACK_PY_METHODDEF \ + {"dump_c_stack", _PyCFunction_CAST(faulthandler_dump_c_stack_py), METH_FASTCALL|METH_KEYWORDS, faulthandler_dump_c_stack_py__doc__}, + +static PyObject * +faulthandler_dump_c_stack_py_impl(PyObject *module, PyObject *file); + +static PyObject * +faulthandler_dump_c_stack_py(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(file), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"file", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "dump_c_stack", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *file = NULL; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + file = args[0]; +skip_optional_pos: + return_value = faulthandler_dump_c_stack_py_impl(module, file); + +exit: + return return_value; +} + +PyDoc_STRVAR(faulthandler_py_enable__doc__, +"enable($module, /, file=sys.stderr, all_threads=True, c_stack=True)\n" +"--\n" +"\n" +"Enable the fault handler."); + +#define FAULTHANDLER_PY_ENABLE_METHODDEF \ + {"enable", _PyCFunction_CAST(faulthandler_py_enable), METH_FASTCALL|METH_KEYWORDS, faulthandler_py_enable__doc__}, + +static PyObject * +faulthandler_py_enable_impl(PyObject *module, PyObject *file, + int all_threads, int c_stack); + +static PyObject * +faulthandler_py_enable(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 3 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(file), &_Py_ID(all_threads), &_Py_ID(c_stack), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"file", "all_threads", "c_stack", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "enable", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[3]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + PyObject *file = NULL; + int all_threads = 1; + int c_stack = 1; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 0, /*maxpos*/ 3, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (args[0]) { + file = args[0]; + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (args[1]) { + all_threads = PyObject_IsTrue(args[1]); + if (all_threads < 0) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + c_stack = PyObject_IsTrue(args[2]); + if (c_stack < 0) { + goto exit; + } +skip_optional_pos: + return_value = faulthandler_py_enable_impl(module, file, all_threads, c_stack); + +exit: + return return_value; +} + +PyDoc_STRVAR(faulthandler_disable_py__doc__, +"disable($module, /)\n" +"--\n" +"\n" +"Disable the fault handler."); + +#define FAULTHANDLER_DISABLE_PY_METHODDEF \ + {"disable", (PyCFunction)faulthandler_disable_py, METH_NOARGS, faulthandler_disable_py__doc__}, + +static PyObject * +faulthandler_disable_py_impl(PyObject *module); + +static PyObject * +faulthandler_disable_py(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return faulthandler_disable_py_impl(module); +} + +PyDoc_STRVAR(faulthandler_is_enabled__doc__, +"is_enabled($module, /)\n" +"--\n" +"\n" +"Check if the handler is enabled."); + +#define FAULTHANDLER_IS_ENABLED_METHODDEF \ + {"is_enabled", (PyCFunction)faulthandler_is_enabled, METH_NOARGS, faulthandler_is_enabled__doc__}, + +static int +faulthandler_is_enabled_impl(PyObject *module); + +static PyObject * +faulthandler_is_enabled(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + int _return_value; + + _return_value = faulthandler_is_enabled_impl(module); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } + return_value = PyBool_FromLong((long)_return_value); + +exit: + return return_value; +} + +PyDoc_STRVAR(faulthandler_dump_traceback_later__doc__, +"dump_traceback_later($module, /, timeout, repeat=False,\n" +" file=sys.stderr, exit=False)\n" +"--\n" +"\n" +"Dump the traceback of all threads in timeout seconds.\n" +"\n" +"If repeat is true, the tracebacks of all threads are dumped every timeout\n" +"seconds. If exit is true, call _exit(1) which is not safe."); + +#define FAULTHANDLER_DUMP_TRACEBACK_LATER_METHODDEF \ + {"dump_traceback_later", _PyCFunction_CAST(faulthandler_dump_traceback_later), METH_FASTCALL|METH_KEYWORDS, faulthandler_dump_traceback_later__doc__}, + +static PyObject * +faulthandler_dump_traceback_later_impl(PyObject *module, + PyObject *timeout_obj, int repeat, + PyObject *file, int exit); + +static PyObject * +faulthandler_dump_traceback_later(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 4 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(timeout), &_Py_ID(repeat), &_Py_ID(file), &_Py_ID(exit), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"timeout", "repeat", "file", "exit", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "dump_traceback_later", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[4]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; + PyObject *timeout_obj; + int repeat = 0; + PyObject *file = NULL; + int exit = 0; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 4, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + timeout_obj = args[0]; + if (!noptargs) { + goto skip_optional_pos; + } + if (args[1]) { + repeat = PyObject_IsTrue(args[1]); + if (repeat < 0) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (args[2]) { + file = args[2]; + if (!--noptargs) { + goto skip_optional_pos; + } + } + exit = PyObject_IsTrue(args[3]); + if (exit < 0) { + goto exit; + } +skip_optional_pos: + return_value = faulthandler_dump_traceback_later_impl(module, timeout_obj, repeat, file, exit); + +exit: + return return_value; +} + +PyDoc_STRVAR(faulthandler_cancel_dump_traceback_later_py__doc__, +"cancel_dump_traceback_later($module, /)\n" +"--\n" +"\n" +"Cancel the previous call to dump_traceback_later()."); + +#define FAULTHANDLER_CANCEL_DUMP_TRACEBACK_LATER_PY_METHODDEF \ + {"cancel_dump_traceback_later", (PyCFunction)faulthandler_cancel_dump_traceback_later_py, METH_NOARGS, faulthandler_cancel_dump_traceback_later_py__doc__}, + +static PyObject * +faulthandler_cancel_dump_traceback_later_py_impl(PyObject *module); + +static PyObject * +faulthandler_cancel_dump_traceback_later_py(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return faulthandler_cancel_dump_traceback_later_py_impl(module); +} + +#if defined(FAULTHANDLER_USER) + +PyDoc_STRVAR(faulthandler_register_py__doc__, +"register($module, /, signum, file=sys.stderr, all_threads=True,\n" +" chain=False)\n" +"--\n" +"\n" +"Register a handler for the signal \'signum\'.\n" +"\n" +"Dump the traceback of the current thread, or of all threads if\n" +"all_threads is True, into file."); + +#define FAULTHANDLER_REGISTER_PY_METHODDEF \ + {"register", _PyCFunction_CAST(faulthandler_register_py), METH_FASTCALL|METH_KEYWORDS, faulthandler_register_py__doc__}, + +static PyObject * +faulthandler_register_py_impl(PyObject *module, int signum, PyObject *file, + int all_threads, int chain); + +static PyObject * +faulthandler_register_py(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 4 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(signum), &_Py_ID(file), &_Py_ID(all_threads), &_Py_ID(chain), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"signum", "file", "all_threads", "chain", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "register", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[4]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; + int signum; + PyObject *file = NULL; + int all_threads = 1; + int chain = 0; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 4, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + signum = PyLong_AsInt(args[0]); + if (signum == -1 && PyErr_Occurred()) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (args[1]) { + file = args[1]; + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (args[2]) { + all_threads = PyObject_IsTrue(args[2]); + if (all_threads < 0) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + chain = PyObject_IsTrue(args[3]); + if (chain < 0) { + goto exit; + } +skip_optional_pos: + return_value = faulthandler_register_py_impl(module, signum, file, all_threads, chain); + +exit: + return return_value; +} + +#endif /* defined(FAULTHANDLER_USER) */ + +#if defined(FAULTHANDLER_USER) + +PyDoc_STRVAR(faulthandler_unregister_py__doc__, +"unregister($module, signum, /)\n" +"--\n" +"\n" +"Unregister the handler of the signal \'signum\' registered by register()."); + +#define FAULTHANDLER_UNREGISTER_PY_METHODDEF \ + {"unregister", (PyCFunction)faulthandler_unregister_py, METH_O, faulthandler_unregister_py__doc__}, + +static PyObject * +faulthandler_unregister_py_impl(PyObject *module, int signum); + +static PyObject * +faulthandler_unregister_py(PyObject *module, PyObject *arg) +{ + PyObject *return_value = NULL; + int signum; + + signum = PyLong_AsInt(arg); + if (signum == -1 && PyErr_Occurred()) { + goto exit; + } + return_value = faulthandler_unregister_py_impl(module, signum); + +exit: + return return_value; +} + +#endif /* defined(FAULTHANDLER_USER) */ + +PyDoc_STRVAR(faulthandler__sigsegv__doc__, +"_sigsegv($module, release_gil=False, /)\n" +"--\n" +"\n" +"Raise a SIGSEGV signal."); + +#define FAULTHANDLER__SIGSEGV_METHODDEF \ + {"_sigsegv", _PyCFunction_CAST(faulthandler__sigsegv), METH_FASTCALL, faulthandler__sigsegv__doc__}, + +static PyObject * +faulthandler__sigsegv_impl(PyObject *module, int release_gil); + +static PyObject * +faulthandler__sigsegv(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + int release_gil = 0; + + if (!_PyArg_CheckPositional("_sigsegv", nargs, 0, 1)) { + goto exit; + } + if (nargs < 1) { + goto skip_optional; + } + release_gil = PyObject_IsTrue(args[0]); + if (release_gil < 0) { + goto exit; + } +skip_optional: + return_value = faulthandler__sigsegv_impl(module, release_gil); + +exit: + return return_value; +} + +PyDoc_STRVAR(faulthandler__fatal_error_c_thread__doc__, +"_fatal_error_c_thread($module, /)\n" +"--\n" +"\n" +"Call Py_FatalError() in a new C thread."); + +#define FAULTHANDLER__FATAL_ERROR_C_THREAD_METHODDEF \ + {"_fatal_error_c_thread", (PyCFunction)faulthandler__fatal_error_c_thread, METH_NOARGS, faulthandler__fatal_error_c_thread__doc__}, + +static PyObject * +faulthandler__fatal_error_c_thread_impl(PyObject *module); + +static PyObject * +faulthandler__fatal_error_c_thread(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return faulthandler__fatal_error_c_thread_impl(module); +} + +PyDoc_STRVAR(faulthandler__sigfpe__doc__, +"_sigfpe($module, /)\n" +"--\n" +"\n" +"Raise a SIGFPE signal."); + +#define FAULTHANDLER__SIGFPE_METHODDEF \ + {"_sigfpe", (PyCFunction)faulthandler__sigfpe, METH_NOARGS, faulthandler__sigfpe__doc__}, + +static PyObject * +faulthandler__sigfpe_impl(PyObject *module); + +static PyObject * +faulthandler__sigfpe(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return faulthandler__sigfpe_impl(module); +} + +PyDoc_STRVAR(faulthandler__sigabrt__doc__, +"_sigabrt($module, /)\n" +"--\n" +"\n" +"Raise a SIGABRT signal."); + +#define FAULTHANDLER__SIGABRT_METHODDEF \ + {"_sigabrt", (PyCFunction)faulthandler__sigabrt, METH_NOARGS, faulthandler__sigabrt__doc__}, + +static PyObject * +faulthandler__sigabrt_impl(PyObject *module); + +static PyObject * +faulthandler__sigabrt(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return faulthandler__sigabrt_impl(module); +} + +#if defined(FAULTHANDLER_USE_ALT_STACK) + +PyDoc_STRVAR(faulthandler__stack_overflow__doc__, +"_stack_overflow($module, /)\n" +"--\n" +"\n" +"Recursive call to raise a stack overflow."); + +#define FAULTHANDLER__STACK_OVERFLOW_METHODDEF \ + {"_stack_overflow", (PyCFunction)faulthandler__stack_overflow, METH_NOARGS, faulthandler__stack_overflow__doc__}, + +static PyObject * +faulthandler__stack_overflow_impl(PyObject *module); + +static PyObject * +faulthandler__stack_overflow(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return faulthandler__stack_overflow_impl(module); +} + +#endif /* defined(FAULTHANDLER_USE_ALT_STACK) */ + +#if defined(MS_WINDOWS) + +PyDoc_STRVAR(faulthandler__raise_exception__doc__, +"_raise_exception($module, code, flags=0, /)\n" +"--\n" +"\n" +"Call RaiseException(code, flags)."); + +#define FAULTHANDLER__RAISE_EXCEPTION_METHODDEF \ + {"_raise_exception", _PyCFunction_CAST(faulthandler__raise_exception), METH_FASTCALL, faulthandler__raise_exception__doc__}, + +static PyObject * +faulthandler__raise_exception_impl(PyObject *module, unsigned int code, + unsigned int flags); + +static PyObject * +faulthandler__raise_exception(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + unsigned int code; + unsigned int flags = 0; + + if (!_PyArg_CheckPositional("_raise_exception", nargs, 1, 2)) { + goto exit; + } + if (!_PyLong_UnsignedInt_Converter(args[0], &code)) { + goto exit; + } + if (nargs < 2) { + goto skip_optional; + } + if (!_PyLong_UnsignedInt_Converter(args[1], &flags)) { + goto exit; + } +skip_optional: + return_value = faulthandler__raise_exception_impl(module, code, flags); + +exit: + return return_value; +} + +#endif /* defined(MS_WINDOWS) */ + +#ifndef FAULTHANDLER_REGISTER_PY_METHODDEF + #define FAULTHANDLER_REGISTER_PY_METHODDEF +#endif /* !defined(FAULTHANDLER_REGISTER_PY_METHODDEF) */ + +#ifndef FAULTHANDLER_UNREGISTER_PY_METHODDEF + #define FAULTHANDLER_UNREGISTER_PY_METHODDEF +#endif /* !defined(FAULTHANDLER_UNREGISTER_PY_METHODDEF) */ + +#ifndef FAULTHANDLER__STACK_OVERFLOW_METHODDEF + #define FAULTHANDLER__STACK_OVERFLOW_METHODDEF +#endif /* !defined(FAULTHANDLER__STACK_OVERFLOW_METHODDEF) */ + +#ifndef FAULTHANDLER__RAISE_EXCEPTION_METHODDEF + #define FAULTHANDLER__RAISE_EXCEPTION_METHODDEF +#endif /* !defined(FAULTHANDLER__RAISE_EXCEPTION_METHODDEF) */ +/*[clinic end generated code: output=31bf0149d0d02ccf input=a9049054013a1b77]*/ diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c index 84cfc6bd8ef6e4..9b8c77e2b0401f 100644 --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -30,6 +30,9 @@ #endif +#include "clinic/faulthandler.c.h" + + /* Sentinel to ignore all_threads on free-threading */ #define FT_IGNORE_ALL_THREADS 2 @@ -39,6 +42,12 @@ #define PUTS(fd, str) (void)_Py_write_noraise(fd, str, strlen(str)) +/*[clinic input] +module faulthandler +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=c3d4f47c4f3d440f]*/ + + typedef struct { int signum; int enabled; @@ -228,22 +237,27 @@ faulthandler_dump_c_stack(int fd) reentrant = 0; } -static PyObject* -faulthandler_dump_traceback_py(PyObject *self, - PyObject *args, PyObject *kwargs) + +/*[clinic input] +faulthandler.dump_traceback as faulthandler_dump_traceback_py + + file: object(py_default="sys.stderr") = NULL + all_threads: bool = True + +Dump the traceback of the current thread into file. + +Dump the traceback of all threads if all_threads is true. +[clinic start generated code]*/ + +static PyObject * +faulthandler_dump_traceback_py_impl(PyObject *module, PyObject *file, + int all_threads) +/*[clinic end generated code: output=34efece0ca18314f input=b832ec55e27a7898]*/ { - static char *kwlist[] = {"file", "all_threads", NULL}; - PyObject *file = NULL; - int all_threads = 1; PyThreadState *tstate; const char *errmsg; int fd; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "|Op:dump_traceback", kwlist, - &file, &all_threads)) - return NULL; - fd = faulthandler_get_fileno(&file); if (fd < 0) return NULL; @@ -278,19 +292,19 @@ faulthandler_dump_traceback_py(PyObject *self, Py_RETURN_NONE; } -static PyObject * -faulthandler_dump_c_stack_py(PyObject *self, - PyObject *args, PyObject *kwargs) -{ - static char *kwlist[] = {"file", NULL}; - PyObject *file = NULL; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "|O:dump_c_stack", kwlist, - &file)) { - return NULL; - } +/*[clinic input] +faulthandler.dump_c_stack as faulthandler_dump_c_stack_py + + file: object(py_default="sys.stderr") = NULL +Dump the C stack of the current thread. +[clinic start generated code]*/ + +static PyObject * +faulthandler_dump_c_stack_py_impl(PyObject *module, PyObject *file) +/*[clinic end generated code: output=151d6c95e9f8c0f6 input=10f6b6f29b635109]*/ +{ int fd = faulthandler_get_fileno(&file); if (fd < 0) { return NULL; @@ -569,20 +583,25 @@ faulthandler_enable(void) return 0; } -static PyObject* -faulthandler_py_enable(PyObject *self, PyObject *args, PyObject *kwargs) + +/*[clinic input] +faulthandler.enable as faulthandler_py_enable + + file: object(py_default="sys.stderr") = NULL + all_threads: bool = True + c_stack: bool = True + +Enable the fault handler. +[clinic start generated code]*/ + +static PyObject * +faulthandler_py_enable_impl(PyObject *module, PyObject *file, + int all_threads, int c_stack) +/*[clinic end generated code: output=580d89b5eb62f1cb input=77277746a88b25ca]*/ { - static char *kwlist[] = {"file", "all_threads", "c_stack", NULL}; - PyObject *file = NULL; - int all_threads = 1; int fd; - int c_stack = 1; PyThreadState *tstate; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "|Opp:enable", kwlist, &file, &all_threads, &c_stack)) - return NULL; - fd = faulthandler_get_fileno(&file); if (fd < 0) return NULL; @@ -626,8 +645,16 @@ faulthandler_disable(void) Py_CLEAR(fatal_error.file); } -static PyObject* -faulthandler_disable_py(PyObject *self, PyObject *Py_UNUSED(ignored)) + +/*[clinic input] +faulthandler.disable as faulthandler_disable_py + +Disable the fault handler. +[clinic start generated code]*/ + +static PyObject * +faulthandler_disable_py_impl(PyObject *module) +/*[clinic end generated code: output=e9087a04535af3cb input=6223eac6804550af]*/ { if (!fatal_error.enabled) { Py_RETURN_FALSE; @@ -636,10 +663,18 @@ faulthandler_disable_py(PyObject *self, PyObject *Py_UNUSED(ignored)) Py_RETURN_TRUE; } -static PyObject* -faulthandler_is_enabled(PyObject *self, PyObject *Py_UNUSED(ignored)) + +/*[clinic input] +faulthandler.is_enabled -> bool + +Check if the handler is enabled. +[clinic start generated code]*/ + +static int +faulthandler_is_enabled_impl(PyObject *module) +/*[clinic end generated code: output=b9f33a3e0f881a23 input=3d5532547eb14bf9]*/ { - return PyBool_FromLong(fatal_error.enabled); + return fatal_error.enabled; } static void @@ -734,26 +769,33 @@ format_timeout(PyTime_t us) return _PyMem_Strdup(buffer); } -static PyObject* -faulthandler_dump_traceback_later(PyObject *self, - PyObject *args, PyObject *kwargs) + +/*[clinic input] +faulthandler.dump_traceback_later + + timeout as timeout_obj: object + repeat: bool = False + file: object(py_default="sys.stderr") = NULL + exit: bool = False + +Dump the traceback of all threads in timeout seconds. + +If repeat is true, the tracebacks of all threads are dumped every timeout +seconds. If exit is true, call _exit(1) which is not safe. +[clinic start generated code]*/ + +static PyObject * +faulthandler_dump_traceback_later_impl(PyObject *module, + PyObject *timeout_obj, int repeat, + PyObject *file, int exit) +/*[clinic end generated code: output=a24d80d694d25ba2 input=fd005625ecc2ba9a]*/ { - static char *kwlist[] = {"timeout", "repeat", "file", "exit", NULL}; - PyObject *timeout_obj; PyTime_t timeout, timeout_us; - int repeat = 0; - PyObject *file = NULL; int fd; - int exit = 0; PyThreadState *tstate; char *header; size_t header_len; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "O|iOi:dump_traceback_later", kwlist, - &timeout_obj, &repeat, &file, &exit)) - return NULL; - if (_PyTime_FromSecondsObject(&timeout, timeout_obj, _PyTime_ROUND_TIMEOUT) < 0) { return NULL; @@ -836,9 +878,16 @@ faulthandler_dump_traceback_later(PyObject *self, Py_RETURN_NONE; } -static PyObject* -faulthandler_cancel_dump_traceback_later_py(PyObject *self, - PyObject *Py_UNUSED(ignored)) + +/*[clinic input] +faulthandler.cancel_dump_traceback_later as faulthandler_cancel_dump_traceback_later_py + +Cancel the previous call to dump_traceback_later(). +[clinic start generated code]*/ + +static PyObject * +faulthandler_cancel_dump_traceback_later_py_impl(PyObject *module) +/*[clinic end generated code: output=2cf303015d39c926 input=51ad64b6ca8412a4]*/ { cancel_dump_traceback_later(); Py_RETURN_NONE; @@ -938,26 +987,32 @@ check_signum(int signum) return 1; } -static PyObject* -faulthandler_register_py(PyObject *self, - PyObject *args, PyObject *kwargs) + +/*[clinic input] +faulthandler.register as faulthandler_register_py + + signum: int + file: object(py_default="sys.stderr") = NULL + all_threads: bool = True + chain: bool = False + +Register a handler for the signal 'signum'. + +Dump the traceback of the current thread, or of all threads if +all_threads is True, into file. +[clinic start generated code]*/ + +static PyObject * +faulthandler_register_py_impl(PyObject *module, int signum, PyObject *file, + int all_threads, int chain) +/*[clinic end generated code: output=1f770cee150a56cd input=ae9de829e850907b]*/ { - static char *kwlist[] = {"signum", "file", "all_threads", "chain", NULL}; - int signum; - PyObject *file = NULL; - int all_threads = 1; - int chain = 0; int fd; user_signal_t *user; _Py_sighandler_t previous; PyThreadState *tstate; int err; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "i|Opp:register", kwlist, - &signum, &file, &all_threads, &chain)) - return NULL; - if (!check_signum(signum)) return NULL; @@ -1022,16 +1077,23 @@ faulthandler_unregister(user_signal_t *user, int signum) return 1; } -static PyObject* -faulthandler_unregister_py(PyObject *self, PyObject *args) + +/*[clinic input] +faulthandler.unregister as faulthandler_unregister_py + + signum: int + / + +Unregister the handler of the signal 'signum' registered by register(). +[clinic start generated code]*/ + +static PyObject * +faulthandler_unregister_py_impl(PyObject *module, int signum) +/*[clinic end generated code: output=01734423da1155ed input=c016de014495d384]*/ { - int signum; user_signal_t *user; int change; - if (!PyArg_ParseTuple(args, "i:unregister", &signum)) - return NULL; - if (!check_signum(signum)) return NULL; @@ -1097,13 +1159,20 @@ faulthandler_raise_sigsegv(void) #endif } + +/*[clinic input] +faulthandler._sigsegv + + release_gil: bool = False + / + +Raise a SIGSEGV signal. +[clinic start generated code]*/ + static PyObject * -faulthandler_sigsegv(PyObject *self, PyObject *args) +faulthandler__sigsegv_impl(PyObject *module, int release_gil) +/*[clinic end generated code: output=96e5a2f215b01b76 input=c6ad893cf2ea2b41]*/ { - int release_gil = 0; - if (!PyArg_ParseTuple(args, "|i:_sigsegv", &release_gil)) - return NULL; - if (release_gil) { Py_BEGIN_ALLOW_THREADS faulthandler_raise_sigsegv(); @@ -1120,8 +1189,16 @@ faulthandler_fatal_error_thread(void *plock) Py_FatalError("in new thread"); } + +/*[clinic input] +faulthandler._fatal_error_c_thread + +Call Py_FatalError() in a new C thread. +[clinic start generated code]*/ + static PyObject * -faulthandler_fatal_error_c_thread(PyObject *self, PyObject *args) +faulthandler__fatal_error_c_thread_impl(PyObject *module) +/*[clinic end generated code: output=101bc8aaf4a5eec1 input=fbdca6fffd639a39]*/ { long tid; PyThread_type_lock lock; @@ -1150,16 +1227,32 @@ faulthandler_fatal_error_c_thread(PyObject *self, PyObject *args) Py_RETURN_NONE; } -static PyObject* -faulthandler_sigfpe(PyObject *self, PyObject *Py_UNUSED(dummy)) + +/*[clinic input] +faulthandler._sigfpe + +Raise a SIGFPE signal. +[clinic start generated code]*/ + +static PyObject * +faulthandler__sigfpe_impl(PyObject *module) +/*[clinic end generated code: output=dec9c98100e986db input=fd608a92d4421d28]*/ { faulthandler_suppress_crash_report(); raise(SIGFPE); Py_UNREACHABLE(); } + +/*[clinic input] +faulthandler._sigabrt + +Raise a SIGABRT signal. +[clinic start generated code]*/ + static PyObject * -faulthandler_sigabrt(PyObject *self, PyObject *args) +faulthandler__sigabrt_impl(PyObject *module) +/*[clinic end generated code: output=58c1378a0c166682 input=be3e0ecefb8676b8]*/ { faulthandler_suppress_crash_report(); abort(); @@ -1186,8 +1279,16 @@ stack_overflow(uintptr_t min_sp, uintptr_t max_sp, size_t *depth) return stack_overflow(min_sp, max_sp, depth); } + +/*[clinic input] +faulthandler._stack_overflow + +Recursive call to raise a stack overflow. +[clinic start generated code]*/ + static PyObject * -faulthandler_stack_overflow(PyObject *self, PyObject *Py_UNUSED(ignored)) +faulthandler__stack_overflow_impl(PyObject *module) +/*[clinic end generated code: output=efffba4be522d8fb input=4291594a790b6c35]*/ { size_t depth, size; uintptr_t sp = (uintptr_t)&depth; @@ -1238,13 +1339,23 @@ faulthandler_traverse(PyObject *module, visitproc visit, void *arg) return 0; } + #ifdef MS_WINDOWS +/*[clinic input] +faulthandler._raise_exception + + code: unsigned_int + flags: unsigned_int = 0 + / + +Call RaiseException(code, flags). +[clinic start generated code]*/ + static PyObject * -faulthandler_raise_exception(PyObject *self, PyObject *args) +faulthandler__raise_exception_impl(PyObject *module, unsigned int code, + unsigned int flags) +/*[clinic end generated code: output=2346cf318eab10dc input=43a5ba0eb7794504]*/ { - unsigned int code, flags = 0; - if (!PyArg_ParseTuple(args, "I|I:_raise_exception", &code, &flags)) - return NULL; faulthandler_suppress_crash_report(); RaiseException(code, flags, 0, NULL); Py_RETURN_NONE; @@ -1255,69 +1366,26 @@ PyDoc_STRVAR(module_doc, "faulthandler module."); static PyMethodDef module_methods[] = { - {"enable", - _PyCFunction_CAST(faulthandler_py_enable), METH_VARARGS|METH_KEYWORDS, - PyDoc_STR("enable($module, /, file=sys.stderr, all_threads=True)\n--\n\n" - "Enable the fault handler.")}, - {"disable", faulthandler_disable_py, METH_NOARGS, - PyDoc_STR("disable($module, /)\n--\n\n" - "Disable the fault handler.")}, - {"is_enabled", faulthandler_is_enabled, METH_NOARGS, - PyDoc_STR("is_enabled($module, /)\n--\n\n" - "Check if the handler is enabled.")}, - {"dump_traceback", - _PyCFunction_CAST(faulthandler_dump_traceback_py), METH_VARARGS|METH_KEYWORDS, - PyDoc_STR("dump_traceback($module, /, file=sys.stderr, all_threads=True)\n--\n\n" - "Dump the traceback of the current thread, or of all threads " - "if all_threads is True, into file.")}, - {"dump_c_stack", - _PyCFunction_CAST(faulthandler_dump_c_stack_py), METH_VARARGS|METH_KEYWORDS, - PyDoc_STR("dump_c_stack($module, /, file=sys.stderr)\n--\n\n" - "Dump the C stack of the current thread.")}, - {"dump_traceback_later", - _PyCFunction_CAST(faulthandler_dump_traceback_later), METH_VARARGS|METH_KEYWORDS, - PyDoc_STR("dump_traceback_later($module, /, timeout, repeat=False, file=sys.stderr, exit=False)\n--\n\n" - "Dump the traceback of all threads in timeout seconds,\n" - "or each timeout seconds if repeat is True. If exit is True, " - "call _exit(1) which is not safe.")}, - {"cancel_dump_traceback_later", - faulthandler_cancel_dump_traceback_later_py, METH_NOARGS, - PyDoc_STR("cancel_dump_traceback_later($module, /)\n--\n\n" - "Cancel the previous call to dump_traceback_later().")}, + FAULTHANDLER_PY_ENABLE_METHODDEF + FAULTHANDLER_DISABLE_PY_METHODDEF + FAULTHANDLER_IS_ENABLED_METHODDEF + FAULTHANDLER_DUMP_TRACEBACK_PY_METHODDEF + FAULTHANDLER_DUMP_C_STACK_PY_METHODDEF + FAULTHANDLER_DUMP_TRACEBACK_LATER_METHODDEF + FAULTHANDLER_CANCEL_DUMP_TRACEBACK_LATER_PY_METHODDEF #ifdef FAULTHANDLER_USER - {"register", - _PyCFunction_CAST(faulthandler_register_py), METH_VARARGS|METH_KEYWORDS, - PyDoc_STR("register($module, /, signum, file=sys.stderr, all_threads=True, chain=False)\n--\n\n" - "Register a handler for the signal 'signum': dump the " - "traceback of the current thread, or of all threads if " - "all_threads is True, into file.")}, - {"unregister", - _PyCFunction_CAST(faulthandler_unregister_py), METH_VARARGS, - PyDoc_STR("unregister($module, signum, /)\n--\n\n" - "Unregister the handler of the signal " - "'signum' registered by register().")}, + FAULTHANDLER_REGISTER_PY_METHODDEF + FAULTHANDLER_UNREGISTER_PY_METHODDEF #endif - {"_sigsegv", faulthandler_sigsegv, METH_VARARGS, - PyDoc_STR("_sigsegv($module, release_gil=False, /)\n--\n\n" - "Raise a SIGSEGV signal.")}, - {"_fatal_error_c_thread", faulthandler_fatal_error_c_thread, METH_NOARGS, - PyDoc_STR("_fatal_error_c_thread($module, /)\n--\n\n" - "Call Py_FatalError() in a new C thread.")}, - {"_sigabrt", faulthandler_sigabrt, METH_NOARGS, - PyDoc_STR("_sigabrt($module, /)\n--\n\n" - "Raise a SIGABRT signal.")}, - {"_sigfpe", faulthandler_sigfpe, METH_NOARGS, - PyDoc_STR("_sigfpe($module, /)\n--\n\n" - "Raise a SIGFPE signal.")}, + FAULTHANDLER__SIGSEGV_METHODDEF + FAULTHANDLER__FATAL_ERROR_C_THREAD_METHODDEF + FAULTHANDLER__SIGABRT_METHODDEF + FAULTHANDLER__SIGFPE_METHODDEF #ifdef FAULTHANDLER_STACK_OVERFLOW - {"_stack_overflow", faulthandler_stack_overflow, METH_NOARGS, - PyDoc_STR("_stack_overflow($module, /)\n--\n\n" - "Recursive call to raise a stack overflow.")}, + FAULTHANDLER__STACK_OVERFLOW_METHODDEF #endif #ifdef MS_WINDOWS - {"_raise_exception", faulthandler_raise_exception, METH_VARARGS, - PyDoc_STR("_raise_exception($module, code, flags=0, /)\n--\n\n" - "Call RaiseException(code, flags).")}, + FAULTHANDLER__RAISE_EXCEPTION_METHODDEF #endif {NULL, NULL} /* sentinel */ }; @@ -1327,26 +1395,26 @@ PyExec_faulthandler(PyObject *module) { /* Add constants for unit tests */ #ifdef MS_WINDOWS /* RaiseException() codes (prefixed by an underscore) */ - if (PyModule_AddIntConstant(module, "_EXCEPTION_ACCESS_VIOLATION", - EXCEPTION_ACCESS_VIOLATION)) { + if (PyModule_Add(module, "_EXCEPTION_ACCESS_VIOLATION", + PyLong_FromUnsignedLong(EXCEPTION_ACCESS_VIOLATION))) { return -1; } - if (PyModule_AddIntConstant(module, "_EXCEPTION_INT_DIVIDE_BY_ZERO", - EXCEPTION_INT_DIVIDE_BY_ZERO)) { + if (PyModule_Add(module, "_EXCEPTION_INT_DIVIDE_BY_ZERO", + PyLong_FromUnsignedLong(EXCEPTION_INT_DIVIDE_BY_ZERO))) { return -1; } - if (PyModule_AddIntConstant(module, "_EXCEPTION_STACK_OVERFLOW", - EXCEPTION_STACK_OVERFLOW)) { + if (PyModule_Add(module, "_EXCEPTION_STACK_OVERFLOW", + PyLong_FromUnsignedLong(EXCEPTION_STACK_OVERFLOW))) { return -1; } /* RaiseException() flags (prefixed by an underscore) */ - if (PyModule_AddIntConstant(module, "_EXCEPTION_NONCONTINUABLE", - EXCEPTION_NONCONTINUABLE)) { + if (PyModule_Add(module, "_EXCEPTION_NONCONTINUABLE", + PyLong_FromUnsignedLong(EXCEPTION_NONCONTINUABLE))) { return -1; } - if (PyModule_AddIntConstant(module, "_EXCEPTION_NONCONTINUABLE_EXCEPTION", - EXCEPTION_NONCONTINUABLE_EXCEPTION)) { + if (PyModule_Add(module, "_EXCEPTION_NONCONTINUABLE_EXCEPTION", + PyLong_FromUnsignedLong(EXCEPTION_NONCONTINUABLE_EXCEPTION))) { return -1; } #endif