openjdk-1.8.0/8231584-Deadlock-with-ClassLoader.findLibrary-and-Sy.patch

377 lines
14 KiB
Diff
Raw Normal View History

From 219a986b26fe9813730939038b3b1d70255d19a6 Mon Sep 17 00:00:00 2001
From: wangshuai <wangshuai94@huawei.com>
Date: Mon, 11 Nov 2019 19:42:17 +0000
Subject: [PATCH] 8231584:Deadlock with ClassLoader.findLibrary and
System.loadLibrary call
Summary:<java.lang>:Deadlock with ClassLoader.findLibrary and System.loadLibrary call
LLT:FileSystemsDeadlockTest.java
Patch Type:backport
bug url: https://bugs.openjdk.java.net/browse/JDK-8231584
---
jdk/src/share/classes/java/lang/ClassLoader.java | 32 +++--
jdk/src/share/classes/java/lang/Runtime.java | 7 +-
jdk/src/share/classes/java/lang/System.java | 2 +
.../lang/Runtime/loadLibrary/LoadLibraryTest.java | 156 +++++++++++++++++++++
jdk/test/java/lang/Runtime/loadLibrary/Target.java | 34 +++++
.../java/lang/Runtime/loadLibrary/Target2.java | 29 ++++
6 files changed, 247 insertions(+), 13 deletions(-)
create mode 100644 jdk/test/java/lang/Runtime/loadLibrary/LoadLibraryTest.java
create mode 100644 jdk/test/java/lang/Runtime/loadLibrary/Target.java
create mode 100644 jdk/test/java/lang/Runtime/loadLibrary/Target2.java
diff --git a/jdk/src/share/classes/java/lang/ClassLoader.java b/jdk/src/share/classes/java/lang/ClassLoader.java
index 2e98092f63..925fdacce3 100644
--- a/jdk/src/share/classes/java/lang/ClassLoader.java
+++ b/jdk/src/share/classes/java/lang/ClassLoader.java
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, Azul Systems, Inc. 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
@@ -1467,6 +1468,17 @@ public abstract class ClassLoader {
}
}
+ /*
+ * Initialize default paths for native libraries search.
+ * Must be done early as JDK may load libraries during bootstrap.
+ *
+ * @see java.lang.System#initPhase1
+ */
+ static void initLibraryPaths() {
+ usr_paths = initializePath("java.library.path");
+ sys_paths = initializePath("sun.boot.library.path");
+ }
+
// Returns true if the specified class loader can be found in this class
// loader's delegation chain.
boolean isAncestor(ClassLoader cl) {
@@ -1809,10 +1821,9 @@ public abstract class ClassLoader {
boolean isAbsolute) {
ClassLoader loader =
(fromClass == null) ? null : fromClass.getClassLoader();
- if (sys_paths == null) {
- usr_paths = initializePath("java.library.path");
- sys_paths = initializePath("sun.boot.library.path");
- }
+ assert sys_paths != null : "should be initialized at this point";
+ assert usr_paths != null : "should be initialized at this point";
+
if (isAbsolute) {
if (loadLibrary0(fromClass, new File(name))) {
return;
@@ -1902,13 +1913,14 @@ public abstract class ClassLoader {
name +
" already loaded in another classloader");
}
- /* If the library is being loaded (must be by the same thread,
- * because Runtime.load and Runtime.loadLibrary are
- * synchronous). The reason is can occur is that the JNI_OnLoad
- * function can cause another loadLibrary invocation.
+ /*
+ * When a library is being loaded, JNI_OnLoad function can cause
+ * another loadLibrary invocation that should succeed.
*
- * Thus we can use a static stack to hold the list of libraries
- * we are loading.
+ * We use a static stack to hold the list of libraries we are
+ * loading because this can happen only when called by the
+ * same thread because Runtime.load and Runtime.loadLibrary
+ * are synchronous.
*
* If there is a pending load operation for the library, we
* immediately return success; otherwise, we raise
diff --git a/jdk/src/share/classes/java/lang/Runtime.java b/jdk/src/share/classes/java/lang/Runtime.java
index 9e53dc939e..5039059149 100644
--- a/jdk/src/share/classes/java/lang/Runtime.java
+++ b/jdk/src/share/classes/java/lang/Runtime.java
@@ -1,5 +1,6 @@
/*
* Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, Azul Systems, Inc. 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
@@ -797,7 +798,7 @@ public class Runtime {
load0(Reflection.getCallerClass(), filename);
}
- synchronized void load0(Class<?> fromClass, String filename) {
+ void load0(Class<?> fromClass, String filename) {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkLink(filename);
@@ -858,14 +859,14 @@ public class Runtime {
loadLibrary0(Reflection.getCallerClass(), libname);
}
- synchronized void loadLibrary0(Class<?> fromClass, String libname) {
+ void loadLibrary0(Class<?> fromClass, String libname) {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkLink(libname);
}
if (libname.indexOf((int)File.separatorChar) != -1) {
throw new UnsatisfiedLinkError(
- "Directory separator should not appear in library name: " + libname);
+ "Directory separator should not appear in library name: " + libname);
}
ClassLoader.loadLibrary(fromClass, libname, false);
}
diff --git a/jdk/src/share/classes/java/lang/System.java b/jdk/src/share/classes/java/lang/System.java
index b2747fa7a4..7bc235beff 100644
--- a/jdk/src/share/classes/java/lang/System.java
+++ b/jdk/src/share/classes/java/lang/System.java
@@ -1192,6 +1192,8 @@ public final class System {
setOut0(newPrintStream(fdOut, props.getProperty("sun.stdout.encoding")));
setErr0(newPrintStream(fdErr, props.getProperty("sun.stderr.encoding")));
+ ClassLoader.initLibraryPaths();
+
// Load the zip library now in order to keep java.util.zip.ZipFile
// from trying to use itself to load this library later.
loadLibrary("zip");
diff --git a/jdk/test/java/lang/Runtime/loadLibrary/LoadLibraryTest.java b/jdk/test/java/lang/Runtime/loadLibrary/LoadLibraryTest.java
new file mode 100644
index 0000000000..62eac12e18
--- /dev/null
+++ b/jdk/test/java/lang/Runtime/loadLibrary/LoadLibraryTest.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2018, Amazon and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, Azul Systems, Inc. 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 8231584
+ * @library /lib/testlibrary
+ * @run main/othervm LoadLibraryTest
+ */
+
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.Path;
+import java.net.MalformedURLException;
+import java.net.URLClassLoader;
+import java.net.URL;
+
+public class LoadLibraryTest {
+ static Thread thread1 = null;
+ static Thread thread2 = null;
+
+ static volatile boolean thread1Ready = false;
+
+ private static final String TEST_SRC = System.getProperty("test.src");
+ private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+ private static final Path CLS_DIR = Paths.get("classes");
+
+ static TestClassLoader loader;
+ static void someLibLoad() {
+ try {
+/*
+ FileSystems.getDefault();
+
+ // jdk/jdk: loads directly from Bootstrap Classloader (doesn't take lock on Runtime)
+ java.net.NetworkInterface.getNetworkInterfaces();
+
+ System.out.println(jdk.net.ExtendedSocketOptions.SO_FLOW_SLA);
+*/
+ Class c = Class.forName("Target2", true, loader);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ static class TestClassLoader extends URLClassLoader {
+ boolean passed = false;
+
+ public boolean passed() {
+ return passed;
+ }
+
+ TestClassLoader() throws MalformedURLException {
+ super(new URL[] { new URL("file://" + CLS_DIR.toAbsolutePath().toString() + '/') });
+ }
+
+ public String findLibrary(String name) {
+ System.out.println("findLibrary " + name);
+
+ if ("someLibrary".equals(name)) {
+ try {
+ synchronized(thread1) {
+ while(!thread1Ready) {
+ thread1.wait();
+ }
+ thread1.notifyAll();
+ }
+
+ Thread.sleep(10000);
+
+ System.out.println("Thread2 load");
+ someLibLoad();
+
+ // no deadlock happened
+ passed = true;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ return null;
+ }
+
+ return super.findLibrary(name);
+ }
+ }
+
+
+ public static void main(String[] args) throws Exception {
+ loader = new TestClassLoader();
+
+ if (!CompilerUtils.compile(SRC_DIR, CLS_DIR)) {
+ throw new Exception("Can't compile");
+ }
+
+ thread1 = new Thread() {
+ public void run() {
+ try {
+ synchronized(this) {
+ thread1Ready = true;
+ thread1.notifyAll();
+ thread1.wait();
+ }
+ } catch(InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+
+ System.out.println("Thread1 load");
+ someLibLoad();
+ };
+ };
+
+ thread2 = new Thread() {
+ public void run() {
+ try {
+ Class c = Class.forName("Target", true, loader);
+ System.out.println(c);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ };
+ };
+
+ thread1.setDaemon(true);
+ thread2.setDaemon(true);
+
+ thread1.start();
+ thread2.start();
+
+ thread1.join();
+ thread2.join();
+
+ if (!loader.passed()) {
+ throw new RuntimeException("FAIL");
+ }
+ }
+}
diff --git a/jdk/test/java/lang/Runtime/loadLibrary/Target.java b/jdk/test/java/lang/Runtime/loadLibrary/Target.java
new file mode 100644
index 0000000000..fc51481053
--- /dev/null
+++ b/jdk/test/java/lang/Runtime/loadLibrary/Target.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2019, Azul Systems, Inc. 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.
+ */
+
+class Target {
+ static {
+ try {
+ System.loadLibrary("someLibrary");
+ throw new RuntimeException("someLibrary was loaded");
+ } catch (UnsatisfiedLinkError e) {
+ // expected: we do not have a someLibrary
+ }
+ }
+}
+
diff --git a/jdk/test/java/lang/Runtime/loadLibrary/Target2.java b/jdk/test/java/lang/Runtime/loadLibrary/Target2.java
new file mode 100644
index 0000000000..bc8dfc5e63
--- /dev/null
+++ b/jdk/test/java/lang/Runtime/loadLibrary/Target2.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2019, Azul Systems, Inc. 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.
+ */
+
+class Target2 {
+ static {
+ System.loadLibrary("awt");
+ }
+}
+
--
2.12.3