Skip to content

Commit

Permalink
work in progress
Browse files Browse the repository at this point in the history
  • Loading branch information
asotona committed Nov 27, 2023
1 parent a3a244f commit e51f45e
Show file tree
Hide file tree
Showing 2 changed files with 183 additions and 84 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import jdk.internal.classfile.Attribute;
import jdk.internal.classfile.AttributedElement;
Expand All @@ -39,6 +38,7 @@
import jdk.internal.classfile.FieldModel;
import jdk.internal.classfile.MethodModel;
import jdk.internal.classfile.attribute.*;
import jdk.internal.classfile.constantpool.*;
import jdk.internal.classfile.impl.BoundAttribute;

/**
Expand All @@ -48,10 +48,65 @@ public record ParserVerifier(ClassModel classModel) {

List<VerifyError> verify() {
var errors = new ArrayList<VerifyError>();
verifyConstantPool(errors);
verifyAttributes(classModel, errors);
return errors;
}

private void verifyConstantPool(List<VerifyError> errors) {
for (var cpe : classModel.constantPool()) try {
switch (cpe) {
case DoubleEntry de ->
de.doubleValue();
case FloatEntry fe ->
fe.floatValue();
case IntegerEntry ie ->
ie.intValue();
case LongEntry le ->
le.longValue();
case Utf8Entry ue ->
ue.stringValue();
case ConstantDynamicEntry cde ->
cde.asSymbol();
case InvokeDynamicEntry ide ->
ide.asSymbol();
case ClassEntry ce ->
ce.asSymbol();
case StringEntry se ->
se.stringValue();
case MethodHandleEntry mhe ->
mhe.asSymbol();
case MethodTypeEntry mte ->
mte.asSymbol();
case FieldRefEntry fre -> {
fre.owner().asSymbol();
fre.name().stringValue();
fre.typeSymbol();
}
case InterfaceMethodRefEntry imre -> {
imre.owner().asSymbol();
imre.name().stringValue();
imre.typeSymbol();
}
case MethodRefEntry mre -> {
mre.owner().asSymbol();
mre.name().stringValue();
mre.typeSymbol();
}
case ModuleEntry me ->
me.asSymbol();
case NameAndTypeEntry nate -> {
nate.name().stringValue();
nate.type().stringValue();
}
case PackageEntry pe ->
pe.asSymbol();
}
} catch (IllegalArgumentException iae) {
errors.add(new VerifyError("%s at constant pool index %d in %s".formatted(iae.getMessage(), cpe.index(), toString(classModel))));
}
}

private void verifyAttributes(ClassfileElement cfe, List<VerifyError> errors) {
if (cfe instanceof AttributedElement ae) {
var attrNames = new HashSet<String>();
Expand Down
210 changes: 127 additions & 83 deletions test/jdk/jdk/classfile/VerifierSelfTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@
*/
import java.io.IOException;
import java.lang.constant.ClassDesc;
import java.lang.constant.ConstantDesc;
import static java.lang.constant.ConstantDescs.*;
import java.lang.invoke.MethodHandleInfo;
import java.net.URI;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
Expand Down Expand Up @@ -97,6 +99,131 @@ void testFailedDump() throws IOException {
}
}

@Test
void testConstantPoolVerification() {
var cc = Classfile.of();
var cd_test = ClassDesc.of("ConstantPoolTestClass");
var clm = cc.parse(cc.build(cd_test, clb -> {
var cp = clb.constantPool();
var ce_valid = cp.classEntry(cd_test);
var ce_invalid = cp.classEntry(cp.utf8Entry("invalid.class.name"));
var nate_field = cp.nameAndTypeEntry("field", CD_int);
var nate_method = cp.nameAndTypeEntry(" method", MTD_void);
var bsme = cp.bsmEntry(BSM_INVOKE, List.of());
cp.methodTypeEntry(cp.utf8Entry("invalid method type"));
cp.constantDynamicEntry(bsme, nate_method);
cp.invokeDynamicEntry(bsme, nate_field);
cp.fieldRefEntry(ce_valid, nate_method);
cp.fieldRefEntry(ce_invalid, nate_field);
cp.methodRefEntry(ce_valid, nate_field);
cp.methodRefEntry(ce_invalid, nate_method);
cp.interfaceMethodRefEntry(ce_valid, nate_field);
cp.interfaceMethodRefEntry(ce_invalid, nate_method);
cp.methodHandleEntry(MethodHandleInfo.REF_getField, cp.methodRefEntry(cd_test, "method", MTD_void));
cp.methodHandleEntry(MethodHandleInfo.REF_invokeVirtual, cp.fieldRefEntry(cd_test, "field", CD_int));
}));
assertVerify(clm, """
Invalid class name: invalid.class.name at constant pool index 4 in class ConstantPoolTestClass
Bad method descriptor: invalid method type at constant pool index 19 in class ConstantPoolTestClass
not a valid reference type descriptor: ()V at constant pool index 20 in class ConstantPoolTestClass
Bad method descriptor: I at constant pool index 21 in class ConstantPoolTestClass
not a valid reference type descriptor: ()V at constant pool index 22 in class ConstantPoolTestClass
Invalid class name: invalid.class.name at constant pool index 23 in class ConstantPoolTestClass
Bad method descriptor: I at constant pool index 24 in class ConstantPoolTestClass
Invalid class name: invalid.class.name at constant pool index 25 in class ConstantPoolTestClass
Bad method descriptor: I at constant pool index 26 in class ConstantPoolTestClass
Invalid class name: invalid.class.name at constant pool index 27 in class ConstantPoolTestClass
not a valid reference type descriptor: ()V at constant pool index 31 in class ConstantPoolTestClass
Bad method descriptor: I at constant pool index 33 in class ConstantPoolTestClass
""");
}

