8304502: Classfile API class hierarchy makes assumptions when class is not resolved

Reviewed-by: jpai
This commit is contained in:
Adam Sotona 2023-03-22 06:13:34 +00:00
parent 0deb648985
commit 0156909ab3
4 changed files with 13 additions and 13 deletions

View file

@ -45,9 +45,6 @@ public final class ClassHierarchyImpl {
private final ClassHierarchyResolver resolver;
//defer initialization of logging until needed
private static System.Logger logger;
/**
* Public constructor of <code>ClassHierarchyImpl</code> accepting instances of <code>ClassHierarchyInfoResolver</code> to resolve individual class streams.
* @param classHierarchyResolver <code>ClassHierarchyInfoResolver</code> instance
@ -59,12 +56,7 @@ public final class ClassHierarchyImpl {
private ClassHierarchyResolver.ClassHierarchyInfo resolve(ClassDesc classDesc) {
var res = resolver.getClassInfo(classDesc);
if (res != null) return res;
//maybe throw an exception here to avoid construction of potentially invalid stack maps
if (logger == null)
logger = System.getLogger("jdk.internal.classfile");
if (logger.isLoggable(System.Logger.Level.DEBUG))
logger.log(System.Logger.Level.DEBUG, "Could not resolve class " + classDesc.displayName());
return new ClassHierarchyResolver.ClassHierarchyInfo(classDesc, false, null);
throw new IllegalArgumentException("Could not resolve class " + classDesc.displayName());
}
/**
@ -173,10 +165,15 @@ public final class ClassHierarchyImpl {
}
public static final class StaticClassHierarchyResolver implements ClassHierarchyResolver {
private static final ClassHierarchyInfo CHI_Object =
new ClassHierarchyInfo(ConstantDescs.CD_Object, false, null);
private final Map<ClassDesc, ClassHierarchyInfo> map;
public StaticClassHierarchyResolver(Collection<ClassDesc> interfaceNames, Map<ClassDesc, ClassDesc> classToSuperClass) {
map = new HashMap<>(interfaceNames.size() + classToSuperClass.size());
map = HashMap.newHashMap(interfaceNames.size() + classToSuperClass.size() + 1);
map.put(ConstantDescs.CD_Object, CHI_Object);
for (var e : classToSuperClass.entrySet())
map.put(e.getKey(), new ClassHierarchyInfo(e.getKey(), false, e.getValue()));
for (var i : interfaceNames)

View file

@ -116,7 +116,7 @@ class AdvancedTransformationsTest {
var clm = Classfile.parse(in.readAllBytes());
var remapped = Classfile.parse(ClassRemapper.of(map).remapClass(clm));
assertEmpty(remapped.verify(
ClassHierarchyResolver.of(Set.of(), Map.of(
ClassHierarchyResolver.of(Set.of(ClassDesc.of("remapped.List")), Map.of(
ClassDesc.of("remapped.RemappedBytecode"), ConstantDescs.CD_Object,
ClassDesc.ofDescriptor(RawBytecodeHelper.class.descriptorString()), ClassDesc.of("remapped.RemappedBytecode")))
.orElse(ClassHierarchyResolver.DEFAULT_CLASS_HIERARCHY_RESOLVER)

View file

@ -50,7 +50,7 @@ class ClassHierarchyInfoTest {
@Test
public void testProduceInvalidStackMaps() throws Exception {
assertThrows(VerifyError.class, () -> transformAndVerify(className -> null));
assertThrows(IllegalArgumentException.class, () -> transformAndVerify(className -> null));
}
@Test
@ -60,6 +60,7 @@ class ClassHierarchyInfoTest {
ConstantDescs.CD_Collection),
Map.of(ClassDesc.of("java.util.HashMap$TreeNode"), ClassDesc.of("java.util.HashMap$Node"),
ClassDesc.of("java.util.HashMap$Node"), ConstantDescs.CD_Object,
ClassDesc.of("java.util.HashMap$EntrySet"), ClassDesc.of("java.util.AbstractSet"),
ClassDesc.of("java.util.HashMap$Values"), ConstantDescs.CD_Object)));
}

View file

@ -35,6 +35,7 @@ import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.stream.Stream;
import jdk.internal.classfile.ClassHierarchyResolver;
import jdk.internal.classfile.Classfile;
import jdk.internal.classfile.CodeModel;
import jdk.internal.classfile.MethodModel;
@ -62,7 +63,8 @@ class VerifierSelfTest {
@Test
void testFailedDump() throws IOException {
Path path = FileSystems.getFileSystem(URI.create("jrt:/")).getPath("modules/java.base/java/util/HashMap.class");
var classModel = Classfile.parse(path, Classfile.Option.classHierarchyResolver(className -> null));
var classModel = Classfile.parse(path, Classfile.Option.classHierarchyResolver(
className -> new ClassHierarchyResolver.ClassHierarchyInfo(className, false, null)));
byte[] brokenClassBytes = classModel.transform(
(clb, cle) -> {
if (cle instanceof MethodModel mm) {