Skip to content

Commit 4d5fefe

Browse files
committed
CLI: Use GetModuleHandleExW to locate libjulia.dll (JuliaLang#54617)
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.
1 parent 48d4fd4 commit 4d5fefe

File tree

1 file changed

+37
-11
lines changed

1 file changed

+37
-11
lines changed

cli/loader_lib.c

+37-11
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,32 @@ static void * lookup_symbol(const void * lib_handle, const char * symbol_name) {
125125
#endif
126126
}
127127

128+
#if defined(_OS_WINDOWS_)
129+
void win32_formatmessage(DWORD code, char *reason, int len) {
130+
DWORD res;
131+
LPWSTR errmsg;
132+
res = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
133+
FORMAT_MESSAGE_FROM_SYSTEM |
134+
FORMAT_MESSAGE_IGNORE_INSERTS |
135+
FORMAT_MESSAGE_MAX_WIDTH_MASK,
136+
NULL, code,
137+
MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
138+
(LPWSTR)&errmsg, 0, NULL);
139+
if (!res && (GetLastError() == ERROR_MUI_FILE_NOT_FOUND ||
140+
GetLastError() == ERROR_RESOURCE_TYPE_NOT_FOUND)) {
141+
res = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
142+
FORMAT_MESSAGE_FROM_SYSTEM |
143+
FORMAT_MESSAGE_IGNORE_INSERTS |
144+
FORMAT_MESSAGE_MAX_WIDTH_MASK,
145+
NULL, code,
146+
0, (LPWSTR)&errmsg, 0, NULL);
147+
}
148+
res = WideCharToMultiByte(CP_UTF8, 0, errmsg, -1, reason, len, NULL, NULL);
149+
reason[len - 1] = '\0';
150+
LocalFree(errmsg);
151+
}
152+
#endif
153+
128154
// Find the location of libjulia.
129155
char *lib_dir = NULL;
130156
JL_DLLEXPORT const char * jl_get_libdir()
@@ -135,21 +161,21 @@ JL_DLLEXPORT const char * jl_get_libdir()
135161
}
136162
#if defined(_OS_WINDOWS_)
137163
// On Windows, we use GetModuleFileNameW
138-
wchar_t *libjulia_path = utf8_to_wchar(LIBJULIA_NAME);
139164
HMODULE libjulia = NULL;
140165

141-
// Get a handle to libjulia.
142-
if (!libjulia_path) {
143-
jl_loader_print_stderr3("ERROR: Unable to convert path ", LIBJULIA_NAME, " to wide string!\n");
144-
exit(1);
145-
}
146-
libjulia = LoadLibraryW(libjulia_path);
147-
if (libjulia == NULL) {
148-
jl_loader_print_stderr3("ERROR: Unable to load ", LIBJULIA_NAME, "!\n");
166+
// Get a handle to libjulia
167+
if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
168+
(LPCWSTR)jl_get_libdir, &libjulia)) {
169+
DWORD err = GetLastError();
170+
jl_loader_print_stderr3("ERROR: could not locate library \"", LIBJULIA_NAME, "\"\n");
171+
172+
char msg[2048];
173+
win32_formatmessage(err, msg, sizeof(msg));
174+
jl_loader_print_stderr(msg);
149175
exit(1);
150176
}
151-
free(libjulia_path);
152-
libjulia_path = (wchar_t*)malloc(32768 * sizeof(wchar_t)); // max long path length
177+
178+
wchar_t *libjulia_path = (wchar_t*)malloc(32768 * sizeof(wchar_t)); // max long path length
153179
if (!GetModuleFileNameW(libjulia, libjulia_path, 32768)) {
154180
jl_loader_print_stderr("ERROR: GetModuleFileName() failed\n");
155181
exit(1);

0 commit comments

Comments
 (0)