Skip to content

Commit 4860f01

Browse files
tonyrobertszooba
authored andcommitted
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.
1 parent 2de576e commit 4860f01

File tree

8 files changed

+48
-6
lines changed

8 files changed

+48
-6
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
GIL is released while calling functions that acquire Windows loader lock.

Modules/_ctypes/_ctypes.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -678,7 +678,9 @@ CDataType_in_dll(PyObject *type, PyObject *args)
678678
}
679679

680680
#ifdef MS_WIN32
681+
Py_BEGIN_ALLOW_THREADS
681682
address = (void *)GetProcAddress(handle, name);
683+
Py_END_ALLOW_THREADS
682684
if (!address) {
683685
PyErr_Format(PyExc_ValueError,
684686
"symbol '%s' not found",
@@ -3243,18 +3245,23 @@ static PyGetSetDef PyCFuncPtr_getsets[] = {
32433245
#ifdef MS_WIN32
32443246
static PPROC FindAddress(void *handle, const char *name, PyObject *type)
32453247
{
3248+
PPROC address;
32463249
#ifdef MS_WIN64
32473250
/* win64 has no stdcall calling conv, so it should
32483251
also not have the name mangling of it.
32493252
*/
3250-
return (PPROC)GetProcAddress(handle, name);
3253+
Py_BEGIN_ALLOW_THREADS
3254+
address = (PPROC)GetProcAddress(handle, name);
3255+
Py_END_ALLOW_THREADS
3256+
return address;
32513257
#else
3252-
PPROC address;
32533258
char *mangled_name;
32543259
int i;
32553260
StgDictObject *dict;
32563261

3262+
Py_BEGIN_ALLOW_THREADS
32573263
address = (PPROC)GetProcAddress(handle, name);
3264+
Py_END_ALLOW_THREADS
32583265
if (address)
32593266
return address;
32603267
if (((size_t)name & ~0xFFFF) == 0) {
@@ -3275,7 +3282,9 @@ static PPROC FindAddress(void *handle, const char *name, PyObject *type)
32753282
return NULL;
32763283
for (i = 0; i < 32; ++i) {
32773284
sprintf(mangled_name, "_%s@%d", name, i*4);
3285+
Py_BEGIN_ALLOW_THREADS
32783286
address = (PPROC)GetProcAddress(handle, mangled_name);
3287+
Py_END_ALLOW_THREADS
32793288
if (address)
32803289
return address;
32813290
}

Modules/_ctypes/callproc.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1286,7 +1286,10 @@ static PyObject *load_library(PyObject *self, PyObject *args)
12861286
if (!name)
12871287
return NULL;
12881288

1289+
Py_BEGIN_ALLOW_THREADS
12891290
hMod = LoadLibraryW(name);
1291+
Py_END_ALLOW_THREADS
1292+
12901293
if (!hMod)
12911294
return PyErr_SetFromWindowsErr(GetLastError());
12921295
#ifdef _WIN64
@@ -1303,9 +1306,15 @@ Free the handle of an executable previously loaded by LoadLibrary.\n";
13031306
static PyObject *free_library(PyObject *self, PyObject *args)
13041307
{
13051308
void *hMod;
1309+
BOOL result;
13061310
if (!PyArg_ParseTuple(args, "O&:FreeLibrary", &_parse_voidp, &hMod))
13071311
return NULL;
1308-
if (!FreeLibrary((HMODULE)hMod))
1312+
1313+
Py_BEGIN_ALLOW_THREADS
1314+
result = FreeLibrary((HMODULE)hMod);
1315+
Py_END_ALLOW_THREADS
1316+
1317+
if (!result)
13091318
return PyErr_SetFromWindowsErr(GetLastError());
13101319
Py_RETURN_NONE;
13111320
}

Modules/overlapped.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,10 @@ initialize_function_pointers(void)
127127
closesocket(s);
128128

129129
/* On WinXP we will have Py_CancelIoEx == NULL */
130+
Py_BEGIN_ALLOW_THREADS
130131
hKernel32 = GetModuleHandle("KERNEL32");
131132
*(FARPROC *)&Py_CancelIoEx = GetProcAddress(hKernel32, "CancelIoEx");
133+
Py_END_ALLOW_THREADS
132134
return 0;
133135
}
134136

Modules/posixmodule.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7749,9 +7749,13 @@ check_CreateSymbolicLink(void)
77497749
/* only recheck */
77507750
if (Py_CreateSymbolicLinkW)
77517751
return 1;
7752+
7753+
Py_BEGIN_ALLOW_THREADS
77527754
hKernel32 = GetModuleHandleW(L"KERNEL32");
77537755
*(FARPROC*)&Py_CreateSymbolicLinkW = GetProcAddress(hKernel32,
77547756
"CreateSymbolicLinkW");
7757+
Py_END_ALLOW_THREADS
7758+
77557759
return Py_CreateSymbolicLinkW != NULL;
77567760
}
77577761

@@ -11288,14 +11292,14 @@ check_ShellExecute()
1128811292
the system SHELL32.DLL, even if there is another SHELL32.DLL
1128911293
in the DLL search path. */
1129011294
hShell32 = LoadLibraryW(L"SHELL32");
11291-
Py_END_ALLOW_THREADS
1129211295
if (hShell32) {
1129311296
*(FARPROC*)&Py_ShellExecuteW = GetProcAddress(hShell32,
1129411297
"ShellExecuteW");
1129511298
has_ShellExecute = Py_ShellExecuteW != NULL;
1129611299
} else {
1129711300
has_ShellExecute = 0;
1129811301
}
11302+
Py_END_ALLOW_THREADS
1129911303
}
1130011304
return has_ShellExecute;
1130111305
}
@@ -11909,11 +11913,12 @@ os_cpu_count_impl(PyObject *module)
1190911913
/* Vista is supported and the GetMaximumProcessorCount API is Win7+
1191011914
Need to fallback to Vista behavior if this call isn't present */
1191111915
HINSTANCE hKernel32;
11912-
hKernel32 = GetModuleHandleW(L"KERNEL32");
11913-
1191411916
static DWORD(CALLBACK *_GetMaximumProcessorCount)(WORD) = NULL;
11917+
Py_BEGIN_ALLOW_THREADS
11918+
hKernel32 = GetModuleHandleW(L"KERNEL32");
1191511919
*(FARPROC*)&_GetMaximumProcessorCount = GetProcAddress(hKernel32,
1191611920
"GetMaximumProcessorCount");
11921+
Py_END_ALLOW_THREADS
1191711922
if (_GetMaximumProcessorCount != NULL) {
1191811923
ncpu = _GetMaximumProcessorCount(ALL_PROCESSOR_GROUPS);
1191911924
}

PC/winreg.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -984,10 +984,12 @@ winreg_DeleteKeyEx_impl(PyObject *module, HKEY key,
984984

985985
/* Only available on 64bit platforms, so we must load it
986986
dynamically. */
987+
Py_BEGIN_ALLOW_THREADS
987988
hMod = GetModuleHandleW(L"advapi32.dll");
988989
if (hMod)
989990
pfn = (RDKEFunc)GetProcAddress(hMod,
990991
"RegDeleteKeyExW");
992+
Py_END_ALLOW_THREADS
991993
if (!pfn) {
992994
PyErr_SetString(PyExc_NotImplementedError,
993995
"not implemented on this platform");
@@ -1714,10 +1716,12 @@ winreg_DisableReflectionKey_impl(PyObject *module, HKEY key)
17141716

17151717
/* Only available on 64bit platforms, so we must load it
17161718
dynamically.*/
1719+
Py_BEGIN_ALLOW_THREADS
17171720
hMod = GetModuleHandleW(L"advapi32.dll");
17181721
if (hMod)
17191722
pfn = (RDRKFunc)GetProcAddress(hMod,
17201723
"RegDisableReflectionKey");
1724+
Py_END_ALLOW_THREADS
17211725
if (!pfn) {
17221726
PyErr_SetString(PyExc_NotImplementedError,
17231727
"not implemented on this platform");
@@ -1757,10 +1761,12 @@ winreg_EnableReflectionKey_impl(PyObject *module, HKEY key)
17571761

17581762
/* Only available on 64bit platforms, so we must load it
17591763
dynamically.*/
1764+
Py_BEGIN_ALLOW_THREADS
17601765
hMod = GetModuleHandleW(L"advapi32.dll");
17611766
if (hMod)
17621767
pfn = (RERKFunc)GetProcAddress(hMod,
17631768
"RegEnableReflectionKey");
1769+
Py_END_ALLOW_THREADS
17641770
if (!pfn) {
17651771
PyErr_SetString(PyExc_NotImplementedError,
17661772
"not implemented on this platform");
@@ -1799,10 +1805,12 @@ winreg_QueryReflectionKey_impl(PyObject *module, HKEY key)
17991805

18001806
/* Only available on 64bit platforms, so we must load it
18011807
dynamically.*/
1808+
Py_BEGIN_ALLOW_THREADS
18021809
hMod = GetModuleHandleW(L"advapi32.dll");
18031810
if (hMod)
18041811
pfn = (RQRKFunc)GetProcAddress(hMod,
18051812
"RegQueryReflectionKey");
1813+
Py_END_ALLOW_THREADS
18061814
if (!pfn) {
18071815
PyErr_SetString(PyExc_NotImplementedError,
18081816
"not implemented on this platform");

Python/dynload_win.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,10 @@ dl_funcptr _PyImport_FindSharedFuncptrWindows(const char *prefix,
218218
/* We use LoadLibraryEx so Windows looks for dependent DLLs
219219
in directory of pathname first. */
220220
/* XXX This call doesn't exist in Windows CE */
221+
Py_BEGIN_ALLOW_THREADS
221222
hDLL = LoadLibraryExW(wpathname, NULL,
222223
LOAD_WITH_ALTERED_SEARCH_PATH);
224+
Py_END_ALLOW_THREADS
223225
#if HAVE_SXS
224226
_Py_DeactivateActCtx(cookie);
225227
#endif
@@ -298,11 +300,15 @@ dl_funcptr _PyImport_FindSharedFuncptrWindows(const char *prefix,
298300
"Module use of %.150s conflicts "
299301
"with this version of Python.",
300302
import_python);
303+
Py_BEGIN_ALLOW_THREADS
301304
FreeLibrary(hDLL);
305+
Py_END_ALLOW_THREADS
302306
return NULL;
303307
}
304308
}
309+
Py_BEGIN_ALLOW_THREADS
305310
p = GetProcAddress(hDLL, funcname);
311+
Py_END_ALLOW_THREADS
306312
}
307313

308314
return p;

Python/sysmodule.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1159,7 +1159,9 @@ sys_getwindowsversion_impl(PyObject *module)
11591159
// We need to read the version info from a system file resource
11601160
// to accurately identify the OS version. If we fail for any reason,
11611161
// just return whatever GetVersion said.
1162+
Py_BEGIN_ALLOW_THREADS
11621163
hKernel32 = GetModuleHandleW(L"kernel32.dll");
1164+
Py_END_ALLOW_THREADS
11631165
if (hKernel32 && GetModuleFileNameW(hKernel32, kernel32_path, MAX_PATH) &&
11641166
(verblock_size = GetFileVersionInfoSizeW(kernel32_path, NULL)) &&
11651167
(verblock = PyMem_RawMalloc(verblock_size))) {

0 commit comments

Comments
 (0)