Skip to content

Commit d30a139

Browse files
committed
Defer dec-refs on created entries until outside mutex to avoid possibility of
re-entrancy.
1 parent 78c9cde commit d30a139

File tree

1 file changed

+19
-4
lines changed

1 file changed

+19
-4
lines changed

Modules/pwdmodule.c

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include "Python.h"
1111
#include "posixmodule.h"
12+
#include "listobject.h" // PyList_Size/PyList_GetItem
1213

1314
#include <errno.h> // ERANGE
1415
#include <pwd.h> // getpwuid()
@@ -306,23 +307,37 @@ pwd_getpwall_impl(PyObject *module)
306307
static PyMutex getpwall_mutex = {0};
307308
PyMutex_Lock(&getpwall_mutex);
308309
#endif
310+
int failure = 0;
311+
PyObject *orphan = NULL;
309312
setpwent();
310-
311313
while ((p = getpwent()) != NULL) {
314+
/* NOTE: Ref counts are not decremented here, as we cannot allow
315+
* re-entrancy while holding the mutex. */
312316
PyObject *v = mkpwent(module, p);
313317
if (v == NULL || PyList_Append(d, v) != 0) {
314-
Py_XDECREF(v);
315-
Py_CLEAR(d);
318+
orphan = v;
319+
failure = 1;
316320
goto done;
317321
}
318-
Py_DECREF(v);
319322
}
320323

321324
done:
322325
endpwent();
323326
#ifdef Py_GIL_DISABLED
324327
PyMutex_Unlock(&getpwall_mutex);
325328
#endif
329+
/* Deferred decref on entries created above and added to the list */
330+
Py_ssize_t n = PyList_Size(d);
331+
for (Py_ssize_t i = 0; i < n; ++i) {
332+
PyObject *entry = PyList_GetItem(d, i);
333+
Py_DECREF(entry);
334+
}
335+
if (failure) {
336+
/* If there was a failure we might have created an entry but not added
337+
* it: dec-ref that, if it exists, before clearing the list. */
338+
Py_XDECREF(orphan);
339+
Py_CLEAR(d);
340+
}
326341
return d;
327342
}
328343
#endif

0 commit comments

Comments
 (0)