From 165da4cfc584613cbc56c25a69750b819dc30436 Mon Sep 17 00:00:00 2001 From: Elliot Saba Date: Tue, 7 Feb 2023 00:26:30 -0500 Subject: [PATCH] [windows] Fix self-path lookup on Windows (#103) Store handle to self in `DllMain` so that we don't try to figure out a handle to ourselves (incorrectly) anymore on Windows. Add test for LBT path printing when `LBT_VERBOSE=1` --- src/dl_utils.c | 5 +++-- src/libblastrampoline.c | 17 ++++++++++++++++- src/win_utils.c | 2 +- test/runtests.jl | 9 ++++++++- 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/dl_utils.c b/src/dl_utils.c index 437f1f5..40de092 100644 --- a/src/dl_utils.c +++ b/src/dl_utils.c @@ -82,10 +82,11 @@ void * lookup_symbol(const void * handle, const char * symbol_name) { * Work around protected symbol visibility and GCC/ld.bfd bug: * https://sourceware.org/bugzilla/show_bug.cgi?id=26815 */ +extern void * _win32_self_handle; void * lookup_self_symbol(const char * symbol_name) { void * self_handle = NULL; #if defined(_OS_WINDOWS_) - self_handle = GetModuleHandle(NULL); + self_handle = _win32_self_handle; #elif defined(_OS_DARWIN_) self_handle = RTLD_SELF; #elif defined(RTLD_DEFAULT) @@ -104,7 +105,7 @@ const char * lookup_self_path() return self_path; } #if defined(_OS_WINDOWS_) - if (!GetModuleFileNameA(GetModuleHandle(NULL), self_path, PATH_MAX)) { + if (!GetModuleFileNameA(_win32_self_handle, self_path, PATH_MAX)) { fprintf(stderr, "ERROR: GetModuleFileName() failed\n"); strcpy(self_path, ""); return self_path; diff --git a/src/libblastrampoline.c b/src/libblastrampoline.c index 36423d0..e265b90 100644 --- a/src/libblastrampoline.c +++ b/src/libblastrampoline.c @@ -395,8 +395,19 @@ LBT_DLLEXPORT int32_t lbt_forward(const char * libname, int32_t clear, int32_t v return nforwards; } - +/* + * On windows it's surprisingly difficult to get a handle to ourselves, + * and that's because they give it to you in `DllMain()`. ;) + */ +#ifdef _OS_WINDOWS_ +void * _win32_self_handle; +BOOL APIENTRY DllMain(HINSTANCE hModule, DWORD code, void *) { + if (code == DLL_PROCESS_ATTACH) { + _win32_self_handle = (void *)hModule; + } +#else __attribute__((constructor)) void init(void) { +#endif // Initialize config structures init_config(); @@ -457,4 +468,8 @@ __attribute__((constructor)) void init(void) { clear = 0; } } + +#ifdef _OS_WINDOWS_ + return TRUE; +#endif } diff --git a/src/win_utils.c b/src/win_utils.c index 444ffb7..fc34465 100644 --- a/src/win_utils.c +++ b/src/win_utils.c @@ -31,4 +31,4 @@ int utf8_to_wchar(const char * str, wchar_t * wstr, size_t maxlen) { if (!MultiByteToWideChar(CP_UTF8, 0, str, -1, wstr, len)) return 0; return 1; -} \ No newline at end of file +} diff --git a/test/runtests.jl b/test/runtests.jl index 3397ebe..d70d55e 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -61,6 +61,13 @@ function run_test((test_name, test_expected_outputs, expect_success), libblas_na end @test expected_return_value + # Expect to see the path to `libblastrampoline` within the output, + # since we have `LBT_VERBOSE=1` and at startup, it announces its own path: + if startswith(libblas_name, "blastrampoline") + lbt_libdir = first(libdirs) + @test occursin(lbt_libdir, output) + end + # Test to make sure the test ran properly has_expected_output = all(occursin(expected, output) for expected in test_expected_outputs) if !has_expected_output @@ -187,7 +194,7 @@ end if openblas_interface == :ILP64 inconsolable = ("inconsolable_test", ("||C||^2 is: 24.3384", "||b||^2 is: 3.0000"), true) @testset "LBT -> OpenBLAS 32 + 64 (LP64 + ILP64)" begin - libdirs = unique(vcat(OpenBLAS32_jll.LIBPATH_list..., OpenBLAS_jll.LIBPATH_list..., CompilerSupportLibraries_jll.LIBPATH_list..., lbt_dir)) + libdirs = unique(vcat(lbt_dir, OpenBLAS32_jll.LIBPATH_list..., OpenBLAS_jll.LIBPATH_list..., CompilerSupportLibraries_jll.LIBPATH_list...)) run_test(inconsolable, lbt_link_name, libdirs, :wild_sobbing, "$(OpenBLAS32_jll.libopenblas_path);$(OpenBLAS_jll.libopenblas_path)") end end