bpo-36085: Enable better DLL resolution on Windows (GH-12302)

This commit is contained in:
Steve Dower 2019-03-29 16:37:16 -07:00 committed by GitHub
parent 32119e10b7
commit 2438cdf0e9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 492 additions and 22 deletions

View file

@ -1442,17 +1442,23 @@ win32_error(const char* function, const char* filename)
}
static PyObject *
win32_error_object(const char* function, PyObject* filename)
win32_error_object_err(const char* function, PyObject* filename, DWORD err)
{
/* XXX - see win32_error for comments on 'function' */
errno = GetLastError();
if (filename)
return PyErr_SetExcFromWindowsErrWithFilenameObject(
PyExc_OSError,
errno,
err,
filename);
else
return PyErr_SetFromWindowsErr(errno);
return PyErr_SetFromWindowsErr(err);
}
static PyObject *
win32_error_object(const char* function, PyObject* filename)
{
errno = GetLastError();
return win32_error_object_err(function, filename, errno);
}
#endif /* MS_WINDOWS */
@ -13161,6 +13167,113 @@ error:
}
#endif /* HAVE_GETRANDOM_SYSCALL */
#ifdef MS_WINDOWS
/* bpo-36085: Helper functions for managing DLL search directories
* on win32
*/
typedef DLL_DIRECTORY_COOKIE (WINAPI *PAddDllDirectory)(PCWSTR newDirectory);
typedef BOOL (WINAPI *PRemoveDllDirectory)(DLL_DIRECTORY_COOKIE cookie);
/*[clinic input]
os._add_dll_directory
path: path_t
Add a path to the DLL search path.
This search path is used when resolving dependencies for imported
extension modules (the module itself is resolved through sys.path),
and also by ctypes.
Returns an opaque value that may be passed to os.remove_dll_directory
to remove this directory from the search path.
[clinic start generated code]*/
static PyObject *
os__add_dll_directory_impl(PyObject *module, path_t *path)
/*[clinic end generated code: output=80b025daebb5d683 input=1de3e6c13a5808c8]*/
{
HMODULE hKernel32;
PAddDllDirectory AddDllDirectory;
DLL_DIRECTORY_COOKIE cookie = 0;
DWORD err = 0;
/* For Windows 7, we have to load this. As this will be a fairly
infrequent operation, just do it each time. Kernel32 is always
loaded. */
Py_BEGIN_ALLOW_THREADS
if (!(hKernel32 = GetModuleHandleW(L"kernel32")) ||
!(AddDllDirectory = (PAddDllDirectory)GetProcAddress(
hKernel32, "AddDllDirectory")) ||
!(cookie = (*AddDllDirectory)(path->wide))) {
err = GetLastError();
}
Py_END_ALLOW_THREADS
if (err) {
return win32_error_object_err("add_dll_directory",
path->object, err);
}
return PyCapsule_New(cookie, "DLL directory cookie", NULL);
}
/*[clinic input]
os._remove_dll_directory
cookie: object
Removes a path from the DLL search path.
The parameter is an opaque value that was returned from
os.add_dll_directory. You can only remove directories that you added
yourself.
[clinic start generated code]*/
static PyObject *
os__remove_dll_directory_impl(PyObject *module, PyObject *cookie)
/*[clinic end generated code: output=594350433ae535bc input=c1d16a7e7d9dc5dc]*/
{
HMODULE hKernel32;
PRemoveDllDirectory RemoveDllDirectory;
DLL_DIRECTORY_COOKIE cookieValue;
DWORD err = 0;
if (!PyCapsule_IsValid(cookie, "DLL directory cookie")) {
PyErr_SetString(PyExc_TypeError,
"Provided cookie was not returned from os.add_dll_directory");
return NULL;
}
cookieValue = (DLL_DIRECTORY_COOKIE)PyCapsule_GetPointer(
cookie, "DLL directory cookie");
/* For Windows 7, we have to load this. As this will be a fairly
infrequent operation, just do it each time. Kernel32 is always
loaded. */
Py_BEGIN_ALLOW_THREADS
if (!(hKernel32 = GetModuleHandleW(L"kernel32")) ||
!(RemoveDllDirectory = (PRemoveDllDirectory)GetProcAddress(
hKernel32, "RemoveDllDirectory")) ||
!(*RemoveDllDirectory)(cookieValue)) {
err = GetLastError();
}
Py_END_ALLOW_THREADS
if (err) {
return win32_error_object_err("remove_dll_directory",
NULL, err);
}
if (PyCapsule_SetName(cookie, NULL)) {
return NULL;
}
Py_RETURN_NONE;
}
#endif
static PyMethodDef posix_methods[] = {
@ -13349,6 +13462,10 @@ static PyMethodDef posix_methods[] = {
OS_SCANDIR_METHODDEF
OS_FSPATH_METHODDEF
OS_GETRANDOM_METHODDEF
#ifdef MS_WINDOWS
OS__ADD_DLL_DIRECTORY_METHODDEF
OS__REMOVE_DLL_DIRECTORY_METHODDEF
#endif
{NULL, NULL} /* Sentinel */
};
@ -13826,6 +13943,14 @@ all_ins(PyObject *m)
if (PyModule_AddIntConstant(m, "_COPYFILE_DATA", COPYFILE_DATA)) return -1;
#endif
#ifdef MS_WINDOWS
if (PyModule_AddIntConstant(m, "_LOAD_LIBRARY_SEARCH_DEFAULT_DIRS", LOAD_LIBRARY_SEARCH_DEFAULT_DIRS)) return -1;
if (PyModule_AddIntConstant(m, "_LOAD_LIBRARY_SEARCH_APPLICATION_DIR", LOAD_LIBRARY_SEARCH_APPLICATION_DIR)) return -1;
if (PyModule_AddIntConstant(m, "_LOAD_LIBRARY_SEARCH_SYSTEM32", LOAD_LIBRARY_SEARCH_SYSTEM32)) return -1;
if (PyModule_AddIntConstant(m, "_LOAD_LIBRARY_SEARCH_USER_DIRS", LOAD_LIBRARY_SEARCH_USER_DIRS)) return -1;
if (PyModule_AddIntConstant(m, "_LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR", LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR)) return -1;
#endif
return 0;
}