Skip to content

Commit 5753fc6

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 d1c0989 commit 5753fc6

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
@@ -6170,37 +6170,40 @@ posix_getgrouplist(PyObject *self, PyObject *args)
61706170
return NULL;
61716171
#endif
61726172

6173+
while (1) {
61736174
#ifdef __APPLE__
6174-
groups = PyMem_New(int, ngroups);
6175+
groups = PyMem_New(int, ngroups);
61756176
#else
6176-
groups = PyMem_New(gid_t, ngroups);
6177+
groups = PyMem_New(gid_t, ngroups);
61776178
#endif
6178-
if (groups == NULL)
6179-
return PyErr_NoMemory();
6179+
if (groups == NULL) {
6180+
return PyErr_NoMemory();
6181+
}
61806182

6181-
#ifdef __APPLE__
6182-
while (getgrouplist(user, basegid, groups, &ngroups)) {
6183-
/* On macOS, getgrouplist() returns a non-zero value without setting
6184-
errno if the group list is too small. Double the list size and call
6185-
it again in this case. */
6183+
int old_ngroups = ngroups;
6184+
if (getgrouplist(user, basegid, groups, &ngroups) != -1) {
6185+
/* Success */
6186+
break;
6187+
}
6188+
6189+
/* getgrouplist() fails if the group list is too small */
61866190
PyMem_Free(groups);
61876191

6188-
if (ngroups > INT_MAX / 2) {
6189-
return PyErr_NoMemory();
6192+
if (ngroups > old_ngroups) {
6193+
/* If the group list is too small, the glibc implementation of
6194+
getgrouplist() sets ngroups to the total number of groups and
6195+
returns -1. */
61906196
}
6191-
ngroups *= 2;
6192-
6193-
groups = PyMem_New(int, ngroups);
6194-
if (groups == NULL) {
6195-
return PyErr_NoMemory();
6197+
else {
6198+
/* Double the group list size */
6199+
if (ngroups > INT_MAX / 2) {
6200+
return PyErr_NoMemory();
6201+
}
6202+
ngroups *= 2;
61966203
}
6204+
6205+
/* Retry getgrouplist() with a larger group list */
61976206
}
6198-
#else
6199-
if (getgrouplist(user, basegid, groups, &ngroups) == -1) {
6200-
PyMem_Del(groups);
6201-
return posix_error();
6202-
}
6203-
#endif
62046207

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

0 commit comments

Comments
 (0)