8255342: Remove non-specified JVM checks on Classes with Record attributes

Reviewed-by: dholmes, coleenp
This commit is contained in:
Harold Seigel 2020-10-27 12:23:14 +00:00
parent 767965046e
commit 18d9905c40
6 changed files with 353 additions and 43 deletions

@ -3900,19 +3900,11 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
_nest_host = class_info_index;
} else if (_major_version >= JAVA_14_VERSION) {
if (tag == vmSymbols::tag_record()) {
// Skip over Record attribute if not supported or if super class is
// not java.lang.Record.
if (supports_records() &&
cp->klass_name_at(_super_class_index) == vmSymbols::java_lang_Record()) {
if (supports_records()) { // Skip over Record attribute if not supported.
if (parsed_record_attribute) {
classfile_parse_error("Multiple Record attributes in class file %s", THREAD);
return;
}
// Check that class is final and not abstract.
if (!_access_flags.is_final() || _access_flags.is_abstract()) {
classfile_parse_error("Record attribute in non-final or abstract class file %s", THREAD);
return;
}
parsed_record_attribute = true;
record_attribute_start = cfs->current();
record_attribute_length = attribute_length;
@ -3922,15 +3914,9 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
// --enable-preview wasn't specified then a java.lang.UnsupportedClassVersionError
// exception would have been thrown.
ResourceMark rm(THREAD);
if (supports_records()) {
log_info(class, record)(
"Ignoring Record attribute in class %s because super type is not java.lang.Record",
_class_name->as_C_string());
} else {
log_info(class, record)(
"Ignoring Record attribute in class %s because class file version is not %d.65535",
_class_name->as_C_string(), JVM_CLASSFILE_MAJOR_VERSION);
}
log_info(class, record)(
"Ignoring Record attribute in class %s because class file version is not %d.65535",
_class_name->as_C_string(), JVM_CLASSFILE_MAJOR_VERSION);
}
cfs->skip_u1(attribute_length, CHECK);
} else if (_major_version >= JAVA_15_VERSION) {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -24,8 +24,8 @@
// This test was generated from this source and then modified:
// record recordNames(int x, String y) {}
// This test is a Record marked as abstract. It should result in a
// ClassFormatError exception.
// This test is a Record marked as abstract. Loading this class should
// not cause a ClassFormatError exception.
class abstractRecord {
0xCAFEBABE;
65535; // minor version

@ -25,7 +25,7 @@
* @test
* @summary test logging of reasons for ignoring Record attribute
* @library /test/lib
* @compile superNotJLRecord.jcod recordIgnoredVersion.jcod
* @compile recordIgnoredVersion.jcod
* @run driver ignoreRecordAttribute
*/
@ -37,14 +37,8 @@ public class ignoreRecordAttribute {
public static void main(String[] args) throws Exception {
String MAJOR_VERSION = Integer.toString(44 + Runtime.version().feature());
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("--enable-preview",
"-Xlog:class+record", "-Xshare:off", "superNotJLRecord");
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldContain("Ignoring Record attribute");
output.shouldContain("because super type is not java.lang.Record");
pb = ProcessTools.createJavaProcessBuilder("--enable-preview",
"-Xlog:class+record", "-Xshare:off", "recordIgnoredVersion");
output = new OutputAnalyzer(pb.start());
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldContain("Ignoring Record attribute");
output.shouldContain("because class file version is not " + MAJOR_VERSION + ".65535");
}

@ -24,8 +24,8 @@
// This test was generated from this source and then modified:
// record recordNames(int x, String y) {}
// This test is a Record but not marked final. It should result in a
// ClassFormatError exception.
// This test is a Record but not marked final. Loading this class should
// not cause a ClassFormatError exception.
class notFinalRecord {
0xCAFEBABE;
65535; // minor version

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -54,13 +54,11 @@ public class recordAttributeTest {
runTest("twoRecordAttributes",
"Multiple Record attributes in class");
// Test loading a Record type marked abstract. This should throw ClassFormatError.
runTest("abstractRecord",
"Record attribute in non-final or abstract class");
// Test loading a Record type marked abstract. This should not throw ClassFormatError.
Class abstractClass = Class.forName("abstractRecord");
// Test loading a Record type that is not final. This should throw ClassFormatError.
runTest("notFinalRecord",
"Record attribute in non-final or abstract class");
// Test loading a Record type that is not final. This should not throw ClassFormatError.
Class notFinalClass = Class.forName("notFinalRecord");
// Test loading a Record type that is badly formed. This should throw ClassFormatError.
runTest("badRecordAttribute",
@ -73,8 +71,13 @@ public class recordAttributeTest {
// badly formed Record attribute. No exception should be thrown.
Class newClass = Class.forName("oldRecordAttribute");
// Test that loading a class whose super class is not java.lang.Record
// ignores a badly formed Record attribute. No exception should be thrown.
newClass = Class.forName("superNotJLRecord");
// Test that loading a class containing an ill-formed Record attribute causes a
// ClassFormatError exception even though its super class is not java.lang.Record.
runTest("superNotJLRecord", "Truncated class file");
// Test that loading a class that contains a properly formed Record attribute
// does not cause a ClassFormatError exception even though its super class is not
// java.lang.Record.
Class superNoJLRClass = Class.forName("superNotJLRecordOK");
}
}

@ -24,8 +24,9 @@
// This test was generated from this source and then modified:
// record recordNames(int x, String y) {}
// This test has a Record attribute that is too short but its super class is
// not java.lang.Record. So, the bogus Record attribute should be ignored.
// This test has a Record attribute that is too short and its super class is
// not java.lang.Record. The bad Record attribute should still be detected
// causing a ClassFormatError exception.
class superNotJLRecord {
0xCAFEBABE;
65535; // minor version
@ -343,3 +344,329 @@ class superNotJLRecord {
} // end Record
} // Attributes
} // end class superNotJLRecord
// This test was generated from this source and then modified:
// record recordNames(int x, String y) {}
//
// This class has a valid Record attribute but its super class is
// not java.lang.Record. Loading this class should not cause a
// ClassFormatError exception.
class superNotJLRecordOK {
0xCAFEBABE;
65535; // minor version
60; // version
[69] { // Constant Pool
; // first element is empty
Method #2 #3; // #1 at 0x0A
class #4; // #2 at 0x0F
NameAndType #5 #6; // #3 at 0x12
Utf8 "java/lang/Object"; // #4 at 0x17
Utf8 "<init>"; // #5 at 0x2A
Utf8 "()V"; // #6 at 0x33
Field #8 #9; // #7 at 0x39
class #10; // #8 at 0x3E
NameAndType #11 #12; // #9 at 0x41
Utf8 "superNotJLRecordOK"; // #10 at 0x46
Utf8 "x"; // #11 at 0x56
Utf8 "I"; // #12 at 0x5A
Field #8 #14; // #13 at 0x5E
NameAndType #15 #16; // #14 at 0x63
Utf8 "y"; // #15 at 0x68
Utf8 "Ljava/lang/String;"; // #16 at 0x6C
InvokeDynamic 0s #18; // #17 at 0x81
NameAndType #19 #20; // #18 at 0x86
Utf8 "toString"; // #19 at 0x8B
Utf8 "(LsuperNotJLRecordOK;)Ljava/lang/String;"; // #20 at 0x96
InvokeDynamic 0s #22; // #21 at 0xBC
NameAndType #23 #24; // #22 at 0xC1
Utf8 "hashCode"; // #23 at 0xC6
Utf8 "(LsuperNotJLRecordOK;)I"; // #24 at 0xD1
InvokeDynamic 0s #26; // #25 at 0xE6
NameAndType #27 #28; // #26 at 0xEB
Utf8 "equals"; // #27 at 0xF0
Utf8 "(LsuperNotJLRecordOK;Ljava/lang/Object;)Z"; // #28 at 0xF9
Dynamic 1s #30; // #29 at 0x0120
NameAndType #31 #32; // #30 at 0x0125
Utf8 "\\%pattern\\%recordExample\\%(ILjava\\|lang\\|String\\?)"; // #31 at 0x012A
Utf8 "Ljava/lang/runtime/PatternHandle;"; // #32 at 0x015F
Utf8 "(ILjava/lang/String;)V"; // #33 at 0x0183
Utf8 "Code"; // #34 at 0x019C
Utf8 "LineNumberTable"; // #35 at 0x01A3
Utf8 "MethodParameters"; // #36 at 0x01B5
Utf8 "()Ljava/lang/String;"; // #37 at 0x01C8
Utf8 "()I"; // #38 at 0x01DF
Utf8 "(Ljava/lang/Object;)Z"; // #39 at 0x01E5
Utf8 "()Ljava/lang/runtime/PatternHandle;"; // #40 at 0x01FD
Utf8 "SourceFile"; // #41 at 0x0223
Utf8 "superNotJLRecordOK.java"; // #42 at 0x0230
Utf8 "Record"; // #43 at 0x0245
Utf8 "BootstrapMethods"; // #44 at 0x024E
MethodHandle 6b #46; // #45 at 0x0261
Method #47 #48; // #46 at 0x0265
class #49; // #47 at 0x026A
NameAndType #50 #51; // #48 at 0x026D
Utf8 "java/lang/runtime/ObjectMethods"; // #49 at 0x0272
Utf8 "bootstrap"; // #50 at 0x029A
Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;"; // #51 at 0x02A6
String #53; // #52 at 0x035A
Utf8 "x;y"; // #53 at 0x035D
MethodHandle 1b #7; // #54 at 0x0363
MethodHandle 1b #13; // #55 at 0x0367
MethodHandle 6b #57; // #56 at 0x036B
Method #58 #59; // #57 at 0x036F
class #60; // #58 at 0x0374
NameAndType #61 #62; // #59 at 0x0377
Utf8 "java/lang/runtime/PatternHandles"; // #60 at 0x037C
Utf8 "ofLazyProjection"; // #61 at 0x039F
Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;Ljava/lang/Class;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/runtime/PatternHandle;"; // #62 at 0x03B2
Utf8 "InnerClasses"; // #63 at 0x0453
class #65; // #64 at 0x0462
Utf8 "java/lang/invoke/MethodHandles$Lookup"; // #65 at 0x0465
class #67; // #66 at 0x048D
Utf8 "java/lang/invoke/MethodHandles"; // #67 at 0x0490
Utf8 "Lookup"; // #68 at 0x04B1
} // Constant Pool
0x0030; // access [ ACC_SUPER ACC_FINAL ]
#8;// this_cpx
#2;// super_cpx
[0] { // Interfaces
} // Interfaces
[2] { // fields
{ // Member at 0x04C4
0x8012; // access
#11; // name_cpx
#12; // sig_cpx
[0] { // Attributes
} // Attributes
} // Member
;
{ // Member at 0x04CC
0x8012; // access
#15; // name_cpx
#16; // sig_cpx
[0] { // Attributes
} // Attributes
} // Member
} // fields
[7] { // methods
{ // Member at 0x04D6
0x0001; // access
#5; // name_cpx
#33; // sig_cpx
[2] { // Attributes
Attr(#34, 39) { // Code at 0x04DE
2; // max_stack
3; // max_locals
Bytes[15]{
0x2AB700012A1BB500;
0x072A2CB5000DB1;
}
[0] { // Traps
} // end Traps
[1] { // Attributes
Attr(#35, 6) { // LineNumberTable at 0x04FF
[1] { // LineNumberTable
0 1; // at 0x050B
}
} // end LineNumberTable
} // Attributes
} // end Code
;
Attr(#36, 9) { // MethodParameters at 0x050B
0x02000B8000000F80;
0x00;
} // end MethodParameters
} // Attributes
} // Member
;
{ // Member at 0x051A
0x8001; // access
#19; // name_cpx
#37; // sig_cpx
[1] { // Attributes
Attr(#34, 31) { // Code at 0x0522
1; // max_stack
1; // max_locals
Bytes[7]{
0x2ABA00110000B0;
}
[0] { // Traps
} // end Traps
[1] { // Attributes
Attr(#35, 6) { // LineNumberTable at 0x053B
[1] { // LineNumberTable
0 1; // at 0x0547
}
} // end LineNumberTable
} // Attributes
} // end Code
} // Attributes
} // Member
;
{ // Member at 0x0547
0x8011; // access
#23; // name_cpx
#38; // sig_cpx
[1] { // Attributes
Attr(#34, 31) { // Code at 0x054F
1; // max_stack
1; // max_locals
Bytes[7]{
0x2ABA00150000AC;
}
[0] { // Traps
} // end Traps
[1] { // Attributes
Attr(#35, 6) { // LineNumberTable at 0x0568
[1] { // LineNumberTable
0 1; // at 0x0574
}
} // end LineNumberTable
} // Attributes
} // end Code
} // Attributes
} // Member
;
{ // Member at 0x0574
0x8011; // access
#27; // name_cpx
#39; // sig_cpx
[1] { // Attributes
Attr(#34, 32) { // Code at 0x057C
2; // max_stack
2; // max_locals
Bytes[8]{
0x2A2BBA00190000AC;
}
[0] { // Traps
} // end Traps
[1] { // Attributes
Attr(#35, 6) { // LineNumberTable at 0x0596
[1] { // LineNumberTable
0 1; // at 0x05A2
}
} // end LineNumberTable
} // Attributes
} // end Code
} // Attributes
} // Member
;
{ // Member at 0x05A2
0x8001; // access
#11; // name_cpx
#38; // sig_cpx
[1] { // Attributes
Attr(#34, 29) { // Code at 0x05AA
1; // max_stack
1; // max_locals
Bytes[5]{
0x2AB40007AC;
}
[0] { // Traps
} // end Traps
[1] { // Attributes
Attr(#35, 6) { // LineNumberTable at 0x05C1
[1] { // LineNumberTable
0 1; // at 0x05CD
}
} // end LineNumberTable
} // Attributes
} // end Code
} // Attributes
} // Member
;
{ // Member at 0x05CD
0x8001; // access
#15; // name_cpx
#37; // sig_cpx
[1] { // Attributes
Attr(#34, 29) { // Code at 0x05D5
1; // max_stack
1; // max_locals
Bytes[5]{
0x2AB4000DB0;
}
[0] { // Traps
} // end Traps
[1] { // Attributes
Attr(#35, 6) { // LineNumberTable at 0x05EC
[1] { // LineNumberTable
0 1; // at 0x05F8
}
} // end LineNumberTable
} // Attributes
} // end Code
} // Attributes
} // Member
;
{ // Member at 0x05F8
0x0009; // access
#31; // name_cpx
#40; // sig_cpx
[1] { // Attributes
Attr(#34, 27) { // Code at 0x0600
1; // max_stack
0; // max_locals
Bytes[3]{
0x121DB0;
}
[0] { // Traps
} // end Traps
[1] { // Attributes
Attr(#35, 6) { // LineNumberTable at 0x0615
[1] { // LineNumberTable
0 1; // at 0x0621
}
} // end LineNumberTable
} // Attributes
} // end Code
} // Attributes
} // Member
} // methods
[4] { // Attributes
Attr(#41, 2) { // SourceFile at 0x0623
#42;
} // end SourceFile
;
Attr(#43, 14) { // Record at 0x062B
0x0002000B000C0000;
0x000F00100000;
} // end Record
;
Attr(#44, 24) { // BootstrapMethods at 0x063F
[2] { // bootstrap_methods
{ // bootstrap_method
#45; // bootstrap_method_ref
[4] { // bootstrap_arguments
#8; // at 0x064D
#52; // at 0x064F
#54; // at 0x0651
#55; // at 0x0653
} // bootstrap_arguments
} // bootstrap_method
;
{ // bootstrap_method
#56; // bootstrap_method_ref
[3] { // bootstrap_arguments
#8; // at 0x0659
#54; // at 0x065B
#55; // at 0x065D
} // bootstrap_arguments
} // bootstrap_method
}
} // end BootstrapMethods
;
Attr(#63, 10) { // InnerClasses at 0x065D
[1] { // InnerClasses
#64 #66 #68 25; // at 0x066D
}
} // end InnerClasses
} // Attributes
} // end class superNotJLRecordOK