1
1
2
2
/* UNIX password file access module */
3
3
4
- // Need limited C API version 3.13 for PyMem_RawRealloc()
5
- #include "pyconfig.h" // Py_GIL_DISABLED
6
- #ifndef Py_GIL_DISABLED
7
- # define Py_LIMITED_API 0x030d0000
8
- #endif
9
-
10
4
#include "Python.h"
11
5
#include "posixmodule.h"
12
6
@@ -69,6 +63,11 @@ get_pwd_state(PyObject *module)
69
63
70
64
static struct PyModuleDef pwdmodule ;
71
65
66
+ /* Mutex to protect calls to getpwuid(), getpwnam(), and getpwent().
67
+ * These functions return pointer to static data structure, which
68
+ * may be overwritten by any subsequent calls. */
69
+ static PyMutex pwd_db_mutex = {0 };
70
+
72
71
#define DEFAULT_BUFFER_SIZE 1024
73
72
74
73
static PyObject *
@@ -182,9 +181,15 @@ pwd_getpwuid(PyObject *module, PyObject *uidobj)
182
181
183
182
Py_END_ALLOW_THREADS
184
183
#else
184
+ PyMutex_Lock (& pwd_db_mutex );
185
+ // The getpwuid() function is not required to be thread-safe.
186
+ // https://pubs.opengroup.org/onlinepubs/009604499/functions/getpwuid.html
185
187
p = getpwuid (uid );
186
188
#endif
187
189
if (p == NULL ) {
190
+ #ifndef HAVE_GETPWUID_R
191
+ PyMutex_Unlock (& pwd_db_mutex );
192
+ #endif
188
193
PyMem_RawFree (buf );
189
194
if (nomem == 1 ) {
190
195
return PyErr_NoMemory ();
@@ -200,6 +205,8 @@ pwd_getpwuid(PyObject *module, PyObject *uidobj)
200
205
retval = mkpwent (module , p );
201
206
#ifdef HAVE_GETPWUID_R
202
207
PyMem_RawFree (buf );
208
+ #else
209
+ PyMutex_Unlock (& pwd_db_mutex );
203
210
#endif
204
211
return retval ;
205
212
}
@@ -265,9 +272,15 @@ pwd_getpwnam_impl(PyObject *module, PyObject *name)
265
272
266
273
Py_END_ALLOW_THREADS
267
274
#else
275
+ PyMutex_Lock (& pwd_db_mutex );
276
+ // The getpwnam() function is not required to be thread-safe.
277
+ // https://pubs.opengroup.org/onlinepubs/009604599/functions/getpwnam.html
268
278
p = getpwnam (name_chars );
269
279
#endif
270
280
if (p == NULL ) {
281
+ #ifndef HAVE_GETPWNAM_R
282
+ PyMutex_Unlock (& pwd_db_mutex );
283
+ #endif
271
284
if (nomem == 1 ) {
272
285
PyErr_NoMemory ();
273
286
}
@@ -278,6 +291,9 @@ pwd_getpwnam_impl(PyObject *module, PyObject *name)
278
291
goto out ;
279
292
}
280
293
retval = mkpwent (module , p );
294
+ #ifndef HAVE_GETPWNAM_R
295
+ PyMutex_Unlock (& pwd_db_mutex );
296
+ #endif
281
297
out :
282
298
PyMem_RawFree (buf );
283
299
Py_DECREF (bytes );
@@ -302,12 +318,12 @@ pwd_getpwall_impl(PyObject *module)
302
318
if ((d = PyList_New (0 )) == NULL )
303
319
return NULL ;
304
320
305
- #ifdef Py_GIL_DISABLED
306
- static PyMutex getpwall_mutex = {0 };
307
- PyMutex_Lock (& getpwall_mutex );
308
- #endif
321
+ PyMutex_Lock (& pwd_db_mutex );
309
322
int failure = 0 ;
310
323
PyObject * v = NULL ;
324
+ // The setpwent(), getpwent() and endpwent() functions are not required to
325
+ // be thread-safe.
326
+ // https://pubs.opengroup.org/onlinepubs/009696799/functions/setpwent.html
311
327
setpwent ();
312
328
while ((p = getpwent ()) != NULL ) {
313
329
v = mkpwent (module , p );
@@ -321,9 +337,7 @@ pwd_getpwall_impl(PyObject *module)
321
337
322
338
done :
323
339
endpwent ();
324
- #ifdef Py_GIL_DISABLED
325
- PyMutex_Unlock (& getpwall_mutex );
326
- #endif
340
+ PyMutex_Unlock (& pwd_db_mutex );
327
341
if (failure ) {
328
342
Py_XDECREF (v );
329
343
Py_CLEAR (d );
0 commit comments