mirror of
https://github.com/python/cpython.git
synced 2024-11-23 01:45:25 +08:00
gh-126316: Make grp.getgrall() thread-safe: add a mutex (#127055)
grpmodule.c is no longer built with the limited C API, since PyMutex is excluded from the limited C API.
This commit is contained in:
parent
60ec854bc2
commit
3c2bd66e21
@ -982,6 +982,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
|
|||||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(hi));
|
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(hi));
|
||||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(hook));
|
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(hook));
|
||||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(hour));
|
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(hour));
|
||||||
|
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(id));
|
||||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(ident));
|
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(ident));
|
||||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(identity_hint));
|
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(identity_hint));
|
||||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(ignore));
|
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(ignore));
|
||||||
|
@ -471,6 +471,7 @@ struct _Py_global_strings {
|
|||||||
STRUCT_FOR_ID(hi)
|
STRUCT_FOR_ID(hi)
|
||||||
STRUCT_FOR_ID(hook)
|
STRUCT_FOR_ID(hook)
|
||||||
STRUCT_FOR_ID(hour)
|
STRUCT_FOR_ID(hour)
|
||||||
|
STRUCT_FOR_ID(id)
|
||||||
STRUCT_FOR_ID(ident)
|
STRUCT_FOR_ID(ident)
|
||||||
STRUCT_FOR_ID(identity_hint)
|
STRUCT_FOR_ID(identity_hint)
|
||||||
STRUCT_FOR_ID(ignore)
|
STRUCT_FOR_ID(ignore)
|
||||||
|
1
Include/internal/pycore_runtime_init_generated.h
generated
1
Include/internal/pycore_runtime_init_generated.h
generated
@ -980,6 +980,7 @@ extern "C" {
|
|||||||
INIT_ID(hi), \
|
INIT_ID(hi), \
|
||||||
INIT_ID(hook), \
|
INIT_ID(hook), \
|
||||||
INIT_ID(hour), \
|
INIT_ID(hour), \
|
||||||
|
INIT_ID(id), \
|
||||||
INIT_ID(ident), \
|
INIT_ID(ident), \
|
||||||
INIT_ID(identity_hint), \
|
INIT_ID(identity_hint), \
|
||||||
INIT_ID(ignore), \
|
INIT_ID(ignore), \
|
||||||
|
@ -1680,6 +1680,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
|
|||||||
_PyUnicode_InternStatic(interp, &string);
|
_PyUnicode_InternStatic(interp, &string);
|
||||||
assert(_PyUnicode_CheckConsistency(string, 1));
|
assert(_PyUnicode_CheckConsistency(string, 1));
|
||||||
assert(PyUnicode_GET_LENGTH(string) != 1);
|
assert(PyUnicode_GET_LENGTH(string) != 1);
|
||||||
|
string = &_Py_ID(id);
|
||||||
|
_PyUnicode_InternStatic(interp, &string);
|
||||||
|
assert(_PyUnicode_CheckConsistency(string, 1));
|
||||||
|
assert(PyUnicode_GET_LENGTH(string) != 1);
|
||||||
string = &_Py_ID(ident);
|
string = &_Py_ID(ident);
|
||||||
_PyUnicode_InternStatic(interp, &string);
|
_PyUnicode_InternStatic(interp, &string);
|
||||||
assert(_PyUnicode_CheckConsistency(string, 1));
|
assert(_PyUnicode_CheckConsistency(string, 1));
|
||||||
|
@ -0,0 +1,2 @@
|
|||||||
|
:mod:`grp`: Make :func:`grp.getgrall` thread-safe by adding a mutex. Patch
|
||||||
|
by Victor Stinner.
|
88
Modules/clinic/grpmodule.c.h
generated
88
Modules/clinic/grpmodule.c.h
generated
@ -2,6 +2,12 @@
|
|||||||
preserve
|
preserve
|
||||||
[clinic start generated code]*/
|
[clinic start generated code]*/
|
||||||
|
|
||||||
|
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
|
||||||
|
# include "pycore_gc.h" // PyGC_Head
|
||||||
|
# include "pycore_runtime.h" // _Py_ID()
|
||||||
|
#endif
|
||||||
|
#include "pycore_modsupport.h" // _PyArg_UnpackKeywords()
|
||||||
|
|
||||||
PyDoc_STRVAR(grp_getgrgid__doc__,
|
PyDoc_STRVAR(grp_getgrgid__doc__,
|
||||||
"getgrgid($module, /, id)\n"
|
"getgrgid($module, /, id)\n"
|
||||||
"--\n"
|
"--\n"
|
||||||
@ -11,21 +17,49 @@ PyDoc_STRVAR(grp_getgrgid__doc__,
|
|||||||
"If id is not valid, raise KeyError.");
|
"If id is not valid, raise KeyError.");
|
||||||
|
|
||||||
#define GRP_GETGRGID_METHODDEF \
|
#define GRP_GETGRGID_METHODDEF \
|
||||||
{"getgrgid", (PyCFunction)(void(*)(void))grp_getgrgid, METH_VARARGS|METH_KEYWORDS, grp_getgrgid__doc__},
|
{"getgrgid", _PyCFunction_CAST(grp_getgrgid), METH_FASTCALL|METH_KEYWORDS, grp_getgrgid__doc__},
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
grp_getgrgid_impl(PyObject *module, PyObject *id);
|
grp_getgrgid_impl(PyObject *module, PyObject *id);
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
grp_getgrgid(PyObject *module, PyObject *args, PyObject *kwargs)
|
grp_getgrgid(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
|
||||||
{
|
{
|
||||||
PyObject *return_value = NULL;
|
PyObject *return_value = NULL;
|
||||||
static char *_keywords[] = {"id", NULL};
|
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
|
||||||
|
|
||||||
|
#define NUM_KEYWORDS 1
|
||||||
|
static struct {
|
||||||
|
PyGC_Head _this_is_not_used;
|
||||||
|
PyObject_VAR_HEAD
|
||||||
|
PyObject *ob_item[NUM_KEYWORDS];
|
||||||
|
} _kwtuple = {
|
||||||
|
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
|
||||||
|
.ob_item = { &_Py_ID(id), },
|
||||||
|
};
|
||||||
|
#undef NUM_KEYWORDS
|
||||||
|
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
|
||||||
|
|
||||||
|
#else // !Py_BUILD_CORE
|
||||||
|
# define KWTUPLE NULL
|
||||||
|
#endif // !Py_BUILD_CORE
|
||||||
|
|
||||||
|
static const char * const _keywords[] = {"id", NULL};
|
||||||
|
static _PyArg_Parser _parser = {
|
||||||
|
.keywords = _keywords,
|
||||||
|
.fname = "getgrgid",
|
||||||
|
.kwtuple = KWTUPLE,
|
||||||
|
};
|
||||||
|
#undef KWTUPLE
|
||||||
|
PyObject *argsbuf[1];
|
||||||
PyObject *id;
|
PyObject *id;
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O:getgrgid", _keywords,
|
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
|
||||||
&id))
|
/*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
|
||||||
|
if (!args) {
|
||||||
goto exit;
|
goto exit;
|
||||||
|
}
|
||||||
|
id = args[0];
|
||||||
return_value = grp_getgrgid_impl(module, id);
|
return_value = grp_getgrgid_impl(module, id);
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
@ -41,21 +75,53 @@ PyDoc_STRVAR(grp_getgrnam__doc__,
|
|||||||
"If name is not valid, raise KeyError.");
|
"If name is not valid, raise KeyError.");
|
||||||
|
|
||||||
#define GRP_GETGRNAM_METHODDEF \
|
#define GRP_GETGRNAM_METHODDEF \
|
||||||
{"getgrnam", (PyCFunction)(void(*)(void))grp_getgrnam, METH_VARARGS|METH_KEYWORDS, grp_getgrnam__doc__},
|
{"getgrnam", _PyCFunction_CAST(grp_getgrnam), METH_FASTCALL|METH_KEYWORDS, grp_getgrnam__doc__},
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
grp_getgrnam_impl(PyObject *module, PyObject *name);
|
grp_getgrnam_impl(PyObject *module, PyObject *name);
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
grp_getgrnam(PyObject *module, PyObject *args, PyObject *kwargs)
|
grp_getgrnam(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
|
||||||
{
|
{
|
||||||
PyObject *return_value = NULL;
|
PyObject *return_value = NULL;
|
||||||
static char *_keywords[] = {"name", NULL};
|
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
|
||||||
|
|
||||||
|
#define NUM_KEYWORDS 1
|
||||||
|
static struct {
|
||||||
|
PyGC_Head _this_is_not_used;
|
||||||
|
PyObject_VAR_HEAD
|
||||||
|
PyObject *ob_item[NUM_KEYWORDS];
|
||||||
|
} _kwtuple = {
|
||||||
|
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
|
||||||
|
.ob_item = { &_Py_ID(name), },
|
||||||
|
};
|
||||||
|
#undef NUM_KEYWORDS
|
||||||
|
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
|
||||||
|
|
||||||
|
#else // !Py_BUILD_CORE
|
||||||
|
# define KWTUPLE NULL
|
||||||
|
#endif // !Py_BUILD_CORE
|
||||||
|
|
||||||
|
static const char * const _keywords[] = {"name", NULL};
|
||||||
|
static _PyArg_Parser _parser = {
|
||||||
|
.keywords = _keywords,
|
||||||
|
.fname = "getgrnam",
|
||||||
|
.kwtuple = KWTUPLE,
|
||||||
|
};
|
||||||
|
#undef KWTUPLE
|
||||||
|
PyObject *argsbuf[1];
|
||||||
PyObject *name;
|
PyObject *name;
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "U:getgrnam", _keywords,
|
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
|
||||||
&name))
|
/*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
|
||||||
|
if (!args) {
|
||||||
goto exit;
|
goto exit;
|
||||||
|
}
|
||||||
|
if (!PyUnicode_Check(args[0])) {
|
||||||
|
_PyArg_BadArgument("getgrnam", "argument 'name'", "str", args[0]);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
name = args[0];
|
||||||
return_value = grp_getgrnam_impl(module, name);
|
return_value = grp_getgrnam_impl(module, name);
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
@ -82,4 +148,4 @@ grp_getgrall(PyObject *module, PyObject *Py_UNUSED(ignored))
|
|||||||
{
|
{
|
||||||
return grp_getgrall_impl(module);
|
return grp_getgrall_impl(module);
|
||||||
}
|
}
|
||||||
/*[clinic end generated code: output=81f180beb67fc585 input=a9049054013a1b77]*/
|
/*[clinic end generated code: output=2154194308dab038 input=a9049054013a1b77]*/
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
/* UNIX group file access module */
|
/* UNIX group file access module */
|
||||||
|
|
||||||
// Need limited C API version 3.13 for PyMem_RawRealloc()
|
// Argument Clinic uses the internal C API
|
||||||
#include "pyconfig.h" // Py_GIL_DISABLED
|
#ifndef Py_BUILD_CORE_BUILTIN
|
||||||
#ifndef Py_GIL_DISABLED
|
# define Py_BUILD_CORE_MODULE 1
|
||||||
#define Py_LIMITED_API 0x030d0000
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
@ -281,23 +280,33 @@ static PyObject *
|
|||||||
grp_getgrall_impl(PyObject *module)
|
grp_getgrall_impl(PyObject *module)
|
||||||
/*[clinic end generated code: output=585dad35e2e763d7 input=d7df76c825c367df]*/
|
/*[clinic end generated code: output=585dad35e2e763d7 input=d7df76c825c367df]*/
|
||||||
{
|
{
|
||||||
PyObject *d;
|
PyObject *d = PyList_New(0);
|
||||||
struct group *p;
|
if (d == NULL) {
|
||||||
|
|
||||||
if ((d = PyList_New(0)) == NULL)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyMutex getgrall_mutex = {0};
|
||||||
|
PyMutex_Lock(&getgrall_mutex);
|
||||||
setgrent();
|
setgrent();
|
||||||
|
|
||||||
|
struct group *p;
|
||||||
while ((p = getgrent()) != NULL) {
|
while ((p = getgrent()) != NULL) {
|
||||||
|
// gh-126316: Don't release the mutex around mkgrent() since
|
||||||
|
// setgrent()/endgrent() are not reentrant / thread-safe. A deadlock
|
||||||
|
// is unlikely since mkgrent() should not be able to call arbitrary
|
||||||
|
// Python code.
|
||||||
PyObject *v = mkgrent(module, p);
|
PyObject *v = mkgrent(module, p);
|
||||||
if (v == NULL || PyList_Append(d, v) != 0) {
|
if (v == NULL || PyList_Append(d, v) != 0) {
|
||||||
Py_XDECREF(v);
|
Py_XDECREF(v);
|
||||||
Py_DECREF(d);
|
Py_CLEAR(d);
|
||||||
endgrent();
|
goto done;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
Py_DECREF(v);
|
Py_DECREF(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
endgrent();
|
endgrent();
|
||||||
|
PyMutex_Unlock(&getgrall_mutex);
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -739,6 +739,7 @@ Modules/expat/xmlrole.c - declClose -
|
|||||||
Modules/expat/xmlrole.c - error -
|
Modules/expat/xmlrole.c - error -
|
||||||
|
|
||||||
## other
|
## other
|
||||||
|
Modules/grpmodule.c grp_getgrall_impl getgrall_mutex -
|
||||||
Modules/_io/_iomodule.c - _PyIO_Module -
|
Modules/_io/_iomodule.c - _PyIO_Module -
|
||||||
Modules/_sqlite/module.c - _sqlite3module -
|
Modules/_sqlite/module.c - _sqlite3module -
|
||||||
Modules/clinic/md5module.c.h _md5_md5 _keywords -
|
Modules/clinic/md5module.c.h _md5_md5 _keywords -
|
||||||
|
Can't render this file because it has a wrong number of fields in line 4.
|
Loading…
Reference in New Issue
Block a user