From 458e33018a2f4f4b3d9a2c8f6e70dcce31f34005 Mon Sep 17 00:00:00 2001 From: Duane Griffin Date: Thu, 22 May 2025 22:22:02 +1200 Subject: [PATCH] gh-127081: lock non-re-entrant `*pwent` calls in free-threading (#132748) --- ...-04-21-00-58-04.gh-issue-127081.3DCl92.rst | 2 ++ Modules/pwdmodule.c | 25 +++++++++++++++---- 2 files changed, 22 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2025-04-21-00-58-04.gh-issue-127081.3DCl92.rst diff --git a/Misc/NEWS.d/next/Library/2025-04-21-00-58-04.gh-issue-127081.3DCl92.rst b/Misc/NEWS.d/next/Library/2025-04-21-00-58-04.gh-issue-127081.3DCl92.rst new file mode 100644 index 00000000000..a99669a1bc0 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-04-21-00-58-04.gh-issue-127081.3DCl92.rst @@ -0,0 +1,2 @@ +Fix libc thread safety issues with :mod:`pwd` by locking access to +``getpwall``. diff --git a/Modules/pwdmodule.c b/Modules/pwdmodule.c index 2240e2078b2..c5a8cead19a 100644 --- a/Modules/pwdmodule.c +++ b/Modules/pwdmodule.c @@ -301,18 +301,33 @@ pwd_getpwall_impl(PyObject *module) struct passwd *p; if ((d = PyList_New(0)) == NULL) return NULL; + +#ifdef Py_GIL_DISABLED + static PyMutex getpwall_mutex = {0}; + PyMutex_Lock(&getpwall_mutex); +#endif + int failure = 0; + PyObject *v = NULL; setpwent(); while ((p = getpwent()) != NULL) { - PyObject *v = mkpwent(module, p); + v = mkpwent(module, p); if (v == NULL || PyList_Append(d, v) != 0) { - Py_XDECREF(v); - Py_DECREF(d); - endpwent(); - return NULL; + /* NOTE: cannot dec-ref here, while holding the mutex. */ + failure = 1; + goto done; } Py_DECREF(v); } + +done: endpwent(); +#ifdef Py_GIL_DISABLED + PyMutex_Unlock(&getpwall_mutex); +#endif + if (failure) { + Py_XDECREF(v); + Py_CLEAR(d); + } return d; } #endif