From 131a4a44898ddf48d3cd55cc3d59b71a8351d6d5 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Wed, 9 Mar 2022 10:13:14 +0000 Subject: [PATCH 1/2] 8275703: System.loadLibrary fails on Big Sur for libraries hidden from filesystem Reviewed-by: mbaesken Backport-of: 6aa02d75d9f26f46fbdb54aef52cea3257aa7462 --- make/test/JtregNativeJdk.gmk | 1 + src/hotspot/share/include/jvm.h | 2 +- .../classes/java/lang/ClassLoaderHelper.java | 28 +++++++- .../share/classes/java/lang/ClassLoader.java | 12 +++- .../share/native/libjava/ClassLoader.c | 7 +- .../classes/java/lang/ClassLoaderHelper.java | 10 ++- .../classes/java/lang/ClassLoaderHelper.java | 8 +++ .../exeLibraryCache/LibraryFromCache.java | 64 +++++++++++++++++++ .../exeLibraryCache/exeLibraryCache.c | 49 ++++++++++++++ 9 files changed, 172 insertions(+), 9 deletions(-) create mode 100644 test/jdk/java/lang/RuntimeTests/loadLibrary/exeLibraryCache/LibraryFromCache.java create mode 100644 test/jdk/java/lang/RuntimeTests/loadLibrary/exeLibraryCache/exeLibraryCache.c diff --git a/make/test/JtregNativeJdk.gmk b/make/test/JtregNativeJdk.gmk index f6cf7cf7ceb..07456060918 100644 --- a/make/test/JtregNativeJdk.gmk +++ b/make/test/JtregNativeJdk.gmk @@ -83,6 +83,7 @@ ifeq ($(OPENJDK_TARGET_OS), macosx) else BUILD_JDK_JTREG_EXCLUDE += libTestMainKeyWindow.m BUILD_JDK_JTREG_EXCLUDE += libTestDynamicStore.m + BUILD_JDK_JTREG_EXCLUDE += exeLibraryCache.c endif $(eval $(call SetupTestFilesCompilation, BUILD_JDK_JTREG_LIBRARIES, \ diff --git a/src/hotspot/share/include/jvm.h b/src/hotspot/share/include/jvm.h index e556e7c8c83..bb7f25282f1 100644 --- a/src/hotspot/share/include/jvm.h +++ b/src/hotspot/share/include/jvm.h @@ -160,7 +160,7 @@ JNIEXPORT jboolean JNICALL JVM_IsUseContainerSupport(void); JNIEXPORT void * JNICALL -JVM_LoadLibrary(const char *name); +JVM_LoadLibrary(const char *name, jboolean throwException); JNIEXPORT void JNICALL JVM_UnloadLibrary(void * handle); diff --git a/src/java.base/macosx/classes/java/lang/ClassLoaderHelper.java b/src/java.base/macosx/classes/java/lang/ClassLoaderHelper.java index bcadaac2359..705011689bb 100644 --- a/src/java.base/macosx/classes/java/lang/ClassLoaderHelper.java +++ b/src/java.base/macosx/classes/java/lang/ClassLoaderHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,11 +26,37 @@ package java.lang; import java.io.File; +import sun.security.action.GetPropertyAction; class ClassLoaderHelper { + private static final boolean hasDynamicLoaderCache; + static { + String osVersion = GetPropertyAction.privilegedGetProperty("os.version"); + // dynamic linker cache support on os.version >= 11.x + int major = 11; + int i = osVersion.indexOf('.'); + try { + major = Integer.parseInt(i < 0 ? osVersion : osVersion.substring(0, i)); + } catch (NumberFormatException e) {} + hasDynamicLoaderCache = major >= 11; + } private ClassLoaderHelper() {} + /** + * Returns true if loading a native library only if + * it's present on the file system. + * + * @implNote + * On macOS 11.x or later which supports dynamic linker cache, + * the dynamic library is not present on the filesystem. The + * library cannot determine if a dynamic library exists on a + * given path or not and so this method returns false. + */ + static boolean loadLibraryOnlyIfPresent() { + return !hasDynamicLoaderCache; + } + /** * Indicates, whether PATH env variable is allowed to contain quoted entries. */ diff --git a/src/java.base/share/classes/java/lang/ClassLoader.java b/src/java.base/share/classes/java/lang/ClassLoader.java index 82535d0176d..fa51f79aa01 100644 --- a/src/java.base/share/classes/java/lang/ClassLoader.java +++ b/src/java.base/share/classes/java/lang/ClassLoader.java @@ -2406,6 +2406,8 @@ protected String findLibrary(String libname) { * @since 1.2 */ static class NativeLibrary { + private static final boolean loadLibraryOnlyIfPresent = ClassLoaderHelper.loadLibraryOnlyIfPresent(); + // the class from which the library is loaded, also indicates // the loader this native library belongs. final Class fromClass; @@ -2420,7 +2422,8 @@ static class NativeLibrary { // the version of JNI environment the native library requires. int jniVersion; - native boolean load0(String name, boolean isBuiltin); + native boolean load0(String name, boolean isBuiltin, + boolean throwExceptionIfFail); native long findEntry(String name); @@ -2439,7 +2442,7 @@ boolean load() { throw new InternalError("Native library " + name + " has been loaded"); } - if (!load0(name, isBuiltin)) return false; + if (!load0(name, isBuiltin, loadLibraryOnlyIfPresent)) return false; // register the class loader for cleanup when unloaded // built class loaders are never unloaded @@ -2681,7 +2684,10 @@ private static boolean loadLibrary0(Class fromClass, final File file) { new PrivilegedAction<>() { public String run() { try { - return file.exists() ? file.getCanonicalPath() : null; + if (NativeLibrary.loadLibraryOnlyIfPresent && !file.exists()) { + return null; + } + return file.getCanonicalPath(); } catch (IOException e) { return null; } diff --git a/src/java.base/share/native/libjava/ClassLoader.c b/src/java.base/share/native/libjava/ClassLoader.c index b3d2ef109de..f20df5949d6 100644 --- a/src/java.base/share/native/libjava/ClassLoader.c +++ b/src/java.base/share/native/libjava/ClassLoader.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -336,7 +336,8 @@ static void *findJniFunction(JNIEnv *env, void *handle, */ JNIEXPORT jboolean JNICALL Java_java_lang_ClassLoader_00024NativeLibrary_load0 - (JNIEnv *env, jobject this, jstring name, jboolean isBuiltin) + (JNIEnv *env, jobject this, jstring name, + jboolean isBuiltin, jboolean throwExceptionIfFail) { const char *cname; jint jniVersion; @@ -350,7 +351,7 @@ Java_java_lang_ClassLoader_00024NativeLibrary_load0 cname = JNU_GetStringPlatformChars(env, name, 0); if (cname == 0) return JNI_FALSE; - handle = isBuiltin ? procHandle : JVM_LoadLibrary(cname); + handle = isBuiltin ? procHandle : JVM_LoadLibrary(cname, throwExceptionIfFail); if (handle) { JNI_OnLoad_t JNI_OnLoad; JNI_OnLoad = (JNI_OnLoad_t)findJniFunction(env, handle, diff --git a/src/java.base/unix/classes/java/lang/ClassLoaderHelper.java b/src/java.base/unix/classes/java/lang/ClassLoaderHelper.java index 68327f81bc3..751ae49e6f9 100644 --- a/src/java.base/unix/classes/java/lang/ClassLoaderHelper.java +++ b/src/java.base/unix/classes/java/lang/ClassLoaderHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,6 +36,14 @@ private ClassLoaderHelper() {} */ static final boolean allowsQuotedPathElements = false; + /** + * Returns true if loading a native library only if + * it's present on the file system. + */ + static boolean loadLibraryOnlyIfPresent() { + return true; + } + /** * Returns an alternate path name for the given file * such that if the original pathname did not exist, then the diff --git a/src/java.base/windows/classes/java/lang/ClassLoaderHelper.java b/src/java.base/windows/classes/java/lang/ClassLoaderHelper.java index 40d21a64333..43b702f0ac2 100644 --- a/src/java.base/windows/classes/java/lang/ClassLoaderHelper.java +++ b/src/java.base/windows/classes/java/lang/ClassLoaderHelper.java @@ -36,6 +36,14 @@ private ClassLoaderHelper() {} */ static final boolean allowsQuotedPathElements = true; + /** + * Returns true if loading a native library only if + * it's present on the file system. + */ + static boolean loadLibraryOnlyIfPresent() { + return true; + } + /** * Returns an alternate path name for the given file * such that if the original pathname did not exist, then the diff --git a/test/jdk/java/lang/RuntimeTests/loadLibrary/exeLibraryCache/LibraryFromCache.java b/test/jdk/java/lang/RuntimeTests/loadLibrary/exeLibraryCache/LibraryFromCache.java new file mode 100644 index 00000000000..e11746a48f9 --- /dev/null +++ b/test/jdk/java/lang/RuntimeTests/loadLibrary/exeLibraryCache/LibraryFromCache.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8275703 + * @library /test/lib + * @requires os.family == "mac" + * @run main/native/othervm -Djava.library.path=/usr/lib LibraryFromCache blas + * @run main/native/othervm -Djava.library.path=/usr/lib LibraryFromCache BLAS + * @summary Test System::loadLibrary to be able to load a library even + * if it's not present on the filesystem on macOS which supports + * dynamic library cache + */ + +import jdk.test.lib.process.OutputAnalyzer; + +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class LibraryFromCache { + public static void main(String[] args) throws IOException { + String libname = args[0]; + if (!systemHasLibrary(libname)) { + System.out.println("Test skipped. Library " + libname + " not found"); + return; + } + + System.loadLibrary(libname); + } + + /* + * Returns true if dlopen successfully loads the specified library + */ + private static boolean systemHasLibrary(String libname) throws IOException { + Path launcher = Paths.get(System.getProperty("test.nativepath"), "LibraryCache"); + ProcessBuilder pb = new ProcessBuilder(launcher.toString(), "lib" + libname + ".dylib"); + OutputAnalyzer outputAnalyzer = new OutputAnalyzer(pb.start()); + System.out.println(outputAnalyzer.getOutput()); + return outputAnalyzer.getExitValue() == 0; + } +} diff --git a/test/jdk/java/lang/RuntimeTests/loadLibrary/exeLibraryCache/exeLibraryCache.c b/test/jdk/java/lang/RuntimeTests/loadLibrary/exeLibraryCache/exeLibraryCache.c new file mode 100644 index 00000000000..846e04e71ef --- /dev/null +++ b/test/jdk/java/lang/RuntimeTests/loadLibrary/exeLibraryCache/exeLibraryCache.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include +#include + +int main(int argc, char** argv) +{ + void *handle; + + if (argc != 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + return EXIT_FAILURE; + } + + printf("Attempting to load library '%s'...\n", argv[1]); + + handle = dlopen(argv[1], RTLD_LAZY); + + if (handle == NULL) { + fprintf(stderr, "Unable to load library!\n"); + return EXIT_FAILURE; + } + + printf("Library successfully loaded!\n"); + + return dlclose(handle); +} From 2c2986398aa5d966b40782c986826c2997451ab2 Mon Sep 17 00:00:00 2001 From: J9 Build Date: Thu, 17 Mar 2022 03:05:46 +0000 Subject: [PATCH 2/2] Update OPENJDK_TAG to merged level jdk-11.0.15+6 Signed-off-by: J9 Build --- closed/openjdk-tag.gmk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/closed/openjdk-tag.gmk b/closed/openjdk-tag.gmk index 354c88dbdc2..7c4caf40ed2 100644 --- a/closed/openjdk-tag.gmk +++ b/closed/openjdk-tag.gmk @@ -1 +1 @@ -OPENJDK_TAG := jdk-11.0.15+5 +OPENJDK_TAG := jdk-11.0.15+6