From a0b29678c87a6a37c7e8a0df76788c71a3fbe7af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Mon, 12 May 2025 17:57:24 +0200 Subject: [PATCH 1/3] fix UBSan failures in `faulthandler.c` - reading from NULL is no more an undefined behavior for C11 - instead of using 1/0 arithmetic, we explicitly raise SIGFPE --- Modules/faulthandler.c | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c index d49ce794d88674..c52a0ff43788b0 100644 --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -1069,8 +1069,8 @@ faulthandler_suppress_crash_report(void) #endif } -static PyObject* _Py_NO_SANITIZE_UNDEFINED -faulthandler_read_null(PyObject *self, PyObject *args) +static PyObject* +faulthandler_read_null(PyObject *self, PyObject *Py_UNUSED(args)) { volatile int *x; volatile int y; @@ -1079,7 +1079,6 @@ faulthandler_read_null(PyObject *self, PyObject *args) x = NULL; y = *x; return PyLong_FromLong(y); - } static void @@ -1158,23 +1157,13 @@ faulthandler_fatal_error_c_thread(PyObject *self, PyObject *args) Py_RETURN_NONE; } -static PyObject* _Py_NO_SANITIZE_UNDEFINED +static PyObject* faulthandler_sigfpe(PyObject *self, PyObject *Py_UNUSED(dummy)) { faulthandler_suppress_crash_report(); - - /* Do an integer division by zero: raise a SIGFPE on Intel CPU, but not on - PowerPC. Use volatile to disable compile-time optimizations. */ - volatile int x = 1, y = 0, z; - z = x / y; - - /* If the division by zero didn't raise a SIGFPE (e.g. on PowerPC), - raise it manually. */ + /* raise SIGFPE manually to prevent crafted undefined behaviors */ raise(SIGFPE); - - /* This line is never reached, but we pretend to make something with z - to silence a compiler warning. */ - return PyLong_FromLong(z); + Py_UNREACHABLE(); } static PyObject * From 130da649a195ea497b53df423d2a1a24329879e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Thu, 15 May 2025 17:30:04 +0200 Subject: [PATCH 2/3] Update Modules/faulthandler.c --- Modules/faulthandler.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c index c52a0ff43788b0..b6c4c745a41602 100644 --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -1161,7 +1161,6 @@ static PyObject* faulthandler_sigfpe(PyObject *self, PyObject *Py_UNUSED(dummy)) { faulthandler_suppress_crash_report(); - /* raise SIGFPE manually to prevent crafted undefined behaviors */ raise(SIGFPE); Py_UNREACHABLE(); } From 05d7ff1c1d791c5f77f235395121275750d9ebc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Fri, 16 May 2025 10:40:51 +0200 Subject: [PATCH 3/3] remove `faulthandler._read_null()` Reading from NULL is an undefined behavior and `faulthandler` should not check for low-level C about undefined behaviors. --- Lib/test/test_faulthandler.py | 23 ----------------------- Modules/faulthandler.c | 15 --------------- 2 files changed, 38 deletions(-) diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py index 371c63adce9412..2fb963f52e5138 100644 --- a/Lib/test/test_faulthandler.py +++ b/Lib/test/test_faulthandler.py @@ -166,29 +166,6 @@ def check_windows_exception(self, code, line_number, name_regex, **kw): fatal_error = 'Windows fatal exception: %s' % name_regex self.check_error(code, line_number, fatal_error, **kw) - @unittest.skipIf(sys.platform.startswith('aix'), - "the first page of memory is a mapped read-only on AIX") - def test_read_null(self): - if not MS_WINDOWS: - self.check_fatal_error(""" - import faulthandler - faulthandler.enable() - faulthandler._read_null() - """, - 3, - # Issue #12700: Read NULL raises SIGILL on Mac OS X Lion - '(?:Segmentation fault' - '|Bus error' - '|Illegal instruction)') - else: - self.check_windows_exception(""" - import faulthandler - faulthandler.enable() - faulthandler._read_null() - """, - 3, - 'access violation') - @skip_segfault_on_android def test_sigsegv(self): self.check_fatal_error(""" diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c index b6c4c745a41602..c94f4f66366170 100644 --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -1069,17 +1069,6 @@ faulthandler_suppress_crash_report(void) #endif } -static PyObject* -faulthandler_read_null(PyObject *self, PyObject *Py_UNUSED(args)) -{ - volatile int *x; - volatile int y; - - faulthandler_suppress_crash_report(); - x = NULL; - y = *x; - return PyLong_FromLong(y); -} static void faulthandler_raise_sigsegv(void) @@ -1304,10 +1293,6 @@ static PyMethodDef module_methods[] = { "Unregister the handler of the signal " "'signum' registered by register().")}, #endif - {"_read_null", faulthandler_read_null, METH_NOARGS, - PyDoc_STR("_read_null($module, /)\n--\n\n" - "Read from NULL, raise " - "a SIGSEGV or SIGBUS signal depending on the platform.")}, {"_sigsegv", faulthandler_sigsegv, METH_VARARGS, PyDoc_STR("_sigsegv($module, release_gil=False, /)\n--\n\n" "Raise a SIGSEGV signal.")},