]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-40014: Fix os.getgrouplist() (GH-19126)
authorVictor Stinner <vstinner@python.org>
Tue, 24 Mar 2020 17:22:10 +0000 (18:22 +0100)
committerGitHub <noreply@github.com>
Tue, 24 Mar 2020 17:22:10 +0000 (18:22 +0100)
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.

Misc/NEWS.d/next/Library/2020-03-23-17-52-00.bpo-40014.Ya70VG.rst
Modules/posixmodule.c

index 58f14fa9a72d077f1cbe0dbe528c4fd5cc34296b..e9b36c211324b5f125e7fc90ff4f24ff5b80bd43 100644 (file)
@@ -1,3 +1,4 @@
-Fix ``os.getgrouplist()``: on macOS, the ``getgrouplist()`` function returns a
-non-zero value without setting ``errno`` if the group list is too small. Double
-the list size and call it again in this case.
+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.
index e489b74ec70f50f4f38ea24bce965071000010c0..9ab136b25255d26ba9cfa0b53fa36fb004c89b68 100644 (file)
@@ -6991,37 +6991,40 @@ posix_getgrouplist(PyObject *self, PyObject *args)
         return NULL;
 #endif
 
+    while (1) {
 #ifdef __APPLE__
-    groups = PyMem_New(int, ngroups);
+        groups = PyMem_New(int, ngroups);
 #else
-    groups = PyMem_New(gid_t, ngroups);
+        groups = PyMem_New(gid_t, ngroups);
 #endif
-    if (groups == NULL)
-        return PyErr_NoMemory();
+        if (groups == NULL) {
+            return PyErr_NoMemory();
+        }
 
-#ifdef __APPLE__
-    while (getgrouplist(user, basegid, groups, &ngroups)) {
-        /* On macOS, getgrouplist() returns a non-zero value without setting
-           errno if the group list is too small. Double the list size and call
-           it again in this case. */
+        int old_ngroups = ngroups;
+        if (getgrouplist(user, basegid, groups, &ngroups) != -1) {
+            /* Success */
+            break;
+        }
+
+        /* getgrouplist() fails if the group list is too small */
         PyMem_Free(groups);
 
-        if (ngroups > INT_MAX / 2) {
-            return PyErr_NoMemory();
+        if (ngroups > old_ngroups) {
+            /* If the group list is too small, the glibc implementation of
+               getgrouplist() sets ngroups to the total number of groups and
+               returns -1. */
         }
-        ngroups *= 2;
-
-        groups = PyMem_New(int, ngroups);
-        if (groups == NULL) {
-            return PyErr_NoMemory();
+        else {
+            /* Double the group list size */
+            if (ngroups > INT_MAX / 2) {
+                return PyErr_NoMemory();
+            }
+            ngroups *= 2;
         }
+
+        /* Retry getgrouplist() with a larger group list */
     }
-#else
-    if (getgrouplist(user, basegid, groups, &ngroups) == -1) {
-        PyMem_Del(groups);
-        return posix_error();
-    }
-#endif
 
 #ifdef _Py_MEMORY_SANITIZER
     /* Clang memory sanitizer libc intercepts don't know getgrouplist. */