8353840: JNativeScan should not abort for missing classes
Reviewed-by: jvernee, liach
This commit is contained in:
parent
1f21da75eb
commit
5f2a604b63
@ -42,15 +42,17 @@ import java.util.zip.ZipFile;
|
|||||||
class JNativeScanTask {
|
class JNativeScanTask {
|
||||||
|
|
||||||
private final PrintWriter out;
|
private final PrintWriter out;
|
||||||
|
private final PrintWriter err;
|
||||||
private final List<Path> classPaths;
|
private final List<Path> classPaths;
|
||||||
private final List<Path> modulePaths;
|
private final List<Path> modulePaths;
|
||||||
private final List<String> cmdRootModules;
|
private final List<String> cmdRootModules;
|
||||||
private final Runtime.Version version;
|
private final Runtime.Version version;
|
||||||
private final Action action;
|
private final Action action;
|
||||||
|
|
||||||
public JNativeScanTask(PrintWriter out, List<Path> classPaths, List<Path> modulePaths,
|
public JNativeScanTask(PrintWriter out, PrintWriter err, List<Path> classPaths, List<Path> modulePaths,
|
||||||
List<String> cmdRootModules, Runtime.Version version, Action action) {
|
List<String> cmdRootModules, Runtime.Version version, Action action) {
|
||||||
this.out = out;
|
this.out = out;
|
||||||
|
this.err = err;
|
||||||
this.classPaths = classPaths;
|
this.classPaths = classPaths;
|
||||||
this.modulePaths = modulePaths;
|
this.modulePaths = modulePaths;
|
||||||
this.version = version;
|
this.version = version;
|
||||||
@ -71,10 +73,13 @@ class JNativeScanTask {
|
|||||||
toScan.add(new ClassFileSource.Module(m.reference()));
|
toScan.add(new ClassFileSource.Module(m.reference()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Set<String> errors = new LinkedHashSet<>();
|
||||||
|
Diagnostics diagnostics = (context, error) ->
|
||||||
|
errors.add("Error while processing method: " + context + ": " + error.getMessage());
|
||||||
SortedMap<ClassFileSource, SortedMap<ClassDesc, List<RestrictedUse>>> allRestrictedMethods;
|
SortedMap<ClassFileSource, SortedMap<ClassDesc, List<RestrictedUse>>> allRestrictedMethods;
|
||||||
try(ClassResolver classesToScan = ClassResolver.forClassFileSources(toScan, version);
|
try(ClassResolver classesToScan = ClassResolver.forClassFileSources(toScan, version);
|
||||||
ClassResolver systemClassResolver = ClassResolver.forSystemModules(version)) {
|
ClassResolver systemClassResolver = ClassResolver.forSystemModules(version)) {
|
||||||
NativeMethodFinder finder = NativeMethodFinder.create(classesToScan, systemClassResolver);
|
NativeMethodFinder finder = NativeMethodFinder.create(diagnostics, classesToScan, systemClassResolver);
|
||||||
allRestrictedMethods = finder.findAll();
|
allRestrictedMethods = finder.findAll();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
@ -82,7 +87,7 @@ class JNativeScanTask {
|
|||||||
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case PRINT -> printNativeAccess(allRestrictedMethods);
|
case PRINT -> printNativeAccess(allRestrictedMethods);
|
||||||
case DUMP_ALL -> dumpAll(allRestrictedMethods);
|
case DUMP_ALL -> dumpAll(allRestrictedMethods, errors);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,7 +161,7 @@ class JNativeScanTask {
|
|||||||
out.println(nativeAccess);
|
out.println(nativeAccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void dumpAll(SortedMap<ClassFileSource, SortedMap<ClassDesc, List<RestrictedUse>>> allRestrictedMethods) {
|
private void dumpAll(SortedMap<ClassFileSource, SortedMap<ClassDesc, List<RestrictedUse>>> allRestrictedMethods, Set<String> errors) {
|
||||||
if (allRestrictedMethods.isEmpty()) {
|
if (allRestrictedMethods.isEmpty()) {
|
||||||
out.println(" <no restricted methods>");
|
out.println(" <no restricted methods>");
|
||||||
} else {
|
} 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 {
|
private static boolean isJarFile(Path path) throws JNativeScanFatalError {
|
||||||
@ -192,4 +201,8 @@ class JNativeScanTask {
|
|||||||
String packagePrefix = desc.packageName().isEmpty() ? "" : desc.packageName() + ".";
|
String packagePrefix = desc.packageName().isEmpty() ? "" : desc.packageName() + ".";
|
||||||
return packagePrefix + desc.displayName();
|
return packagePrefix + desc.displayName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Diagnostics {
|
||||||
|
void error(MethodRef context, JNativeScanFatalError error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -165,7 +165,7 @@ public class Main {
|
|||||||
action = JNativeScanTask.Action.PRINT;
|
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 {
|
private static String[] expandArgFiles(String[] args) throws JNativeScanFatalError {
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.sun.tools.jnativescan;
|
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.NativeMethodDecl;
|
||||||
import com.sun.tools.jnativescan.RestrictedUse.RestrictedMethodRefs;
|
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 static final String RESTRICTED_NAME = "Ljdk/internal/javac/Restricted+Annotation;";
|
||||||
|
|
||||||
private final Map<MethodRef, Boolean> cache = new HashMap<>();
|
private final Map<MethodRef, Boolean> cache = new HashMap<>();
|
||||||
|
private final Diagnostics diagnostics;
|
||||||
private final ClassResolver classesToScan;
|
private final ClassResolver classesToScan;
|
||||||
private final ClassResolver systemClassResolver;
|
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.classesToScan = classesToScan;
|
||||||
this.systemClassResolver = systemClassResolver;
|
this.systemClassResolver = systemClassResolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static NativeMethodFinder create(ClassResolver classesToScan, ClassResolver systemClassResolver) throws JNativeScanFatalError, IOException {
|
public static NativeMethodFinder create(Diagnostics diagnostics, ClassResolver classesToScan,
|
||||||
return new NativeMethodFinder(classesToScan, systemClassResolver);
|
ClassResolver systemClassResolver) throws JNativeScanFatalError, IOException {
|
||||||
|
return new NativeMethodFinder(diagnostics, classesToScan, systemClassResolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SortedMap<ClassFileSource, SortedMap<ClassDesc, List<RestrictedUse>>> findAll() throws JNativeScanFatalError {
|
public SortedMap<ClassFileSource, SortedMap<ClassDesc, List<RestrictedUse>>> findAll() throws JNativeScanFatalError {
|
||||||
@ -68,23 +72,22 @@ class NativeMethodFinder {
|
|||||||
} else {
|
} else {
|
||||||
SortedSet<MethodRef> perMethod = new TreeSet<>(Comparator.comparing(MethodRef::toString));
|
SortedSet<MethodRef> perMethod = new TreeSet<>(Comparator.comparing(MethodRef::toString));
|
||||||
methodModel.code().ifPresent(code -> {
|
methodModel.code().ifPresent(code -> {
|
||||||
try {
|
code.forEach(e -> {
|
||||||
code.forEach(e -> {
|
switch (e) {
|
||||||
switch (e) {
|
case InvokeInstruction invoke -> {
|
||||||
case InvokeInstruction invoke -> {
|
MethodRef ref = MethodRef.ofInvokeInstruction(invoke);
|
||||||
MethodRef ref = MethodRef.ofInvokeInstruction(invoke);
|
try {
|
||||||
if (isRestrictedMethod(ref)) {
|
if (isRestrictedMethod(ref)) {
|
||||||
perMethod.add(ref);
|
perMethod.add(ref);
|
||||||
}
|
}
|
||||||
}
|
} catch (JNativeScanFatalError ex) {
|
||||||
default -> {
|
diagnostics.error(MethodRef.ofModel(methodModel), ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
default -> {
|
||||||
} catch (JNativeScanFatalError e) {
|
}
|
||||||
throw new JNativeScanFatalError("Error while processing method: " +
|
}
|
||||||
MethodRef.ofModel(methodModel), e);
|
});
|
||||||
}
|
|
||||||
});
|
});
|
||||||
if (!perMethod.isEmpty()) {
|
if (!perMethod.isEmpty()) {
|
||||||
perClass.add(new RestrictedMethodRefs(MethodRef.ofModel(methodModel), perMethod));
|
perClass.add(new RestrictedMethodRefs(MethodRef.ofModel(methodModel), perMethod));
|
||||||
|
@ -35,6 +35,9 @@ import org.junit.jupiter.api.Test;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
public class TestMissingSystemClass extends JNativeScanTestBase {
|
public class TestMissingSystemClass extends JNativeScanTestBase {
|
||||||
|
|
||||||
@ -49,12 +52,15 @@ public class TestMissingSystemClass extends JNativeScanTestBase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSingleJarClassPath() {
|
public void testSingleJarClassPath() {
|
||||||
assertFailure(jnativescan("--class-path", MISSING_SYSTEM.toString(), "--release", "21"))
|
List<String> stderr = assertSuccess(jnativescan("--class-path", MISSING_SYSTEM.toString(), "--release", "21"))
|
||||||
.stdoutShouldBeEmpty()
|
.stdoutShouldContain("<no restricted methods>")
|
||||||
|
.stderrShouldContain("Error(s) while processing classes")
|
||||||
.stderrShouldContain("Error while processing method")
|
.stderrShouldContain("Error while processing method")
|
||||||
.stderrShouldContain("missingsystem.App::main(String[])void")
|
.stderrShouldContain("missingsystem.App::main(String[])void")
|
||||||
.stderrShouldContain("CAUSED BY:")
|
|
||||||
.stderrShouldContain("System class can not be found")
|
.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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,5 +28,6 @@ public class App {
|
|||||||
// if we compile with --release 20, but run jnativescan
|
// if we compile with --release 20, but run jnativescan
|
||||||
// with --release 21, we should get an error
|
// with --release 21, we should get an error
|
||||||
java.lang.Compiler.enable();
|
java.lang.Compiler.enable();
|
||||||
|
java.lang.Compiler.enable(); // should be de-duplicated in the error logs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user