From: Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> Date: Wed, 14 Jun 2023 01:34:26 +0000 (-0700) Subject: [3.12] gh-105699: Use a Thread-Local Variable for PKGCONTEXT (gh-105740) (gh-105765) X-Git-Tag: v3.12.0b3~26 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=bc997b38b66cd61ab2ba9697546c39472cb93ee3;p=thirdparty%2FPython%2Fcpython.git [3.12] gh-105699: Use a Thread-Local Variable for PKGCONTEXT (gh-105740) (gh-105765) This fixes a race during import. The existing _PyRuntimeState.imports.pkgcontext is shared between interpreters, and occasionally this would cause a crash when multiple interpreters were importing extensions modules at the same time. To solve this we add a thread-local variable for the value. We also leave the existing state (and infrequent race) in place for platforms that do not support thread-local variables. (cherry picked from commit b87d2882754a7c273e2695c33384383eba380d7d) Co-authored-by: Eric Snow --- diff --git a/Python/import.c b/Python/import.c index 9e1857d5f3e4..24723d64bd0c 100644 --- a/Python/import.c +++ b/Python/import.c @@ -703,10 +703,19 @@ _PyImport_ClearModulesByIndex(PyInterpreterState *interp) _PyRuntime.imports.pkgcontext, and PyModule_Create*() will substitute this (if the name actually matches). */ + +#ifdef HAVE_THREAD_LOCAL +_Py_thread_local const char *pkgcontext = NULL; +# undef PKGCONTEXT +# define PKGCONTEXT pkgcontext +#endif + const char * _PyImport_ResolveNameWithPackageContext(const char *name) { +#ifndef HAVE_THREAD_LOCAL PyThread_acquire_lock(EXTENSIONS.mutex, WAIT_LOCK); +#endif if (PKGCONTEXT != NULL) { const char *p = strrchr(PKGCONTEXT, '.'); if (p != NULL && strcmp(name, p+1) == 0) { @@ -714,17 +723,23 @@ _PyImport_ResolveNameWithPackageContext(const char *name) PKGCONTEXT = NULL; } } +#ifndef HAVE_THREAD_LOCAL PyThread_release_lock(EXTENSIONS.mutex); +#endif return name; } const char * _PyImport_SwapPackageContext(const char *newcontext) { +#ifndef HAVE_THREAD_LOCAL PyThread_acquire_lock(EXTENSIONS.mutex, WAIT_LOCK); +#endif const char *oldcontext = PKGCONTEXT; PKGCONTEXT = newcontext; +#ifndef HAVE_THREAD_LOCAL PyThread_release_lock(EXTENSIONS.mutex); +#endif return oldcontext; } diff --git a/Tools/c-analyzer/c_parser/parser/_regexes.py b/Tools/c-analyzer/c_parser/parser/_regexes.py index b7f22b186f49..5695daff67d6 100644 --- a/Tools/c-analyzer/c_parser/parser/_regexes.py +++ b/Tools/c-analyzer/c_parser/parser/_regexes.py @@ -58,6 +58,7 @@ _KEYWORD = textwrap.dedent(r''' extern | register | static | + _Thread_local | typedef | const | @@ -137,7 +138,7 @@ COMPOUND_TYPE_KIND = r'(?: \b (?: struct | union | enum ) \b )' ####################################### # variable declarations -_STORAGE = 'auto register static extern'.split() +_STORAGE = 'auto register static extern _Thread_local'.split() STORAGE_CLASS = rf'(?: \b (?: {" | ".join(_STORAGE)} ) \b )' TYPE_QUALIFIER = r'(?: \b (?: const | volatile ) \b )' PTR_QUALIFIER = rf'(?: [*] (?: \s* {TYPE_QUALIFIER} )? )' diff --git a/Tools/c-analyzer/c_parser/preprocessor/gcc.py b/Tools/c-analyzer/c_parser/preprocessor/gcc.py index c680f351f224..147615707a3c 100644 --- a/Tools/c-analyzer/c_parser/preprocessor/gcc.py +++ b/Tools/c-analyzer/c_parser/preprocessor/gcc.py @@ -219,6 +219,7 @@ def _strip_directives(line, partial=0): line = line[m.end():] line = re.sub(r'__extension__', '', line) + line = re.sub(r'__thread\b', '_Thread_local', line) while (m := COMPILER_DIRECTIVE_RE.match(line)): before, _, _, closed = m.groups() diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index b6745b6aeb0b..afc28e551813 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -168,6 +168,12 @@ Modules/_xxinterpchannelsmodule.c - _globals - Python/pyfpe.c - PyFPE_counter - +##----------------------- +## thread-local variables + +Python/import.c - pkgcontext - +Python/pystate.c - _Py_tss_tstate - + ##----------------------- ## should be const # XXX Make them const.