@Test
void testAttributesVerification() {
var cc = Classfile.of();
var cd_test = ClassDesc.of("AttributesTestClass");
var clm = cc.parse(cc.build(cd_test, clb -> patch(clb,
DeprecatedAttribute.of(),
EnclosingMethodAttribute.of(cd_test, Optional.empty(), Optional.empty()),
InnerClassesAttribute.of(InnerClassInfo.of(cd_test, Optional.empty(), Optional.empty(), 0)),
NestHostAttribute.of(cd_test),
NestMembersAttribute.ofSymbols(cd_test),
PermittedSubclassesAttribute.ofSymbols(cd_test),
RecordAttribute.of(RecordComponentInfo.of("c", CD_String, patch(
SignatureAttribute.of(Signature.of(CD_String))))),
SignatureAttribute.of(ClassSignature.of(Signature.ClassTypeSig.of(cd_test))),
SourceFileAttribute.of("AttributesTestClass.java"),
SyntheticAttribute.of())
.withField("f", CD_String, fb -> patch(fb,
ConstantValueAttribute.of(""),
DeprecatedAttribute.of(),
SignatureAttribute.of(Signature.of(CD_String)),
SyntheticAttribute.of()))
.withMethod("m", MTD_void, 0, mb -> patch(mb,
DeprecatedAttribute.of(),
ExceptionsAttribute.ofSymbols(CD_Exception),
MethodParametersAttribute.of(MethodParameterInfo.ofParameter(Optional.empty(), 0)),
SignatureAttribute.of(MethodSignature.of(MTD_void)),
SyntheticAttribute.of())
.withCode(cob -> cob.return_()))

));
assertVerify(clm, """
Wrong Deprecated attribute length in class AttributesTestClass
Multiple EnclosingMethod attributes in class AttributesTestClass
Wrong EnclosingMethod attribute length in class AttributesTestClass
Multiple InnerClasses attributes in class AttributesTestClass
Wrong InnerClasses attribute length in class AttributesTestClass
Multiple NestHost attributes in class AttributesTestClass
Wrong NestHost attribute length in class AttributesTestClass
Multiple NestMembers attributes in class AttributesTestClass
Wrong NestMembers attribute length in class AttributesTestClass
Multiple PermittedSubclasses attributes in class AttributesTestClass
Wrong PermittedSubclasses attribute length in class AttributesTestClass
Multiple Record attributes in class AttributesTestClass
Wrong Record attribute length in class AttributesTestClass
Multiple Signature attributes in class AttributesTestClass
Wrong Signature attribute length in class AttributesTestClass
Multiple SourceFile attributes in class AttributesTestClass
Wrong SourceFile attribute length in class AttributesTestClass
Wrong Synthetic attribute length in class AttributesTestClass
Multiple ConstantValue attributes in field AttributesTestClass.f
Wrong ConstantValue attribute length in field AttributesTestClass.f
Wrong Deprecated attribute length in field AttributesTestClass.f
Multiple Signature attributes in field AttributesTestClass.f
Wrong Signature attribute length in field AttributesTestClass.f
Wrong Synthetic attribute length in field AttributesTestClass.f
Wrong Deprecated attribute length in method AttributesTestClass::m()
Multiple Exceptions attributes in method AttributesTestClass::m()
Wrong Exceptions attribute length in method AttributesTestClass::m()
Multiple MethodParameters attributes in method AttributesTestClass::m()
Wrong MethodParameters attribute length in method AttributesTestClass::m()
Multiple Signature attributes in method AttributesTestClass::m()
Wrong Signature attribute length in method AttributesTestClass::m()
Wrong Synthetic attribute length in method AttributesTestClass::m()
Multiple Signature attributes in Record component c of class AttributesTestClass
Wrong Signature attribute length in Record component c of class AttributesTestClass
Multiple Signature attributes in Record component c of class AttributesTestClass
Wrong Signature attribute length in Record component c of class AttributesTestClass
""");
}

private static void assertVerify(ClassModel clm, String errors) {
var found = clm.verify(null).stream().map(VerifyError::getMessage).collect(Collectors.toCollection(LinkedList::new));
var expected = errors.lines().filter(exp -> !found.remove(exp)).toList();
if (!found.isEmpty() || !expected.isEmpty()) {
ClassPrinter.toYaml(clm, ClassPrinter.Verbosity.TRACE_ALL, System.out::print);
fail(STR."""
Expected:
\{ expected.stream().collect(Collectors.joining("\n ")) }
Found:
\{ found.stream().collect(Collectors.joining("\n ")) }
""");
}
}

