From a4c8ebae8dc454531d22074d134bcd288e4f44ec Mon Sep 17 00:00:00 2001 From: Mandy Chung Date: Wed, 1 Nov 2023 10:45:47 -0700 Subject: [PATCH 1/2] 8317965: TestLoadLibraryDeadlock.java fails with "Unable to load native library.: expected true, was false" --- .../LoadLibraryDeadlock.java | 7 +- .../TestLoadLibraryDeadlock.java | 69 ++----------------- 2 files changed, 12 insertions(+), 64 deletions(-) diff --git a/test/jdk/java/lang/ClassLoader/loadLibraryDeadlock/LoadLibraryDeadlock.java b/test/jdk/java/lang/ClassLoader/loadLibraryDeadlock/LoadLibraryDeadlock.java index 42ecd372aecbc..3de814d511915 100644 --- a/test/jdk/java/lang/ClassLoader/loadLibraryDeadlock/LoadLibraryDeadlock.java +++ b/test/jdk/java/lang/ClassLoader/loadLibraryDeadlock/LoadLibraryDeadlock.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021, BELLSOFT. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -32,11 +32,13 @@ * called from Class1, then acquiring ZipFile during the search for a class * triggered from JNI. */ + import java.lang.*; public class LoadLibraryDeadlock { public static void main(String[] args) { + System.out.println("LoadLibraryDeadlock test started"); Thread t1 = new Thread() { public void run() { try { @@ -68,7 +70,8 @@ public void run() { try { t1.join(); t2.join(); - } catch (InterruptedException ignore) { + } catch (InterruptedException ex) { + throw new RuntimeException(ex); } } } diff --git a/test/jdk/java/lang/ClassLoader/loadLibraryDeadlock/TestLoadLibraryDeadlock.java b/test/jdk/java/lang/ClassLoader/loadLibraryDeadlock/TestLoadLibraryDeadlock.java index 65a485b34a3d0..968962d313e63 100644 --- a/test/jdk/java/lang/ClassLoader/loadLibraryDeadlock/TestLoadLibraryDeadlock.java +++ b/test/jdk/java/lang/ClassLoader/loadLibraryDeadlock/TestLoadLibraryDeadlock.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021, BELLSOFT. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -34,15 +34,14 @@ import jdk.test.lib.Asserts; import jdk.test.lib.JDKToolFinder; +import jdk.test.lib.Utils; import jdk.test.lib.process.*; import jdk.test.lib.util.FileUtils; import java.lang.ProcessBuilder; -import java.lang.Process; import java.nio.file.Paths; import java.io.*; import java.util.*; -import java.util.concurrent.*; import java.util.spi.ToolProvider; public class TestLoadLibraryDeadlock { @@ -108,51 +107,13 @@ private static OutputAnalyzer signJar(String jarToSign) throws Throwable { ); } - private static Process runJavaCommand(String... command) throws Throwable { + private static OutputAnalyzer runJavaCommand(String... command) throws Throwable { String java = JDKToolFinder.getJDKTool("java"); List commands = new ArrayList<>(); Collections.addAll(commands, java); + Collections.addAll(commands, Utils.getTestJavaOpts()); Collections.addAll(commands, command); - System.out.println("COMMAND: " + String.join(" ", commands)); - return new ProcessBuilder(commands.toArray(new String[0])) - .redirectErrorStream(true) - .directory(new File(testClassPath)) - .start(); - } - - private static OutputAnalyzer jcmd(long pid, String command) throws Throwable { - String jcmd = JDKToolFinder.getJDKTool("jcmd"); - return runCommandInTestClassPath(jcmd, - String.valueOf(pid), - command - ); - } - - private static String readAvailable(final InputStream is) throws Throwable { - final List list = Collections.synchronizedList(new ArrayList()); - ExecutorService executor = Executors.newFixedThreadPool(2); - Future future = executor.submit(new Callable() { - public String call() { - String result = new String(); - BufferedReader reader = new BufferedReader(new InputStreamReader(is)); - try { - while(true) { - String s = reader.readLine(); - if (s.length() > 0) { - list.add(s); - result += s + "\n"; - } - } - } catch (IOException ignore) {} - return result; - } - }); - try { - return future.get(1000, TimeUnit.MILLISECONDS); - } catch (Exception ignoreAll) { - future.cancel(true); - return String.join("\n", list); - } + return runCommand(new File(testClassPath), commands.toArray(new String[0])); } private final static long countLines(OutputAnalyzer output, String string) { @@ -194,24 +155,16 @@ public static void main(String[] args) throws Throwable { .shouldHaveExitValue(0); // load trigger class - Process process = runJavaCommand("-cp", + OutputAnalyzer outputAnalyzer = runJavaCommand("-cp", "a.jar" + classPathSeparator + "b.jar" + classPathSeparator + "c.jar", "-Djava.library.path=" + testLibraryPath, "LoadLibraryDeadlock"); - - // wait for a while to grab some output - process.waitFor(5, TimeUnit.SECONDS); - // dump available output - String output = readAvailable(process.getInputStream()); - OutputAnalyzer outputAnalyzer = new OutputAnalyzer(output); dump(outputAnalyzer); - // if the process is still running, get the thread dump - OutputAnalyzer outputAnalyzerJcmd = jcmd(process.pid(), "Thread.print"); - dump(outputAnalyzerJcmd); + outputAnalyzer.shouldHaveExitValue(0); Asserts.assertTrue( countLines(outputAnalyzer, "Java-level deadlock") == 0, @@ -237,13 +190,5 @@ public static void main(String[] args) throws Throwable { Asserts.assertTrue( countLines(outputAnalyzer, "Signed jar loaded from native library.") > 0, "Unable to load signed jar from native library."); - - if (!process.waitFor(5, TimeUnit.SECONDS)) { - // if the process is still frozen, fail the test even though - // the "deadlock" text hasn't been found - process.destroyForcibly(); - Asserts.assertTrue(process.waitFor() == 0, - "Process frozen."); - } } } From 962690fad0fc072274030454476b57d4a2ffe54f Mon Sep 17 00:00:00 2001 From: Mandy Chung Date: Wed, 1 Nov 2023 12:40:26 -0700 Subject: [PATCH 2/2] review feedback: use ProcessTools.createTestJavaProcessBuilder --- .../LoadLibraryDeadlock.java | 10 +++- .../TestLoadLibraryDeadlock.java | 53 ++++++++----------- 2 files changed, 29 insertions(+), 34 deletions(-) diff --git a/test/jdk/java/lang/ClassLoader/loadLibraryDeadlock/LoadLibraryDeadlock.java b/test/jdk/java/lang/ClassLoader/loadLibraryDeadlock/LoadLibraryDeadlock.java index 3de814d511915..bab4d828457ab 100644 --- a/test/jdk/java/lang/ClassLoader/loadLibraryDeadlock/LoadLibraryDeadlock.java +++ b/test/jdk/java/lang/ClassLoader/loadLibraryDeadlock/LoadLibraryDeadlock.java @@ -32,7 +32,6 @@ * called from Class1, then acquiring ZipFile during the search for a class * triggered from JNI. */ - import java.lang.*; public class LoadLibraryDeadlock { @@ -45,6 +44,7 @@ public void run() { // an instance of unsigned class that loads a native library Class c1 = Class.forName("Class1"); Object o = c1.newInstance(); + System.out.println("Class1 loaded from " + getLocation(c1)); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { @@ -58,7 +58,7 @@ public void run() { try { // load a class from a signed jar, which locks the JarFile Class c2 = Class.forName("p.Class2"); - System.out.println("Signed jar loaded."); + System.out.println("Class2 loaded from " + getLocation(c2)); } catch (ClassNotFoundException e) { System.out.println("Class Class2 not found."); throw new RuntimeException(e); @@ -74,4 +74,10 @@ public void run() { throw new RuntimeException(ex); } } + + private static String getLocation(Class c) { + var pd = c.getProtectionDomain(); + var cs = pd != null ? pd.getCodeSource() : null; + return cs != null ? cs.getLocation().getPath() : null; + } } diff --git a/test/jdk/java/lang/ClassLoader/loadLibraryDeadlock/TestLoadLibraryDeadlock.java b/test/jdk/java/lang/ClassLoader/loadLibraryDeadlock/TestLoadLibraryDeadlock.java index 968962d313e63..0e031c8610ba9 100644 --- a/test/jdk/java/lang/ClassLoader/loadLibraryDeadlock/TestLoadLibraryDeadlock.java +++ b/test/jdk/java/lang/ClassLoader/loadLibraryDeadlock/TestLoadLibraryDeadlock.java @@ -34,16 +34,18 @@ import jdk.test.lib.Asserts; import jdk.test.lib.JDKToolFinder; -import jdk.test.lib.Utils; import jdk.test.lib.process.*; import jdk.test.lib.util.FileUtils; import java.lang.ProcessBuilder; +import java.nio.file.Path; import java.nio.file.Paths; import java.io.*; import java.util.*; import java.util.spi.ToolProvider; +import static jdk.test.lib.process.ProcessTools.*; + public class TestLoadLibraryDeadlock { private static final ToolProvider JAR = ToolProvider.findFirst("jar") @@ -107,15 +109,6 @@ private static OutputAnalyzer signJar(String jarToSign) throws Throwable { ); } - private static OutputAnalyzer runJavaCommand(String... command) throws Throwable { - String java = JDKToolFinder.getJDKTool("java"); - List commands = new ArrayList<>(); - Collections.addAll(commands, java); - Collections.addAll(commands, Utils.getTestJavaOpts()); - Collections.addAll(commands, command); - return runCommand(new File(testClassPath), commands.toArray(new String[0])); - } - private final static long countLines(OutputAnalyzer output, String string) { return output.asLines() .stream() @@ -123,22 +116,17 @@ private final static long countLines(OutputAnalyzer output, String string) { .count(); } - private final static void dump(OutputAnalyzer output) { - output.asLines() - .stream() - .forEach(s -> System.out.println(s)); - } - public static void main(String[] args) throws Throwable { genKey() .shouldHaveExitValue(0); - FileUtils.deleteFileIfExistsWithRetry( - Paths.get(testClassPath, "a.jar")); - FileUtils.deleteFileIfExistsWithRetry( - Paths.get(testClassPath, "b.jar")); - FileUtils.deleteFileIfExistsWithRetry( - Paths.get(testClassPath, "c.jar")); + Path aJar = Path.of(testClassPath, "a.jar"); + Path bJar = Path.of(testClassPath, "b.jar"); + Path cJar = Path.of(testClassPath, "c.jar"); + + FileUtils.deleteFileIfExistsWithRetry(aJar); + FileUtils.deleteFileIfExistsWithRetry(bJar); + FileUtils.deleteFileIfExistsWithRetry(cJar); createJar("a.jar", "LoadLibraryDeadlock.class", @@ -155,15 +143,12 @@ public static void main(String[] args) throws Throwable { .shouldHaveExitValue(0); // load trigger class - OutputAnalyzer outputAnalyzer = runJavaCommand("-cp", - "a.jar" + classPathSeparator + - "b.jar" + classPathSeparator + - "c.jar", + OutputAnalyzer outputAnalyzer = executeCommand(createTestJavaProcessBuilder("-cp", + aJar.toString() + classPathSeparator + + bJar.toString() + classPathSeparator + + cJar.toString(), "-Djava.library.path=" + testLibraryPath, - "LoadLibraryDeadlock"); - // dump available output - dump(outputAnalyzer); - + "LoadLibraryDeadlock")); outputAnalyzer.shouldHaveExitValue(0); Asserts.assertTrue( @@ -184,8 +169,12 @@ public static void main(String[] args) throws Throwable { "Unable to load native library."); Asserts.assertTrue( - countLines(outputAnalyzer, "Signed jar loaded.") > 0, - "Unable to load signed jar."); + countLines(outputAnalyzer, "Class1 loaded from " + bJar) > 0, + "Unable to load b.jar."); + + Asserts.assertTrue( + countLines(outputAnalyzer, "Class2 loaded from " + cJar) > 0, + "Unable to load signed c.jar."); Asserts.assertTrue( countLines(outputAnalyzer, "Signed jar loaded from native library.") > 0,