Skip to content

Commit 5f2a604

Browse files
danishnawabliach
authored andcommittedApr 9, 2025
8353840: JNativeScan should not abort for missing classes
Reviewed-by: jvernee, liach
1 parent 1f21da7 commit 5f2a604

File tree

5 files changed

+52
-29
lines changed

5 files changed

+52
-29
lines changed
 

‎src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/JNativeScanTask.java

+17-4
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,17 @@
4242
class JNativeScanTask {
4343

4444
private final PrintWriter out;
45+
private final PrintWriter err;
4546
private final List<Path> classPaths;
4647
private final List<Path> modulePaths;
4748
private final List<String> cmdRootModules;
4849
private final Runtime.Version version;
4950
private final Action action;
5051

51-
public JNativeScanTask(PrintWriter out, List<Path> classPaths, List<Path> modulePaths,
52+
public JNativeScanTask(PrintWriter out, PrintWriter err, List<Path> classPaths, List<Path> modulePaths,
5253
List<String> cmdRootModules, Runtime.Version version, Action action) {
5354
this.out = out;
55+
this.err = err;
5456
this.classPaths = classPaths;
5557
this.modulePaths = modulePaths;
5658
this.version = version;
@@ -71,18 +73,21 @@ public void run() throws JNativeScanFatalError {
7173
toScan.add(new ClassFileSource.Module(m.reference()));
7274
}
7375

76+
Set<String> errors = new LinkedHashSet<>();
77+
Diagnostics diagnostics = (context, error) ->
78+
errors.add("Error while processing method: " + context + ": " + error.getMessage());
7479
SortedMap<ClassFileSource, SortedMap<ClassDesc, List<RestrictedUse>>> allRestrictedMethods;
7580
try(ClassResolver classesToScan = ClassResolver.forClassFileSources(toScan, version);
7681
ClassResolver systemClassResolver = ClassResolver.forSystemModules(version)) {
77-
NativeMethodFinder finder = NativeMethodFinder.create(classesToScan, systemClassResolver);
82+
NativeMethodFinder finder = NativeMethodFinder.create(diagnostics, classesToScan, systemClassResolver);
7883
allRestrictedMethods = finder.findAll();
7984
} catch (IOException e) {
8085
throw new RuntimeException(e);
8186
}
8287

8388
switch (action) {
8489
case PRINT -> printNativeAccess(allRestrictedMethods);
85-
case DUMP_ALL -> dumpAll(allRestrictedMethods);
90+
case DUMP_ALL -> dumpAll(allRestrictedMethods, errors);
8691
}
8792
}
8893

@@ -156,7 +161,7 @@ private void printNativeAccess(SortedMap<ClassFileSource, SortedMap<ClassDesc, L
156161
out.println(nativeAccess);
157162
}
158163

159-
private void dumpAll(SortedMap<ClassFileSource, SortedMap<ClassDesc, List<RestrictedUse>>> allRestrictedMethods) {
164+
private void dumpAll(SortedMap<ClassFileSource, SortedMap<ClassDesc, List<RestrictedUse>>> allRestrictedMethods, Set<String> errors) {
160165
if (allRestrictedMethods.isEmpty()) {
161166
out.println(" <no restricted methods>");
162167
} else {
@@ -177,6 +182,10 @@ private void dumpAll(SortedMap<ClassFileSource, SortedMap<ClassDesc, List<Restri
177182
});
178183
});
179184
}
185+
if (!errors.isEmpty()) {
186+
err.println("Error(s) while processing classes:");
187+
errors.forEach(error -> err.println(" " + error));
188+
}
180189
}
181190

182191
private static boolean isJarFile(Path path) throws JNativeScanFatalError {
@@ -192,4 +201,8 @@ public static String qualName(ClassDesc desc) {
192201
String packagePrefix = desc.packageName().isEmpty() ? "" : desc.packageName() + ".";
193202
return packagePrefix + desc.displayName();
194203
}
204+
205+
interface Diagnostics {
206+
void error(MethodRef context, JNativeScanFatalError error);
207+
}
195208
}

‎src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/Main.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ private void parseOptionsAndRun(String[] expandedArgs) throws JNativeScanFatalEr
165165
action = JNativeScanTask.Action.PRINT;
166166
}
167167

168-
new JNativeScanTask(out, classPathJars, modulePaths, rootModules, version, action).run();
168+
new JNativeScanTask(out, err, classPathJars, modulePaths, rootModules, version, action).run();
169169
}
170170

