bpo-33895: Relase GIL while calling functions that acquire Windows loader lock (GH-7789)

LoadLibrary, GetProcAddress, FreeLibrary and GetModuleHandle acquire the system loader lock. Calling these while holding the GIL will cause a deadlock on the rare occasion that another thread is detaching and needs to destroy its thread state at the same time.
This commit is contained in:
Tony Roberts 2019-02-02 18:16:42 +01:00 committed by Steve Dower
parent 2de576e16d
commit 4860f01ac0
8 changed files with 48 additions and 6 deletions

View file

@ -0,0 +1 @@
GIL is released while calling functions that acquire Windows loader lock.

View file

@ -678,7 +678,9 @@ CDataType_in_dll(PyObject *type, PyObject *args)
} }
#ifdef MS_WIN32 #ifdef MS_WIN32
Py_BEGIN_ALLOW_THREADS
address = (void *)GetProcAddress(handle, name); address = (void *)GetProcAddress(handle, name);
Py_END_ALLOW_THREADS
if (!address) { if (!address) {
PyErr_Format(PyExc_ValueError, PyErr_Format(PyExc_ValueError,
"symbol '%s' not found", "symbol '%s' not found",
@ -3243,18 +3245,23 @@ static PyGetSetDef PyCFuncPtr_getsets[] = {
#ifdef MS_WIN32 #ifdef MS_WIN32
static PPROC FindAddress(void *handle, const char *name, PyObject *type) static PPROC FindAddress(void *handle, const char *name, PyObject *type)
{ {
PPROC address;
#ifdef MS_WIN64 #ifdef MS_WIN64
/* win64 has no stdcall calling conv, so it should /* win64 has no stdcall calling conv, so it should
also not have the name mangling of it. also not have the name mangling of it.
*/ */
return (PPROC)GetProcAddress(handle, name); Py_BEGIN_ALLOW_THREADS
address = (PPROC)GetProcAddress(handle, name);
Py_END_ALLOW_THREADS
return address;
#else #else
PPROC address;
char *mangled_name; char *mangled_name;
int i; int i;
StgDictObject *dict; StgDictObject *dict;
Py_BEGIN_ALLOW_THREADS
address = (PPROC)GetProcAddress(handle, name); address = (PPROC)GetProcAddress(handle, name);
Py_END_ALLOW_THREADS
if (address) if (address)
return address; return address;
if (((size_t)name & ~0xFFFF) == 0) { if (((size_t)name & ~0xFFFF) == 0) {
@ -3275,7 +3282,9 @@ static PPROC FindAddress(void *handle, const char *name, PyObject *type)
return NULL; return NULL;
for (i = 0; i < 32; ++i) { for (i = 0; i < 32; ++i) {
sprintf(mangled_name, "_%s@%d", name, i*4); sprintf(mangled_name, "_%s@%d", name, i*4);
Py_BEGIN_ALLOW_THREADS
address = (PPROC)GetProcAddress(handle, mangled_name); address = (PPROC)GetProcAddress(handle, mangled_name);
Py_END_ALLOW_THREADS
if (address) if (address)
return address; return address;
} }

View file

@ -1286,7 +1286,10 @@ static PyObject *load_library(PyObject *self, PyObject *args)
if (!name) if (!name)
return NULL; return NULL;
Py_BEGIN_ALLOW_THREADS
hMod = LoadLibraryW(name); hMod = LoadLibraryW(name);
Py_END_ALLOW_THREADS
if (!hMod) if (!hMod)
return PyErr_SetFromWindowsErr(GetLastError()); return PyErr_SetFromWindowsErr(GetLastError());
#ifdef _WIN64 #ifdef _WIN64
@ -1303,9 +1306,15 @@ Free the handle of an executable previously loaded by LoadLibrary.\n";
static PyObject *free_library(PyObject *self, PyObject *args) static PyObject *free_library(PyObject *self, PyObject *args)
{ {
void *hMod; void *hMod;
BOOL result;
if (!PyArg_ParseTuple(args, "O&:FreeLibrary", &_parse_voidp, &hMod)) if (!PyArg_ParseTuple(args, "O&:FreeLibrary", &_parse_voidp, &hMod))
return NULL; return NULL;
if (!FreeLibrary((HMODULE)hMod))
Py_BEGIN_ALLOW_THREADS
result = FreeLibrary((HMODULE)hMod);
Py_END_ALLOW_THREADS
if (!result)
return PyErr_SetFromWindowsErr(GetLastError()); return PyErr_SetFromWindowsErr(GetLastError());
Py_RETURN_NONE; Py_RETURN_NONE;
} }

View file

@ -127,8 +127,10 @@ initialize_function_pointers(void)
closesocket(s); closesocket(s);
/* On WinXP we will have Py_CancelIoEx == NULL */ /* On WinXP we will have Py_CancelIoEx == NULL */
Py_BEGIN_ALLOW_THREADS
hKernel32 = GetModuleHandle("KERNEL32"); hKernel32 = GetModuleHandle("KERNEL32");
*(FARPROC *)&Py_CancelIoEx = GetProcAddress(hKernel32, "CancelIoEx"); *(FARPROC *)&Py_CancelIoEx = GetProcAddress(hKernel32, "CancelIoEx");
Py_END_ALLOW_THREADS
return 0; return 0;
} }

View file

@ -7749,9 +7749,13 @@ check_CreateSymbolicLink(void)
/* only recheck */ /* only recheck */
if (Py_CreateSymbolicLinkW) if (Py_CreateSymbolicLinkW)
return 1; return 1;
Py_BEGIN_ALLOW_THREADS
hKernel32 = GetModuleHandleW(L"KERNEL32"); hKernel32 = GetModuleHandleW(L"KERNEL32");
*(FARPROC*)&Py_CreateSymbolicLinkW = GetProcAddress(hKernel32, *(FARPROC*)&Py_CreateSymbolicLinkW = GetProcAddress(hKernel32,
"CreateSymbolicLinkW"); "CreateSymbolicLinkW");
Py_END_ALLOW_THREADS
return Py_CreateSymbolicLinkW != NULL; return Py_CreateSymbolicLinkW != NULL;
} }
@ -11288,7 +11292,6 @@ check_ShellExecute()
the system SHELL32.DLL, even if there is another SHELL32.DLL the system SHELL32.DLL, even if there is another SHELL32.DLL
in the DLL search path. */ in the DLL search path. */
hShell32 = LoadLibraryW(L"SHELL32"); hShell32 = LoadLibraryW(L"SHELL32");
Py_END_ALLOW_THREADS
if (hShell32) { if (hShell32) {
*(FARPROC*)&Py_ShellExecuteW = GetProcAddress(hShell32, *(FARPROC*)&Py_ShellExecuteW = GetProcAddress(hShell32,
"ShellExecuteW"); "ShellExecuteW");
@ -11296,6 +11299,7 @@ check_ShellExecute()
} else { } else {
has_ShellExecute = 0; has_ShellExecute = 0;
} }
Py_END_ALLOW_THREADS
} }
return has_ShellExecute; return has_ShellExecute;
} }
@ -11909,11 +11913,12 @@ os_cpu_count_impl(PyObject *module)
/* Vista is supported and the GetMaximumProcessorCount API is Win7+ /* Vista is supported and the GetMaximumProcessorCount API is Win7+
Need to fallback to Vista behavior if this call isn't present */ Need to fallback to Vista behavior if this call isn't present */
HINSTANCE hKernel32; HINSTANCE hKernel32;
hKernel32 = GetModuleHandleW(L"KERNEL32");
static DWORD(CALLBACK *_GetMaximumProcessorCount)(WORD) = NULL; static DWORD(CALLBACK *_GetMaximumProcessorCount)(WORD) = NULL;
Py_BEGIN_ALLOW_THREADS
hKernel32 = GetModuleHandleW(L"KERNEL32");
*(FARPROC*)&_GetMaximumProcessorCount = GetProcAddress(hKernel32, *(FARPROC*)&_GetMaximumProcessorCount = GetProcAddress(hKernel32,
"GetMaximumProcessorCount"); "GetMaximumProcessorCount");
Py_END_ALLOW_THREADS
if (_GetMaximumProcessorCount != NULL) { if (_GetMaximumProcessorCount != NULL) {
ncpu = _GetMaximumProcessorCount(ALL_PROCESSOR_GROUPS); ncpu = _GetMaximumProcessorCount(ALL_PROCESSOR_GROUPS);
} }

View file

@ -984,10 +984,12 @@ winreg_DeleteKeyEx_impl(PyObject *module, HKEY key,
/* Only available on 64bit platforms, so we must load it /* Only available on 64bit platforms, so we must load it
dynamically. */ dynamically. */
Py_BEGIN_ALLOW_THREADS
hMod = GetModuleHandleW(L"advapi32.dll"); hMod = GetModuleHandleW(L"advapi32.dll");
if (hMod) if (hMod)
pfn = (RDKEFunc)GetProcAddress(hMod, pfn = (RDKEFunc)GetProcAddress(hMod,
"RegDeleteKeyExW"); "RegDeleteKeyExW");
Py_END_ALLOW_THREADS
if (!pfn) { if (!pfn) {
PyErr_SetString(PyExc_NotImplementedError, PyErr_SetString(PyExc_NotImplementedError,
"not implemented on this platform"); "not implemented on this platform");
@ -1714,10 +1716,12 @@ winreg_DisableReflectionKey_impl(PyObject *module, HKEY key)
/* Only available on 64bit platforms, so we must load it /* Only available on 64bit platforms, so we must load it
dynamically.*/ dynamically.*/
Py_BEGIN_ALLOW_THREADS
hMod = GetModuleHandleW(L"advapi32.dll"); hMod = GetModuleHandleW(L"advapi32.dll");
if (hMod) if (hMod)
pfn = (RDRKFunc)GetProcAddress(hMod, pfn = (RDRKFunc)GetProcAddress(hMod,
"RegDisableReflectionKey"); "RegDisableReflectionKey");
Py_END_ALLOW_THREADS
if (!pfn) { if (!pfn) {
PyErr_SetString(PyExc_NotImplementedError, PyErr_SetString(PyExc_NotImplementedError,
"not implemented on this platform"); "not implemented on this platform");
@ -1757,10 +1761,12 @@ winreg_EnableReflectionKey_impl(PyObject *module, HKEY key)
/* Only available on 64bit platforms, so we must load it /* Only available on 64bit platforms, so we must load it
dynamically.*/ dynamically.*/
Py_BEGIN_ALLOW_THREADS
hMod = GetModuleHandleW(L"advapi32.dll"); hMod = GetModuleHandleW(L"advapi32.dll");
if (hMod) if (hMod)
pfn = (RERKFunc)GetProcAddress(hMod, pfn = (RERKFunc)GetProcAddress(hMod,
"RegEnableReflectionKey"); "RegEnableReflectionKey");
Py_END_ALLOW_THREADS
if (!pfn) { if (!pfn) {
PyErr_SetString(PyExc_NotImplementedError, PyErr_SetString(PyExc_NotImplementedError,
"not implemented on this platform"); "not implemented on this platform");
@ -1799,10 +1805,12 @@ winreg_QueryReflectionKey_impl(PyObject *module, HKEY key)
/* Only available on 64bit platforms, so we must load it /* Only available on 64bit platforms, so we must load it
dynamically.*/ dynamically.*/
Py_BEGIN_ALLOW_THREADS
hMod = GetModuleHandleW(L"advapi32.dll"); hMod = GetModuleHandleW(L"advapi32.dll");
if (hMod) if (hMod)
pfn = (RQRKFunc)GetProcAddress(hMod, pfn = (RQRKFunc)GetProcAddress(hMod,
"RegQueryReflectionKey"); "RegQueryReflectionKey");
Py_END_ALLOW_THREADS
if (!pfn) { if (!pfn) {
PyErr_SetString(PyExc_NotImplementedError, PyErr_SetString(PyExc_NotImplementedError,
"not implemented on this platform"); "not implemented on this platform");

View file

@ -218,8 +218,10 @@ dl_funcptr _PyImport_FindSharedFuncptrWindows(const char *prefix,
/* We use LoadLibraryEx so Windows looks for dependent DLLs /* We use LoadLibraryEx so Windows looks for dependent DLLs
in directory of pathname first. */ in directory of pathname first. */
/* XXX This call doesn't exist in Windows CE */ /* XXX This call doesn't exist in Windows CE */
Py_BEGIN_ALLOW_THREADS
hDLL = LoadLibraryExW(wpathname, NULL, hDLL = LoadLibraryExW(wpathname, NULL,
LOAD_WITH_ALTERED_SEARCH_PATH); LOAD_WITH_ALTERED_SEARCH_PATH);
Py_END_ALLOW_THREADS
#if HAVE_SXS #if HAVE_SXS
_Py_DeactivateActCtx(cookie); _Py_DeactivateActCtx(cookie);
#endif #endif
@ -298,11 +300,15 @@ dl_funcptr _PyImport_FindSharedFuncptrWindows(const char *prefix,
"Module use of %.150s conflicts " "Module use of %.150s conflicts "
"with this version of Python.", "with this version of Python.",
import_python); import_python);
Py_BEGIN_ALLOW_THREADS
FreeLibrary(hDLL); FreeLibrary(hDLL);
Py_END_ALLOW_THREADS
return NULL; return NULL;
} }
} }
Py_BEGIN_ALLOW_THREADS
p = GetProcAddress(hDLL, funcname); p = GetProcAddress(hDLL, funcname);
Py_END_ALLOW_THREADS
} }
return p; return p;

View file

@ -1159,7 +1159,9 @@ sys_getwindowsversion_impl(PyObject *module)
// We need to read the version info from a system file resource // We need to read the version info from a system file resource
// to accurately identify the OS version. If we fail for any reason, // to accurately identify the OS version. If we fail for any reason,
// just return whatever GetVersion said. // just return whatever GetVersion said.
Py_BEGIN_ALLOW_THREADS
hKernel32 = GetModuleHandleW(L"kernel32.dll"); hKernel32 = GetModuleHandleW(L"kernel32.dll");
Py_END_ALLOW_THREADS
if (hKernel32 && GetModuleFileNameW(hKernel32, kernel32_path, MAX_PATH) && if (hKernel32 && GetModuleFileNameW(hKernel32, kernel32_path, MAX_PATH) &&
(verblock_size = GetFileVersionInfoSizeW(kernel32_path, NULL)) && (verblock_size = GetFileVersionInfoSizeW(kernel32_path, NULL)) &&
(verblock = PyMem_RawMalloc(verblock_size))) { (verblock = PyMem_RawMalloc(verblock_size))) {