Skip to content

Commit 74127b8

Browse files
authored
bpo-46606: Reduce stack usage of getgroups and setgroups (GH-31073)
NGROUPS_MAX was 32 before Linux 2.6.4 but 65536 since Linux 2.6.4.
1 parent 4140bcb commit 74127b8

File tree

1 file changed

+23
-56
lines changed

1 file changed

+23
-56
lines changed

Modules/posixmodule.c

+23-56
Original file line numberDiff line numberDiff line change
@@ -7623,21 +7623,15 @@ static PyObject *
76237623
os_getgroups_impl(PyObject *module)
76247624
/*[clinic end generated code: output=42b0c17758561b56 input=d3f109412e6a155c]*/
76257625
{
7626-
PyObject *result = NULL;
7627-
gid_t grouplist[MAX_GROUPS];
7628-
76297626
/* On MacOSX getgroups(2) can return more than MAX_GROUPS results
76307627
* This is a helper variable to store the intermediate result when
76317628
* that happens.
76327629
*
7633-
* To keep the code readable the OSX behaviour is unconditional,
7634-
* according to the POSIX spec this should be safe on all unix-y
7635-
* systems.
7630+
* See bpo-7900.
76367631
*/
7637-
gid_t* alt_grouplist = grouplist;
7632+
gid_t *grouplist = NULL;
76387633
int n;
76397634

7640-
#ifdef __APPLE__
76417635
/* Issue #17557: As of OS X 10.8, getgroups(2) no longer raises EINVAL if
76427636
* there are more groups than can fit in grouplist. Therefore, on OS X
76437637
* always first call getgroups with length 0 to get the actual number
@@ -7646,56 +7640,25 @@ os_getgroups_impl(PyObject *module)
76467640
n = getgroups(0, NULL);
76477641
if (n < 0) {
76487642
return posix_error();
7649-
} else if (n <= MAX_GROUPS) {
7650-
/* groups will fit in existing array */
7651-
alt_grouplist = grouplist;
76527643
} else {
7653-
alt_grouplist = PyMem_New(gid_t, n);
7654-
if (alt_grouplist == NULL) {
7644+
n++; // Avoid malloc(0)
7645+
grouplist = PyMem_New(gid_t, n+1);
7646+
if (grouplist == NULL) {
76557647
return PyErr_NoMemory();
76567648
}
76577649
}
76587650

7659-
n = getgroups(n, alt_grouplist);
7651+
n = getgroups(n, grouplist);
76607652
if (n == -1) {
7661-
if (alt_grouplist != grouplist) {
7662-
PyMem_Free(alt_grouplist);
7663-
}
7653+
PyMem_Free(grouplist);
76647654
return posix_error();
76657655
}
7666-
#else
7667-
n = getgroups(MAX_GROUPS, grouplist);
7668-
if (n < 0) {
7669-
if (errno == EINVAL) {
7670-
n = getgroups(0, NULL);
7671-
if (n == -1) {
7672-
return posix_error();
7673-
}
7674-
if (n == 0) {
7675-
/* Avoid malloc(0) */
7676-
alt_grouplist = grouplist;
7677-
} else {
7678-
alt_grouplist = PyMem_New(gid_t, n);
7679-
if (alt_grouplist == NULL) {
7680-
return PyErr_NoMemory();
7681-
}
7682-
n = getgroups(n, alt_grouplist);
7683-
if (n == -1) {
7684-
PyMem_Free(alt_grouplist);
7685-
return posix_error();
7686-
}
7687-
}
7688-
} else {
7689-
return posix_error();
7690-
}
7691-
}
7692-
#endif
76937656

7694-
result = PyList_New(n);
7657+
PyObject *result = PyList_New(n);
76957658
if (result != NULL) {
76967659
int i;
76977660
for (i = 0; i < n; ++i) {
7698-
PyObject *o = _PyLong_FromGid(alt_grouplist[i]);
7661+
PyObject *o = _PyLong_FromGid(grouplist[i]);
76997662
if (o == NULL) {
77007663
Py_DECREF(result);
77017664
result = NULL;
@@ -7705,9 +7668,7 @@ os_getgroups_impl(PyObject *module)
77057668
}
77067669
}
77077670

7708-
if (alt_grouplist != grouplist) {
7709-
PyMem_Free(alt_grouplist);
7710-
}
7671+
PyMem_Free(grouplist);
77117672

77127673
return result;
77137674
}
@@ -8212,42 +8173,48 @@ static PyObject *
82128173
os_setgroups(PyObject *module, PyObject *groups)
82138174
/*[clinic end generated code: output=3fcb32aad58c5ecd input=fa742ca3daf85a7e]*/
82148175
{
8215-
Py_ssize_t i, len;
8216-
gid_t grouplist[MAX_GROUPS];
8217-
82188176
if (!PySequence_Check(groups)) {
82198177
PyErr_SetString(PyExc_TypeError, "setgroups argument must be a sequence");
82208178
return NULL;
82218179
}
8222-
len = PySequence_Size(groups);
8180+
Py_ssize_t len = PySequence_Size(groups);
82238181
if (len < 0) {
82248182
return NULL;
82258183
}
82268184
if (len > MAX_GROUPS) {
82278185
PyErr_SetString(PyExc_ValueError, "too many groups");
82288186
return NULL;
82298187
}
8230-
for(i = 0; i < len; i++) {
8188+
8189+
gid_t *grouplist = PyMem_New(gid_t, len+1); // Avoid malloc(0)
8190+
for (Py_ssize_t i = 0; i < len; i++) {
82318191
PyObject *elem;
82328192
elem = PySequence_GetItem(groups, i);
8233-
if (!elem)
8193+
if (!elem) {
8194+
PyMem_Free(grouplist);
82348195
return NULL;
8196+
}
82358197
if (!PyLong_Check(elem)) {
82368198
PyErr_SetString(PyExc_TypeError,
82378199
"groups must be integers");
82388200
Py_DECREF(elem);
8201+
PyMem_Free(grouplist);
82398202
return NULL;
82408203
} else {
82418204
if (!_Py_Gid_Converter(elem, &grouplist[i])) {
82428205
Py_DECREF(elem);
8206+
PyMem_Free(grouplist);
82438207
return NULL;
82448208
}
82458209
}
82468210
Py_DECREF(elem);
82478211
}
82488212

8249-
if (setgroups(len, grouplist) < 0)
8213+
if (setgroups(len, grouplist) < 0) {
8214+
PyMem_Free(grouplist);
82508215
return posix_error();
8216+
}
8217+
PyMem_Free(grouplist);
82518218
Py_RETURN_NONE;
82528219
}
82538220
#endif /* HAVE_SETGROUPS */

0 commit comments

Comments
 (0)