private static class CloneAttribute extends CustomAttribute<CloneAttribute> {
CloneAttribute(Attribute a) {
super(new AttributeMapper<CloneAttribute>(){
Expand Down Expand Up @@ -141,87 +268,4 @@ private static List<Attribute<?>> patch(Attribute... attrs) {
}
return lst;
}

@Test
void testParserVerifier() {

var cc = Classfile.of();
var cd_test = ClassDesc.of("TestParserVerifier");
var clm = cc.parse(cc.build(cd_test, clb -> patch(clb,
DeprecatedAttribute.of(),
EnclosingMethodAttribute.of(cd_test, Optional.empty(), Optional.empty()),
InnerClassesAttribute.of(InnerClassInfo.of(cd_test, Optional.empty(), Optional.empty(), 0)),
NestHostAttribute.of(cd_test),
NestMembersAttribute.ofSymbols(cd_test),
PermittedSubclassesAttribute.ofSymbols(cd_test),
RecordAttribute.of(RecordComponentInfo.of("c", CD_String, patch(
SignatureAttribute.of(Signature.of(CD_String))))),
SignatureAttribute.of(ClassSignature.of(Signature.ClassTypeSig.of(cd_test))),
SourceFileAttribute.of("TestParserVerifier.java"),
SyntheticAttribute.of())
.withField("f", CD_String, fb -> patch(fb,
ConstantValueAttribute.of(""),
DeprecatedAttribute.of(),
SignatureAttribute.of(Signature.of(CD_String)),
SyntheticAttribute.of()))
.withMethod("m", MTD_void, 0, mb -> patch(mb,
DeprecatedAttribute.of(),
ExceptionsAttribute.ofSymbols(CD_Exception),
MethodParametersAttribute.of(MethodParameterInfo.ofParameter(Optional.empty(), 0)),
SignatureAttribute.of(MethodSignature.of(MTD_void)),
SyntheticAttribute.of())
.withCode(cob -> cob.return_()))

));
var found = clm.verify(null).stream().map(VerifyError::getMessage).collect(Collectors.toCollection(LinkedList::new));
var expected = """
Wrong Deprecated attribute length in class TestParserVerifier
Multiple EnclosingMethod attributes in class TestParserVerifier
Wrong EnclosingMethod attribute length in class TestParserVerifier
Multiple InnerClasses attributes in class TestParserVerifier
Wrong InnerClasses attribute length in class TestParserVerifier
Multiple NestHost attributes in class TestParserVerifier
Wrong NestHost attribute length in class TestParserVerifier
Multiple NestMembers attributes in class TestParserVerifier
Wrong NestMembers attribute length in class TestParserVerifier
Multiple PermittedSubclasses attributes in class TestParserVerifier
Wrong PermittedSubclasses attribute length in class TestParserVerifier
Multiple Record attributes in class TestParserVerifier
Wrong Record attribute length in class TestParserVerifier
Multiple Signature attributes in class TestParserVerifier
Wrong Signature attribute length in class TestParserVerifier
Multiple SourceFile attributes in class TestParserVerifier
Wrong SourceFile attribute length in class TestParserVerifier
Wrong Synthetic attribute length in class TestParserVerifier
Multiple ConstantValue attributes in field TestParserVerifier.f
Wrong ConstantValue attribute length in field TestParserVerifier.f
Wrong Deprecated attribute length in field TestParserVerifier.f
Multiple Signature attributes in field TestParserVerifier.f
Wrong Signature attribute length in field TestParserVerifier.f
Wrong Synthetic attribute length in field TestParserVerifier.f
Wrong Deprecated attribute length in method TestParserVerifier::m()
Multiple Exceptions attributes in method TestParserVerifier::m()
Wrong Exceptions attribute length in method TestParserVerifier::m()
Multiple MethodParameters attributes in method TestParserVerifier::m()
Wrong MethodParameters attribute length in method TestParserVerifier::m()
Multiple Signature attributes in method TestParserVerifier::m()
Wrong Signature attribute length in method TestParserVerifier::m()
Wrong Synthetic attribute length in method TestParserVerifier::m()
Multiple Signature attributes in Record component c of class TestParserVerifier
Wrong Signature attribute length in Record component c of class TestParserVerifier
Multiple Signature attributes in Record component c of class TestParserVerifier
Wrong Signature attribute length in Record component c of class TestParserVerifier
""".lines().filter(exp -> !found.remove(exp)).toList();
if (!found.isEmpty() || !expected.isEmpty()) {
ClassPrinter.toYaml(clm, ClassPrinter.Verbosity.TRACE_ALL, System.out::print);
fail(STR."""
Expected:
\{ expected.stream().collect(Collectors.joining("\n ")) }
Found:
\{ found.stream().collect(Collectors.joining("\n ")) }
""");
}
}
}

0 comments on commit e51f45e

Please sign in to comment.