From 37c48db29b3928578a36c0bb66ea7294fb590615 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Bl=C3=A4sing?= Date: Sun, 13 Mar 2022 19:51:51 +0100 Subject: [PATCH] Load jawt library relative to sun.boot.library.path system on unix OSes At least Ubuntu builds the JDK with RUNPATH set instead of RPATH. The two differ in their effect on loading transitive dependencies. RPATHs effect also covers libraries loaded as transitive dependencies, while RUNPATH does not. In the case of JNA libjawt is loaded by libdispatch (the native JNA part), which makes it a transtive load. The solution is to load the library with the full path based on the sun.boot.library.path system property, which points to the native library dirs. --- CHANGES.md | 1 + native/dispatch.c | 87 +++++++++++++++++++++++++++++++++++------------ 2 files changed, 66 insertions(+), 22 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 5d3279a80c..0d45d223ce 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -16,6 +16,7 @@ Bug Fixes --------- * [#1411](https://github.com/java-native-access/jna/pull/1411): Do not throw `Win32Exception` on success for empty section in `Kernel32Util#getPrivateProfileSection` - [@mkarg](https://github.com/mkarg). * [#1414](https://github.com/java-native-access/jna/pull/1414): Fix definition of `c.s.j.p.unix.X11.XK_Shift_R` - [@matthiasblaesing](https://github.com/matthiasblaesing). +* [#1422](https://github.com/java-native-access/jna/pull/1422): Load jawt library relative to `sun.boot.library.path` system on unix OSes - [@matthiasblaesing](https://github.com/matthiasblaesing). Release 5.10.0 ============== diff --git a/native/dispatch.c b/native/dispatch.c index d5148bf2ae..930ccebf05 100644 --- a/native/dispatch.c +++ b/native/dispatch.c @@ -3063,23 +3063,23 @@ Java_com_sun_jna_Native_initIDs(JNIEnv *env, jclass cls) { } #ifndef NO_JAWT -#if !defined(__APPLE__) -#define JAWT_HEADLESS_HACK -#ifdef _WIN32 -#define JAWT_NAME "jawt.dll" -#if defined(_WIN64) -#define METHOD_NAME "JAWT_GetAWT" -#else -#define METHOD_NAME "_JAWT_GetAWT@8" -#endif -#else -#define JAWT_NAME "libjawt.so" -#define METHOD_NAME "JAWT_GetAWT" -#endif -static void* jawt_handle = NULL; -static jboolean (JNICALL *pJAWT_GetAWT)(JNIEnv*,JAWT*); -#define JAWT_GetAWT (*pJAWT_GetAWT) -#endif + #if !defined(__APPLE__) + #define JAWT_HEADLESS_HACK + #ifdef _WIN32 + #if defined(_WIN64) + #define METHOD_NAME "JAWT_GetAWT" + #else + #define METHOD_NAME "_JAWT_GetAWT@8" + #endif + #else + #define METHOD_NAME "JAWT_GetAWT" + #endif + + static void* jawt_handle = NULL; + static jboolean (JNICALL *pJAWT_GetAWT)(JNIEnv*,JAWT*); + + #define JAWT_GetAWT (*pJAWT_GetAWT) + #endif #endif /* NO_JAWT */ JNIEXPORT jlong JNICALL @@ -3116,17 +3116,60 @@ Java_com_sun_jna_Native_getWindowHandle0(JNIEnv* UNUSED_JAWT(env), jclass UNUSED path = (wchar_t*)alloca(len * sizeof(wchar_t)); swprintf(path, len, L"%s%s", prop, suffix); - + free((void *)prop); } -#undef JAWT_NAME -#define JAWT_NAME path -#endif - if ((jawt_handle = LOAD_LIBRARY(JAWT_NAME, DEFAULT_LOAD_OPTS)) == NULL) { + if ((jawt_handle = LOAD_LIBRARY(path, DEFAULT_LOAD_OPTS)) == NULL) { char msg[MSG_SIZE]; throwByName(env, EUnsatisfiedLink, LOAD_ERROR(msg, sizeof(msg))); return -1; } +#else + const char* jawtLibraryName = "libjawt.so"; + + // Try to load the libjawt.so library first from the the directories listed + // in the sun.boot.library.path system property. At least Ubuntu builds the + // JDK with RUNPATH set instead of RPATH. The two differ in their effect on + // loading transitive dependencies. + // + // RPATHs effect also covers libraries loaded as transitive dependencies, + // while RUNPATH does not. In the case of JNA libjawt is loaded by + // libdispatch (the native JNA part), which makes it a transtive load. + // + // The solution is to load the library with the full path based on the + // sun.boot.library.path system property, which points to the native library + // dirs. + jstring jprop = get_system_property(env, "sun.boot.library.path"); + if (jprop != NULL) { + + char* prop = newCString(env, jprop); + char* saveptr; + + for(char* propToBeTokeninzed = prop; ; propToBeTokeninzed = NULL) { + char* pathElement = strtok_r(propToBeTokeninzed, ":", &saveptr); + + size_t len = strlen(pathElement) + strlen(jawtLibraryName) + 2; + char* path = (char*) alloca(len); + + sprintf(path, "%s/%s", pathElement, jawtLibraryName); + + jawt_handle = LOAD_LIBRARY(path, DEFAULT_LOAD_OPTS); + if(jawt_handle != NULL || pathElement == NULL) { + break; + } + } + + free((void *)prop); + } + + if (jawt_handle == NULL) { + if ((jawt_handle = LOAD_LIBRARY(jawtLibraryName, DEFAULT_LOAD_OPTS)) == NULL) { + char msg[MSG_SIZE]; + throwByName(env, EUnsatisfiedLink, LOAD_ERROR(msg, sizeof(msg))); + return -1; + } + } +#endif if ((pJAWT_GetAWT = (void*)FIND_ENTRY(jawt_handle, METHOD_NAME)) == NULL) { char msg[MSG_SIZE], buf[MSG_SIZE - 31 /* literal characters */ - sizeof(METHOD_NAME)]; snprintf(msg, sizeof(msg), "Error looking up JAWT method %s: %s",