gh-105699: Use a Thread-Local Variable for PKGCONTEXT (gh-105740)

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.
This commit is contained in:
Eric Snow 2023-06-13 18:58:23 -06:00 committed by GitHub
parent fcf0647cf2
commit b87d288275
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 24 additions and 1 deletions

View file

@ -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;
}