Skip to content

Commit af6fd1f

Browse files
bpo-40014: Fix os.getgrouplist() (GH-19126)
Fix os.getgrouplist(): if getgrouplist() function fails because the group list is too small, retry with a larger group list. On failure, the glibc implementation of getgrouplist() sets ngroups to the total number of groups. For other implementations, double the group list size. (cherry picked from commit f5c7cab) Co-authored-by: Victor Stinner <[email protected]>
1 parent 8cd48b6 commit af6fd1f

File tree

2 files changed

+29
-25
lines changed

2 files changed

+29
-25
lines changed
Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1-
Fix ``os.getgrouplist()``: on macOS, the ``getgrouplist()`` function returns a
2-
non-zero value without setting ``errno`` if the group list is too small. Double
3-
the list size and call it again in this case.
1+
Fix ``os.getgrouplist()``: if ``getgrouplist()`` function fails because the
2+
group list is too small, retry with a larger group list. On failure, the glibc
3+
implementation of ``getgrouplist()`` sets ``ngroups`` to the total number of
4+
groups. For other implementations, double the group list size.

Modules/posixmodule.c

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6906,37 +6906,40 @@ posix_getgrouplist(PyObject *self, PyObject *args)
69066906
return NULL;
69076907
#endif
69086908

6909+
while (1) {
69096910
#ifdef __APPLE__
6910-
groups = PyMem_New(int, ngroups);
6911+
groups = PyMem_New(int, ngroups);
69116912
#else
6912-
groups = PyMem_New(gid_t, ngroups);
6913+
groups = PyMem_New(gid_t, ngroups);
69136914
#endif
6914-
if (groups == NULL)
6915-
return PyErr_NoMemory();
6915+
if (groups == NULL) {
6916+
return PyErr_NoMemory();
6917+
}
69166918

6917-
#ifdef __APPLE__
6918-
while (getgrouplist(user, basegid, groups, &ngroups)) {
6919-
/* On macOS, getgrouplist() returns a non-zero value without setting
6920-
errno if the group list is too small. Double the list size and call
6921-
it again in this case. */
6919+
int old_ngroups = ngroups;
6920+
if (getgrouplist(user, basegid, groups, &ngroups) != -1) {
6921+
/* Success */
6922+
break;
6923+
}
6924+
6925+
/* getgrouplist() fails if the group list is too small */
69226926
PyMem_Free(groups);
69236927

6924-
if (ngroups > INT_MAX / 2) {
6925-
return PyErr_NoMemory();
6928+
if (ngroups > old_ngroups) {
6929+
/* If the group list is too small, the glibc implementation of
6930+
getgrouplist() sets ngroups to the total number of groups and
6931+
returns -1. */
69266932
}
6927-
ngroups *= 2;
6928-
6929-
groups = PyMem_New(int, ngroups);
6930-
if (groups == NULL) {
6931-
return PyErr_NoMemory();
6933+
else {
6934+
/* Double the group list size */
6935+
if (ngroups > INT_MAX / 2) {
6936+
return PyErr_NoMemory();
6937+
}
6938+
ngroups *= 2;
69326939
}
6940+
6941+
/* Retry getgrouplist() with a larger group list */
69336942
}
6934-
#else
6935-
if (getgrouplist(user, basegid, groups, &ngroups) == -1) {
6936-
PyMem_Del(groups);
6937-
return posix_error();
6938-
}
6939-
#endif
69406943

69416944
#ifdef _Py_MEMORY_SANITIZER
69426945
/* Clang memory sanitizer libc intercepts don't know getgrouplist. */

0 commit comments

Comments
 (0)