Skip to content

Commit

Permalink
CLI: Use GetModuleHandleExW to locate libjulia.dll (#54617)
Browse files Browse the repository at this point in the history
This should be a more reliable look-up, since this will directly report
the path of the currently-executing libjulia.dll.

Without this PR, `LoadLibraryW` depends on the system library search
order. When the top-level executable is adjacent to `libjulia.dll` (as
it is for our binary distribution usually), then that search should be
OK.

However, applications that use Julia as a library can end up searching
the system PATH before making it to the correct `lib/julia` directory,
causing us to load the wrong version of `libjulia.dll`. In many cases,
that extra load is benign due to the stricter separation of
libraries/symbols on Windows - However, in general it's likely to be the
cause of subtle bugs.
  • Loading branch information
topolarity authored May 29, 2024
1 parent fb0d4a2 commit c11245d
Showing 1 changed file with 37 additions and 11 deletions.
48 changes: 37 additions & 11 deletions cli/loader_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,32 @@ static void * lookup_symbol(const void * lib_handle, const char * symbol_name) {
#endif
}

#if defined(_OS_WINDOWS_)
void win32_formatmessage(DWORD code, char *reason, int len) {
DWORD res;
LPWSTR errmsg;
res = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_MAX_WIDTH_MASK,
NULL, code,
MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
(LPWSTR)&errmsg, 0, NULL);
if (!res && (GetLastError() == ERROR_MUI_FILE_NOT_FOUND ||
GetLastError() == ERROR_RESOURCE_TYPE_NOT_FOUND)) {
res = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_MAX_WIDTH_MASK,
NULL, code,
0, (LPWSTR)&errmsg, 0, NULL);
}
res = WideCharToMultiByte(CP_UTF8, 0, errmsg, -1, reason, len, NULL, NULL);
reason[len - 1] = '\0';
LocalFree(errmsg);
}
#endif

// Find the location of libjulia.
char *lib_dir = NULL;
JL_DLLEXPORT const char * jl_get_libdir()
Expand All @@ -135,21 +161,21 @@ JL_DLLEXPORT const char * jl_get_libdir()
}
#if defined(_OS_WINDOWS_)
// On Windows, we use GetModuleFileNameW
wchar_t *libjulia_path = utf8_to_wchar(LIBJULIA_NAME);
HMODULE libjulia = NULL;

// Get a handle to libjulia.
if (!libjulia_path) {
jl_loader_print_stderr3("ERROR: Unable to convert path ", LIBJULIA_NAME, " to wide string!\n");
exit(1);
}
libjulia = LoadLibraryW(libjulia_path);
if (libjulia == NULL) {
jl_loader_print_stderr3("ERROR: Unable to load ", LIBJULIA_NAME, "!\n");
// Get a handle to libjulia
if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
(LPCWSTR)jl_get_libdir, &libjulia)) {
DWORD err = GetLastError();
jl_loader_print_stderr3("ERROR: could not locate library \"", LIBJULIA_NAME, "\"\n");

char msg[2048];
win32_formatmessage(err, msg, sizeof(msg));
jl_loader_print_stderr(msg);
exit(1);
}
free(libjulia_path);
libjulia_path = (wchar_t*)malloc(32768 * sizeof(wchar_t)); // max long path length

wchar_t *libjulia_path = (wchar_t*)malloc(32768 * sizeof(wchar_t)); // max long path length
if (!GetModuleFileNameW(libjulia, libjulia_path, 32768)) {
jl_loader_print_stderr("ERROR: GetModuleFileName() failed\n");
exit(1);
Expand Down

0 comments on commit c11245d

Please sign in to comment.