diff --git a/Misc/NEWS.d/next/Library/2024-11-06-17-24-59.gh-issue-126316._I1Ikc.rst b/Misc/NEWS.d/next/Library/2024-11-06-17-24-59.gh-issue-126316._I1Ikc.rst new file mode 100644 index 00000000000000..0657838fd3cacb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-11-06-17-24-59.gh-issue-126316._I1Ikc.rst @@ -0,0 +1,3 @@ +:mod:`grp`: :func:`grp.getgrall` now uses ``getgrent_r()``, if the function +is available, to make :func:`grp.getgrall` thread-safe. Patch by Victor +Stinner. diff --git a/Modules/grpmodule.c b/Modules/grpmodule.c index f7d3e12f347ec2..cd85c58aef0f83 100644 --- a/Modules/grpmodule.c +++ b/Modules/grpmodule.c @@ -281,22 +281,46 @@ static PyObject * grp_getgrall_impl(PyObject *module) /*[clinic end generated code: output=585dad35e2e763d7 input=d7df76c825c367df]*/ { - PyObject *d; - struct group *p; - - if ((d = PyList_New(0)) == NULL) + PyObject *d = PyList_New(0); + if (d == NULL) { return NULL; + } + setgrent(); - while ((p = getgrent()) != NULL) { - PyObject *v = mkgrent(module, p); + while (1) { +#ifdef HAVE_GETGRENT_R + struct group grp; + struct group *grpp; + char buf[4096]; + int err = getgrent_r(&grp, buf, sizeof(buf), &grpp); + if (err) { + if (err != ENOENT) { + errno = err; + PyErr_SetFromErrno(PyExc_OSError); + goto error; + } + break; + } +#else + struct group *grpp = getgrent(); + if (grpp == NULL) { + break; + } +#endif + + PyObject *v = mkgrent(module, grpp); if (v == NULL || PyList_Append(d, v) != 0) { Py_XDECREF(v); - Py_DECREF(d); - endgrent(); - return NULL; + goto error; } Py_DECREF(v); } + goto done; + +error: + Py_CLEAR(d); + +done: endgrent(); return d; } diff --git a/configure b/configure index e529527214da29..1a4aff30f8bf12 100755 --- a/configure +++ b/configure @@ -18519,6 +18519,12 @@ if test "x$ac_cv_func_getgrent" = xyes then : printf "%s\n" "#define HAVE_GETGRENT 1" >>confdefs.h +fi +ac_fn_c_check_func "$LINENO" "getgrent_r" "ac_cv_func_getgrent_r" +if test "x$ac_cv_func_getgrent_r" = xyes +then : + printf "%s\n" "#define HAVE_GETGRENT_R 1" >>confdefs.h + fi ac_fn_c_check_func "$LINENO" "getgrgid" "ac_cv_func_getgrgid" if test "x$ac_cv_func_getgrgid" = xyes diff --git a/configure.ac b/configure.ac index bc67a0596ac2b4..8b44926650d706 100644 --- a/configure.ac +++ b/configure.ac @@ -5181,7 +5181,7 @@ AC_CHECK_FUNCS([ \ copy_file_range ctermid dup dup3 execv explicit_bzero explicit_memset \ faccessat fchmod fchmodat fchown fchownat fdopendir fdwalk fexecve \ fork fork1 fpathconf fstatat ftime ftruncate futimens futimes futimesat \ - gai_strerror getegid geteuid getgid getgrent getgrgid getgrgid_r \ + gai_strerror getegid geteuid getgid getgrent getgrent_r getgrgid getgrgid_r \ getgrnam_r getgrouplist gethostname getitimer getloadavg getlogin \ getpeername getpgid getpid getppid getpriority _getpty \ getpwent getpwnam_r getpwuid getpwuid_r getresgid getresuid getrusage getsid getspent \ diff --git a/pyconfig.h.in b/pyconfig.h.in index 924d86627b0e9b..6bdcc3d8e95bd2 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -482,6 +482,9 @@ /* Define to 1 if you have the `getgrent' function. */ #undef HAVE_GETGRENT +/* Define to 1 if you have the `getgrent_r' function. */ +#undef HAVE_GETGRENT_R + /* Define to 1 if you have the `getgrgid' function. */ #undef HAVE_GETGRGID