From 7582e4847a94d894cd11ad3d3a095ec43c10296f Mon Sep 17 00:00:00 2001 From: Stan Ulbrych Date: Thu, 22 Oct 2026 07:52:22 +0100 Subject: [PATCH 1/2] Fix unchecked NULL returns in several C modules --- Modules/_elementtree.c | 3 +++ Modules/_io/winconsoleio.c | 4 ++++ Modules/_testinternalcapi.c | 3 +++ Modules/_xxtestfuzz/fuzzer.c | 4 ++++ Modules/getpath.c | 6 +++++- Modules/posixmodule.c | 3 ++- Modules/readline.c | 15 +++++++++++---- Modules/socketmodule.c | 3 +++ Python/ceval.c | 10 ++++++++++ Python/crossinterp.c | 5 +++++ 10 files changed, 50 insertions(+), 6 deletions(-) diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c index cee564c2c1c1f0f..f8f661a73418912 100644 --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -4285,6 +4285,9 @@ _elementtree_XMLParser__setevents_impl(XMLParserObject *self, if (events_to_report == Py_None) { /* default is "end" only */ self->end_event_obj = PyUnicode_FromString("end"); + if (self->end_event_obj == NULL) { + return NULL; + } Py_RETURN_NONE; } diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c index e3e57d8df455530..3da4f1df1708a78 100644 --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -962,6 +962,10 @@ _io__WindowsConsoleIO_readall_impl(winconsoleio *self) bytes_size += _buflen(self); bytes = PyBytes_FromStringAndSize(NULL, bytes_size); + if (bytes == NULL) { + PyMem_Free(buf); + return NULL; + } rn = _copyfrombuf(self, PyBytes_AS_STRING(bytes), bytes_size); if (len) { diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 479297a996c2502..e5c8e24a9dbbfbc 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -2625,6 +2625,9 @@ get_crossinterp_data(PyObject *self, PyObject *args, PyObject *kwargs) } else { mode = PyUnicode_AsUTF8(modeobj); + if (mode == NULL) { + return NULL; + } if (strlen(mode) == 0) { mode = "xidata"; } diff --git a/Modules/_xxtestfuzz/fuzzer.c b/Modules/_xxtestfuzz/fuzzer.c index 02afb01d3731fbc..8c2d0e93cd72d44 100644 --- a/Modules/_xxtestfuzz/fuzzer.c +++ b/Modules/_xxtestfuzz/fuzzer.c @@ -325,6 +325,10 @@ static int fuzz_sre_match(const char* data, size_t size) { PyObject* pattern = compiled_patterns[idx]; PyObject* match_callable = PyObject_GetAttrString(pattern, "match"); + if (match_callable == NULL) { + Py_DECREF(to_match); + return 0; + } PyObject* matches = PyObject_CallOneArg(match_callable, to_match); diff --git a/Modules/getpath.c b/Modules/getpath.c index 10964af12819d2a..d1b0cf6bf902b96 100644 --- a/Modules/getpath.c +++ b/Modules/getpath.c @@ -632,7 +632,11 @@ getpath_warn(PyObject *Py_UNUSED(self), PyObject *args) if (!PyArg_ParseTuple(args, "U", &msgobj)) { return NULL; } - fprintf(stderr, "%s\n", PyUnicode_AsUTF8(msgobj)); + const char *msg = PyUnicode_AsUTF8(msgobj); + if (msg == NULL) { + return NULL; + } + fprintf(stderr, "%s\n", msg); Py_RETURN_NONE; } diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 301afe1fa27be68..a619de79ca73b26 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -5675,8 +5675,9 @@ os__getvolumepathname_impl(PyObject *module, path_t *path) goto exit; } result = PyUnicode_FromWideChar(mountpath, -1); - if (PyBytes_Check(path->object)) + if (result != NULL && PyBytes_Check(path->object)) { Py_SETREF(result, PyUnicode_EncodeFSDefault(result)); + } exit: PyMem_Free(mountpath); diff --git a/Modules/readline.c b/Modules/readline.c index 649604055ed4b34..f76fabd7a610596 100644 --- a/Modules/readline.c +++ b/Modules/readline.c @@ -1508,10 +1508,17 @@ flex_complete(const char *text, int start, int end) done: if (state) { - Py_XDECREF(state->begidx); - Py_XDECREF(state->endidx); - state->begidx = PyLong_FromLong((long) start); - state->endidx = PyLong_FromLong((long) end); + PyObject *begidx = PyLong_FromLong((long) start); + PyObject *endidx = PyLong_FromLong((long) end); + if (begidx == NULL || endidx == NULL) { + Py_XDECREF(begidx); + Py_XDECREF(endidx); + PyErr_Clear(); + PyGILState_Release(gilstate); + return NULL; + } + Py_XSETREF(state->begidx, begidx); + Py_XSETREF(state->endidx, endidx); } result = completion_matches((char *)text, *on_completion); PyGILState_Release(gilstate); diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 21a00a31201d9fb..ccd8815125c1bf4 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -1786,6 +1786,9 @@ makesockaddr(SOCKET_T sockfd, struct sockaddr *addr, size_t addrlen, int proto) PyObject *vmId = PyUnicode_FromWideChar(guidStr, -1); res = RpcStringFreeW(&guidStr); assert(res == RPC_S_OK); + if (vmId == NULL) { + return 0; + } res = UuidToStringW(&a->ServiceId, &guidStr); if (res != RPC_S_OK) { diff --git a/Python/ceval.c b/Python/ceval.c index 2b8c425789c0398..ab5f3d587b111c3 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1225,8 +1225,13 @@ dtrace_function_entry(_PyInterpreterFrame *frame) int lineno; PyCodeObject *code = _PyFrame_GetCode(frame); + PyObject *exc = PyErr_GetRaisedException(); filename = PyUnicode_AsUTF8(code->co_filename); funcname = PyUnicode_AsUTF8(code->co_name); + PyErr_SetRaisedException(exc); + if (filename == NULL || funcname == NULL) { + return; + } lineno = PyUnstable_InterpreterFrame_GetLine(frame); PyDTrace_FUNCTION_ENTRY(filename, funcname, lineno); @@ -1240,8 +1245,13 @@ dtrace_function_return(_PyInterpreterFrame *frame) int lineno; PyCodeObject *code = _PyFrame_GetCode(frame); + PyObject *exc = PyErr_GetRaisedException(); filename = PyUnicode_AsUTF8(code->co_filename); funcname = PyUnicode_AsUTF8(code->co_name); + PyErr_SetRaisedException(exc); + if (filename == NULL || funcname == NULL) { + return; + } lineno = PyUnstable_InterpreterFrame_GetLine(frame); PyDTrace_FUNCTION_RETURN(filename, funcname, lineno); diff --git a/Python/crossinterp.c b/Python/crossinterp.c index ed77c1be646e275..b8dd5f11c2a44c7 100644 --- a/Python/crossinterp.c +++ b/Python/crossinterp.c @@ -664,6 +664,11 @@ check_missing___main___attr(PyObject *exc) } } const char *err = PyUnicode_AsUTF8(msgobj); + if (err == NULL) { + PyErr_Clear(); + Py_DECREF(msgobj); + return 0; + } // Check if it's a missing __main__ attr. int cmp = strncmp(err, "module '__main__' has no attribute '", 36); From 13ce797e0816cf573d126cd62f68b801deb1c3a9 Mon Sep 17 00:00:00 2001 From: Stan Ulbrych Date: Thu, 22 Oct 2026 16:20:45 +0100 Subject: [PATCH 2/2] Address Jelle's review --- Modules/readline.c | 4 +++- Python/ceval.c | 14 ++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/Modules/readline.c b/Modules/readline.c index f76fabd7a610596..643b1fcb040290d 100644 --- a/Modules/readline.c +++ b/Modules/readline.c @@ -1513,7 +1513,9 @@ flex_complete(const char *text, int start, int end) if (begidx == NULL || endidx == NULL) { Py_XDECREF(begidx); Py_XDECREF(endidx); - PyErr_Clear(); + PyErr_FormatUnraisable("Exception ignored while preparing " + "readline completion"); + rl_attempted_completion_over = 1; PyGILState_Release(gilstate); return NULL; } diff --git a/Python/ceval.c b/Python/ceval.c index ab5f3d587b111c3..223106065c603c4 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1229,8 +1229,11 @@ dtrace_function_entry(_PyInterpreterFrame *frame) filename = PyUnicode_AsUTF8(code->co_filename); funcname = PyUnicode_AsUTF8(code->co_name); PyErr_SetRaisedException(exc); - if (filename == NULL || funcname == NULL) { - return; + if (filename == NULL) { + filename = ""; + } + if (funcname == NULL) { + funcname = ""; } lineno = PyUnstable_InterpreterFrame_GetLine(frame); @@ -1249,8 +1252,11 @@ dtrace_function_return(_PyInterpreterFrame *frame) filename = PyUnicode_AsUTF8(code->co_filename); funcname = PyUnicode_AsUTF8(code->co_name); PyErr_SetRaisedException(exc); - if (filename == NULL || funcname == NULL) { - return; + if (filename == NULL) { + filename = ""; + } + if (funcname == NULL) { + funcname = ""; } lineno = PyUnstable_InterpreterFrame_GetLine(frame);