GH-95909: Make _PyArg_Parser initialization thread safe (GH-95958)

This commit is contained in:
Kumar Aditya 2022-08-16 23:52:14 +05:30 committed by GitHub
parent 48174fa0b9
commit 9b30b965f0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 48 additions and 12 deletions

View file

@ -1974,15 +1974,10 @@ new_kwtuple(const char * const *keywords, int total, int pos)
}
static int
parser_init(struct _PyArg_Parser *parser)
_parser_init(struct _PyArg_Parser *parser)
{
const char * const *keywords = parser->keywords;
assert(keywords != NULL);
if (parser->initialized) {
assert(parser->kwtuple != NULL);
return 1;
}
assert(parser->pos == 0 &&
(parser->format == NULL || parser->fname == NULL) &&
parser->custom_msg == NULL &&
@ -2035,6 +2030,28 @@ parser_init(struct _PyArg_Parser *parser)
return 1;
}
static int
parser_init(struct _PyArg_Parser *parser)
{
// volatile as it can be modified by other threads
// and should not be optimized or reordered by compiler
if (*((volatile int *)&parser->initialized)) {
assert(parser->kwtuple != NULL);
return 1;
}
PyThread_acquire_lock(_PyRuntime.getargs.mutex, WAIT_LOCK);
// Check again if another thread initialized the parser
// while we were waiting for the lock.
if (*((volatile int *)&parser->initialized)) {
assert(parser->kwtuple != NULL);
PyThread_release_lock(_PyRuntime.getargs.mutex);
return 1;
}
int ret = _parser_init(parser);
PyThread_release_lock(_PyRuntime.getargs.mutex);
return ret;
}
static void
parser_clear(struct _PyArg_Parser *parser)
{