From 5d4d511d14c338d5a84153fe0aedcbd8a6d75335 Mon Sep 17 00:00:00 2001 From: Thomas Kowalski Date: Wed, 20 May 2026 15:16:27 +0200 Subject: [PATCH 1/3] fix: pickle whichmodule has a UAF on free-threading --- Modules/_pickle.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/Modules/_pickle.c b/Modules/_pickle.c index 15d95c658d6f90..7d39ed946d2e0a 100644 --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -2055,22 +2055,34 @@ whichmodule(PickleState *st, PyObject *global, PyObject *global_name, PyObject * return NULL; } if (PyDict_CheckExact(modules)) { + PyObject *found_name = NULL; + int error = 0; i = 0; + Py_BEGIN_CRITICAL_SECTION(modules); while (PyDict_Next(modules, &i, &module_name, &module)) { Py_INCREF(module_name); Py_INCREF(module); if (_checkmodule(module_name, module, global, dotted_path) == 0) { Py_DECREF(module); - Py_DECREF(modules); - return module_name; + found_name = module_name; + break; } Py_DECREF(module); Py_DECREF(module_name); if (PyErr_Occurred()) { - Py_DECREF(modules); - return NULL; + error = 1; + break; } } + Py_END_CRITICAL_SECTION(); + if (found_name != NULL) { + Py_DECREF(modules); + return found_name; + } + if (error) { + Py_DECREF(modules); + return NULL; + } } else { PyObject *iterator = PyObject_GetIter(modules); From 1fd7911d022c5e9371d0ae8a18fd788142dcf5e2 Mon Sep 17 00:00:00 2001 From: Thomas Kowalski Date: Thu, 21 May 2026 20:45:54 +0200 Subject: [PATCH 2/3] review: address comment on code order --- Modules/_pickle.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Modules/_pickle.c b/Modules/_pickle.c index 7d39ed946d2e0a..ae4daff9198db1 100644 --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -2075,14 +2075,14 @@ whichmodule(PickleState *st, PyObject *global, PyObject *global_name, PyObject * } } Py_END_CRITICAL_SECTION(); - if (found_name != NULL) { - Py_DECREF(modules); - return found_name; - } if (error) { Py_DECREF(modules); return NULL; } + if (found_name != NULL) { + Py_DECREF(modules); + return found_name; + } } else { PyObject *iterator = PyObject_GetIter(modules); From adea9625005aa3c3425d43f86c319a22e42456a8 Mon Sep 17 00:00:00 2001 From: Thomas Kowalski Date: Thu, 21 May 2026 20:48:48 +0200 Subject: [PATCH 3/3] misc: add news entry --- .../Library/2026-05-21-20-47-45.gh-issue-150157.ZvmO-bQZ.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-05-21-20-47-45.gh-issue-150157.ZvmO-bQZ.rst diff --git a/Misc/NEWS.d/next/Library/2026-05-21-20-47-45.gh-issue-150157.ZvmO-bQZ.rst b/Misc/NEWS.d/next/Library/2026-05-21-20-47-45.gh-issue-150157.ZvmO-bQZ.rst new file mode 100644 index 00000000000000..5d0db14943ff1b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-21-20-47-45.gh-issue-150157.ZvmO-bQZ.rst @@ -0,0 +1,2 @@ +Fix a heap use-after-free in :mod:`pickle`\'s ``whichmodule`` on +free-threaded builds. Patch by Thomas Kowalski.