171171
private static String[] expandArgFiles(String[] args) throws JNativeScanFatalError {

‎src/jdk.jdeps/share/classes/com/sun/tools/jnativescan/NativeMethodFinder.java

+23-20
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
*/
2525
package com.sun.tools.jnativescan;
2626

27+
import com.sun.tools.jnativescan.JNativeScanTask.Diagnostics;
2728
import com.sun.tools.jnativescan.RestrictedUse.NativeMethodDecl;
2829
import com.sun.tools.jnativescan.RestrictedUse.RestrictedMethodRefs;
2930

@@ -44,16 +45,19 @@ class NativeMethodFinder {
4445
private static final String RESTRICTED_NAME = "Ljdk/internal/javac/Restricted+Annotation;";
4546

4647
private final Map<MethodRef, Boolean> cache = new HashMap<>();
48+
private final Diagnostics diagnostics;
4749
private final ClassResolver classesToScan;
4850
private final ClassResolver systemClassResolver;
4951

50-
private NativeMethodFinder(ClassResolver classesToScan, ClassResolver systemClassResolver) {
52+
private NativeMethodFinder(Diagnostics diagnostics, ClassResolver classesToScan, ClassResolver systemClassResolver) {
53+
this.diagnostics = diagnostics;
5154
this.classesToScan = classesToScan;
5255
this.systemClassResolver = systemClassResolver;
5356
}
5457

55-
public static NativeMethodFinder create(ClassResolver classesToScan, ClassResolver systemClassResolver) throws JNativeScanFatalError, IOException {
56-
return new NativeMethodFinder(classesToScan, systemClassResolver);
58+
public static NativeMethodFinder create(Diagnostics diagnostics, ClassResolver classesToScan,
59+
ClassResolver systemClassResolver) throws JNativeScanFatalError, IOException {
60+
return new NativeMethodFinder(diagnostics, classesToScan, systemClassResolver);
5761
}
5862

5963
public SortedMap<ClassFileSource, SortedMap<ClassDesc, List<RestrictedUse>>> findAll() throws JNativeScanFatalError {
@@ -68,23 +72,22 @@ public SortedMap<ClassFileSource, SortedMap<ClassDesc, List<RestrictedUse>>> fin
6872
} else {
6973
SortedSet<MethodRef> perMethod = new TreeSet<>(Comparator.comparing(MethodRef::toString));
7074
methodModel.code().ifPresent(code -> {
71-
try {
72-
code.forEach(e -> {
73-
switch (e) {
74-
case InvokeInstruction invoke -> {
75-
MethodRef ref = MethodRef.ofInvokeInstruction(invoke);
76-
if (isRestrictedMethod(ref)) {
77-
perMethod.add(ref);
78-
}
79-
}
80-
default -> {
81-
}
82-
}
83-
});
84-
} catch (JNativeScanFatalError e) {
85-
throw new JNativeScanFatalError("Error while processing method: " +
86-
MethodRef.ofModel(methodModel), e);
87-
}
75+
code.forEach(e -> {
76+
switch (e) {
77+
case InvokeInstruction invoke -> {
78+
MethodRef ref = MethodRef.ofInvokeInstruction(invoke);
79+
try {
80+
if (isRestrictedMethod(ref)) {
81+
perMethod.add(ref);
82+
}
83+
} catch (JNativeScanFatalError ex) {
84+
diagnostics.error(MethodRef.ofModel(methodModel), ex);
85+
}
86+
}
87+
default -> {
88+
}
89+
}
90+
});
8891
});
8992
if (!perMethod.isEmpty()) {
9093
perClass.add(new RestrictedMethodRefs(MethodRef.ofModel(methodModel), perMethod));

‎test/langtools/tools/jnativescan/TestMissingSystemClass.java

+10-4
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@
3535

3636
import java.io.IOException;
3737
import java.nio.file.Path;
38+
import java.util.List;
39+
40+
import static org.junit.jupiter.api.Assertions.assertEquals;
3841

3942
public class TestMissingSystemClass extends JNativeScanTestBase {
4043

@@ -49,12 +52,15 @@ public static void before() throws IOException {
4952

5053
@Test
5154
public void testSingleJarClassPath() {
52-
assertFailure(jnativescan("--class-path", MISSING_SYSTEM.toString(), "--release", "21"))
53-
.stdoutShouldBeEmpty()
55+
List<String> stderr = assertSuccess(jnativescan("--class-path", MISSING_SYSTEM.toString(), "--release", "21"))
56+
.stdoutShouldContain("<no restricted methods>")
57+
.stderrShouldContain("Error(s) while processing classes")
5458
.stderrShouldContain("Error while processing method")
5559
.stderrShouldContain("missingsystem.App::main(String[])void")
56-
.stderrShouldContain("CAUSED BY:")
5760
.stderrShouldContain("System class can not be found")
58-
.stderrShouldContain("java.lang.Compiler");
61+
.stderrShouldContain("java.lang.Compiler")
62+
.stderrAsLines();
63+
64+
assertEquals(2, stderr.size(), "Unexpected number of lines in stderr");
5965
}
6066
}

‎test/langtools/tools/jnativescan/cases/classpath/missingsystem/App.java

+1
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,6 @@ public static void main(String[] args) {
2828
// if we compile with --release 20, but run jnativescan
2929
// with --release 21, we should get an error
3030
java.lang.Compiler.enable();
31+
java.lang.Compiler.enable(); // should be de-duplicated in the error logs
3132
}
3233
}

0 commit comments

Comments
 (0)