From b2dd05cf1aede0820b2547fd3ec2805a111cbd67 Mon Sep 17 00:00:00 2001
From: Ray Donnelly <mingw.android@gmail.com>
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 <isuruf@gmail.com>
---
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 <shlwapi.h>
+# include <string.h>
+# include <malloc.h>
+# include <libloaderapi.h>
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 <PREFIX>/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)