From b2dd05cf1aede0820b2547fd3ec2805a111cbd67 Mon Sep 17 00:00:00 2001 From: Ray Donnelly Date: Tue, 24 Dec 2019 18:37:17 +0100 Subject: [PATCH 14/25] Add CondaEcosystemModifyDllSearchPath() The python interpreter is modifed so that it works as if the python interpreter was called with the following conda directories. os.add_dll_directory(join(sys.prefix, 'bin')) os.add_dll_directory(join(sys.prefix, 'Scripts')) os.add_dll_directory(join(sys.prefix, 'Library', 'bin')) os.add_dll_directory(join(sys.prefix, 'Library', 'usr', 'bin')) os.add_dll_directory(join(sys.prefix, 'Library', 'mingw-w64', 'bin')) Search order - The directory that contains the DLL (if looking for a dependency) - Application (python.exe) directory - Directories added with os.add_dll_directory - The 5 conda directories - C:\Windows\System32 Note that the default behaviour changed in conda python 3.10 to make os.add_dll_directory work in user code. Note that in conda python <3.11, there was an option CONDA_DLL_SEARCH_MODIFICATION=1 to add directories in PATH to the search order, but this was deprecated in 3.10 and removed in 3.11 in favour of using AddDllDirectory Co-authored-by: Isuru Fernando --- Python/pylifecycle.c | 96 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 960a38aebe..a05002b904 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -53,6 +53,10 @@ extern void _PyIO_Fini(void); #ifdef MS_WINDOWS # undef BYTE # include "windows.h" +# include +# include +# include +# include extern PyTypeObject PyWindowsConsoleIO_Type; # define PyWindowsConsoleIO_Check(op) \ @@ -105,6 +109,94 @@ __attribute__ ((section (".PyRuntime"))) = _PyRuntimeState_INIT; _Py_COMP_DIAG_POP +#ifdef MS_WINDOWS +/* + This function will modify the DLL search path so that /Library\bin + and other conda PATHS are added to the front of the DLL search path. +*/ + +#if !defined(LOAD_LIBRARY_SEARCH_DEFAULT_DIRS) +#define LOAD_LIBRARY_SEARCH_DEFAULT_DIRS 0x00001000 +#endif + +typedef void (WINAPI *ADD)(PCWSTR NewDirectory); +static ADD pAddDllDirectory = NULL; +typedef struct +{ + wchar_t *p_relative; + wchar_t *p_name; +} CONDA_PATH; + +#define NUM_CONDA_PATHS 5 + +static CONDA_PATH condaPaths[NUM_CONDA_PATHS] = +{ + {L"Library\\mingw-w64\\bin", NULL}, + {L"Library\\usr\\bin", NULL}, + {L"Library\\bin", NULL}, + {L"Scripts", NULL}, + {L"bin", NULL} +}; +static wchar_t sv_dll_dirname[1024]; + +int CondaEcosystemModifyDllSearchPath_Init() +{ + int debug_it = _wgetenv(L"CONDA_DLL_SEARCH_MODIFICATION_DEBUG") ? 1 : 0; + wchar_t* enable = _wgetenv(L"CONDA_DLL_SEARCH_MODIFICATION_ENABLE"); + int res = 0; + long long j; + CONDA_PATH *p_conda_path; + HMODULE dll_handle = NULL; + + if (pAddDllDirectory == NULL) + { + pAddDllDirectory = (ADD)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "AddDllDirectory"); + + /* Determine sv_dll_dirname */ + if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + (LPCSTR) &CondaEcosystemModifyDllSearchPath_Init, &dll_handle) == 0) + { + // Getting the pythonxx.dll path failed. Fall back to relative path of python.exe + // assuming that the executable that is running this code is python.exe + dll_handle = NULL; + } + GetModuleFileNameW(dll_handle, &sv_dll_dirname[0], sizeof(sv_dll_dirname)/sizeof(sv_dll_dirname[0])-1); + sv_dll_dirname[sizeof(sv_dll_dirname)/sizeof(sv_dll_dirname[0])-1] = L'\0'; + if (wcsrchr(sv_dll_dirname, L'\\')) + *wcsrchr(sv_dll_dirname, L'\\') = L'\0'; + + for (p_conda_path = &condaPaths[0]; p_conda_path < &condaPaths[NUM_CONDA_PATHS]; ++p_conda_path) + { + size_t n_chars_dll_dirname = wcslen(sv_dll_dirname); + size_t n_chars_p_relative = wcslen(p_conda_path->p_relative); + p_conda_path->p_name = malloc(sizeof(wchar_t) * (n_chars_dll_dirname + n_chars_p_relative + 2)); + wcsncpy(p_conda_path->p_name, sv_dll_dirname, n_chars_dll_dirname+1); + wcsncat(p_conda_path->p_name, L"\\", 2); + wcsncat(p_conda_path->p_name, p_conda_path->p_relative, n_chars_p_relative+1); + } + + } + + if (pAddDllDirectory == NULL) + { + if (debug_it) + fwprintf(stderr, L"CondaEcosystemModifyDllSearchPath() :: WARNING :: Please install KB2533623 from http://go.microsoft.com/fwlink/p/?linkid=217865\n"\ + L"CondaEcosystemModifyDllSearchPath() :: WARNING :: to improve conda ecosystem DLL isolation"); + res = 2; + } + else { + for (j = NUM_CONDA_PATHS-1, p_conda_path = &condaPaths[NUM_CONDA_PATHS-1]; j > -1; --j, --p_conda_path) + { + if (debug_it) + fwprintf(stderr, L"CondaEcosystemModifyDllSearchPath() :: AddDllDirectory(%ls - ExePrefix)\n", p_conda_path->p_name); + pAddDllDirectory(p_conda_path->p_name); + } + } + return res; +} + +#endif + static int runtime_initialized = 0; PyStatus @@ -121,6 +213,10 @@ _PyRuntime_Initialize(void) } runtime_initialized = 1; +#ifdef MS_WINDOWS + extern int CondaEcosystemModifyDllSearchPath_Init(); + CondaEcosystemModifyDllSearchPath_Init(); +#endif return _PyRuntimeState_Init(&_PyRuntime); } -- 2.32.1 (Apple Git-133)