From 5f2a604b633c0cd24f897f828a7c928c3d2b651c Mon Sep 17 00:00:00 2001 From: Danish Nawab Date: Wed, 9 Apr 2025 15:25:24 +0000 Subject: [PATCH] 8353840: JNativeScan should not abort for missing classes Reviewed-by: jvernee, liach --- .../tools/jnativescan/JNativeScanTask.java | 21 +++++++-- .../com/sun/tools/jnativescan/Main.java | 2 +- .../tools/jnativescan/NativeMethodFinder.java | 43 ++++++++++--------- .../jnativescan/TestMissingSystemClass.java | 14 ++++-- .../cases/classpath/missingsystem/App.java | 1 + 5 files changed, 52 insertions(+), 29 deletions(-) diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/JNativeScanTask.java b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/JNativeScanTask.java index 2ff172e9c1b..c57e033427e 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/JNativeScanTask.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/JNativeScanTask.java @@ -42,15 +42,17 @@ import java.util.zip.ZipFile; class JNativeScanTask { private final PrintWriter out; + private final PrintWriter err; private final List classPaths; private final List modulePaths; private final List cmdRootModules; private final Runtime.Version version; private final Action action; - public JNativeScanTask(PrintWriter out, List classPaths, List modulePaths, + public JNativeScanTask(PrintWriter out, PrintWriter err, List classPaths, List modulePaths, List cmdRootModules, Runtime.Version version, Action action) { this.out = out; + this.err = err; this.classPaths = classPaths; this.modulePaths = modulePaths; this.version = version; @@ -71,10 +73,13 @@ class JNativeScanTask { toScan.add(new ClassFileSource.Module(m.reference())); } + Set errors = new LinkedHashSet<>(); + Diagnostics diagnostics = (context, error) -> + errors.add("Error while processing method: " + context + ": " + error.getMessage()); SortedMap>> allRestrictedMethods; try(ClassResolver classesToScan = ClassResolver.forClassFileSources(toScan, version); ClassResolver systemClassResolver = ClassResolver.forSystemModules(version)) { - NativeMethodFinder finder = NativeMethodFinder.create(classesToScan, systemClassResolver); + NativeMethodFinder finder = NativeMethodFinder.create(diagnostics, classesToScan, systemClassResolver); allRestrictedMethods = finder.findAll(); } catch (IOException e) { throw new RuntimeException(e); @@ -82,7 +87,7 @@ class JNativeScanTask { switch (action) { case PRINT -> printNativeAccess(allRestrictedMethods); - case DUMP_ALL -> dumpAll(allRestrictedMethods); + case DUMP_ALL -> dumpAll(allRestrictedMethods, errors); } } @@ -156,7 +161,7 @@ class JNativeScanTask { out.println(nativeAccess); } - private void dumpAll(SortedMap>> allRestrictedMethods) { + private void dumpAll(SortedMap>> allRestrictedMethods, Set errors) { if (allRestrictedMethods.isEmpty()) { out.println(" "); } else { @@ -177,6 +182,10 @@ class JNativeScanTask { }); }); } + if (!errors.isEmpty()) { + err.println("Error(s) while processing classes:"); + errors.forEach(error -> err.println(" " + error)); + } } private static boolean isJarFile(Path path) throws JNativeScanFatalError { @@ -192,4 +201,8 @@ class JNativeScanTask { String packagePrefix = desc.packageName().isEmpty() ? "" : desc.packageName() + "."; return packagePrefix + desc.displayName(); } + + interface Diagnostics { + void error(MethodRef context, JNativeScanFatalError error); + } } diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/Main.java b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/Main.java index 425a106d599..9aa77a947a9 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/Main.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/Main.java @@ -165,7 +165,7 @@ public class Main { action = JNativeScanTask.Action.PRINT; } - new JNativeScanTask(out, classPathJars, modulePaths, rootModules, version, action).run(); + new JNativeScanTask(out, err, classPathJars, modulePaths, rootModules, version, action).run(); } private static String[] expandArgFiles(String[] args) throws JNativeScanFatalError { diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/NativeMethodFinder.java b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/NativeMethodFinder.java index 681b954d4cd..b89c9db2858 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/NativeMethodFinder.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/NativeMethodFinder.java @@ -24,6 +24,7 @@ */ package com.sun.tools.jnativescan; +import com.sun.tools.jnativescan.JNativeScanTask.Diagnostics; import com.sun.tools.jnativescan.RestrictedUse.NativeMethodDecl; import com.sun.tools.jnativescan.RestrictedUse.RestrictedMethodRefs; @@ -44,16 +45,19 @@ class NativeMethodFinder { private static final String RESTRICTED_NAME = "Ljdk/internal/javac/Restricted+Annotation;"; private final Map cache = new HashMap<>(); + private final Diagnostics diagnostics; private final ClassResolver classesToScan; private final ClassResolver systemClassResolver; - private NativeMethodFinder(ClassResolver classesToScan, ClassResolver systemClassResolver) { + private NativeMethodFinder(Diagnostics diagnostics, ClassResolver classesToScan, ClassResolver systemClassResolver) { + this.diagnostics = diagnostics; this.classesToScan = classesToScan; this.systemClassResolver = systemClassResolver; } - public static NativeMethodFinder create(ClassResolver classesToScan, ClassResolver systemClassResolver) throws JNativeScanFatalError, IOException { - return new NativeMethodFinder(classesToScan, systemClassResolver); + public static NativeMethodFinder create(Diagnostics diagnostics, ClassResolver classesToScan, + ClassResolver systemClassResolver) throws JNativeScanFatalError, IOException { + return new NativeMethodFinder(diagnostics, classesToScan, systemClassResolver); } public SortedMap>> findAll() throws JNativeScanFatalError { @@ -68,23 +72,22 @@ class NativeMethodFinder { } else { SortedSet perMethod = new TreeSet<>(Comparator.comparing(MethodRef::toString)); methodModel.code().ifPresent(code -> { - try { - code.forEach(e -> { - switch (e) { - case InvokeInstruction invoke -> { - MethodRef ref = MethodRef.ofInvokeInstruction(invoke); - if (isRestrictedMethod(ref)) { - perMethod.add(ref); - } - } - default -> { - } - } - }); - } catch (JNativeScanFatalError e) { - throw new JNativeScanFatalError("Error while processing method: " + - MethodRef.ofModel(methodModel), e); - } + code.forEach(e -> { + switch (e) { + case InvokeInstruction invoke -> { + MethodRef ref = MethodRef.ofInvokeInstruction(invoke); + try { + if (isRestrictedMethod(ref)) { + perMethod.add(ref); + } + } catch (JNativeScanFatalError ex) { + diagnostics.error(MethodRef.ofModel(methodModel), ex); + } + } + default -> { + } + } + }); }); if (!perMethod.isEmpty()) { perClass.add(new RestrictedMethodRefs(MethodRef.ofModel(methodModel), perMethod)); diff --git a/test/langtools/tools/jnativescan/TestMissingSystemClass.java b/test/langtools/tools/jnativescan/TestMissingSystemClass.java index 5806590d0e0..8b6266aa5d7 100644 --- a/test/langtools/tools/jnativescan/TestMissingSystemClass.java +++ b/test/langtools/tools/jnativescan/TestMissingSystemClass.java @@ -35,6 +35,9 @@ import org.junit.jupiter.api.Test; import java.io.IOException; import java.nio.file.Path; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; public class TestMissingSystemClass extends JNativeScanTestBase { @@ -49,12 +52,15 @@ public class TestMissingSystemClass extends JNativeScanTestBase { @Test public void testSingleJarClassPath() { - assertFailure(jnativescan("--class-path", MISSING_SYSTEM.toString(), "--release", "21")) - .stdoutShouldBeEmpty() + List stderr = assertSuccess(jnativescan("--class-path", MISSING_SYSTEM.toString(), "--release", "21")) + .stdoutShouldContain("") + .stderrShouldContain("Error(s) while processing classes") .stderrShouldContain("Error while processing method") .stderrShouldContain("missingsystem.App::main(String[])void") - .stderrShouldContain("CAUSED BY:") .stderrShouldContain("System class can not be found") - .stderrShouldContain("java.lang.Compiler"); + .stderrShouldContain("java.lang.Compiler") + .stderrAsLines(); + + assertEquals(2, stderr.size(), "Unexpected number of lines in stderr"); } } diff --git a/test/langtools/tools/jnativescan/cases/classpath/missingsystem/App.java b/test/langtools/tools/jnativescan/cases/classpath/missingsystem/App.java index 0e20fe81eec..05812be45ce 100644 --- a/test/langtools/tools/jnativescan/cases/classpath/missingsystem/App.java +++ b/test/langtools/tools/jnativescan/cases/classpath/missingsystem/App.java @@ -28,5 +28,6 @@ public class App { // if we compile with --release 20, but run jnativescan // with --release 21, we should get an error java.lang.Compiler.enable(); + java.lang.Compiler.enable(); // should be de-duplicated in the error logs } }