Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Should OpenJ9 throw a verifyerror for my test class? #1404

Closed
myspringchen opened this issue Mar 9, 2018 · 11 comments
Closed

Should OpenJ9 throw a verifyerror for my test class? #1404

myspringchen opened this issue Mar 9, 2018 · 11 comments

Comments

@myspringchen
Copy link

I was recently confused by a test class. When run on OpenJDK's HotSpot, the class triggers a verify error; when run on OpenJ9, it triggers a class format error (JVMCFRE068). I wonder whether OpenJ9 throws an incorrect error here. (Some class variable is not correctly defined, while the format should be correct)

How to reproduce: download ATest.class/BTest.class (https://jbox.sjtu.edu.cn/l/WuCI1G) and run java ATest

OpenJ9:
Error: LinkageError occurred while loading main class ATest
java.lang.ClassFormatError: JVMCFRE068 class name is invalid; class=ATest, offset=0

HotSpot:
Exception in thread "main" java.lang.VerifyError: Bad local variable type
Exception Details:
Location:
ATest.put()V @9: aload_1
Reason:
Type top (current frame, locals[1]) is not assignable to reference type
Current Frame:
bci: @9
flags: { }
locals: { 'ATest' }
stack: { }
Bytecode:
0x0000000: 2ac7 0008 2ab4 000a 4c2b 0332 4b2a b400
0x0000010: 104b a7ff fb
Stackmap Table:
same_frame(@9)
full_frame(@13,{Object[#18]},{})

javap -verbose ATest.class

public class ATest
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Utf8 ATest
#2 = Class #1 // ATest
#3 = Utf8 java/lang/Object
#4 = Class #3 // java/lang/Object
#5 = Utf8 table
#6 = Utf8 [LBTest;
#7 = Utf8 put
#8 = Utf8 ()V
#9 = NameAndType #5:#6 // table:[LBTest;
#10 = Fieldref #2.#9 // ATest.table:[LBTest;
#11 = Utf8 BTest
#12 = Class #11 // BTest
#13 = Utf8 next
#14 = Utf8 LBTest;
#15 = NameAndType #13:#14 // next:LBTest;
#16 = Fieldref #12.#15 // BTest.next:LBTest;
#17 = Utf8 Ljava/lang/Object;
#18 = Class #17 // "Ljava/lang/Object;"
#19 = Utf8 Code
#20 = Utf8 StackMapTable
{
BTest[] table;
descriptor: [LBTest;
flags:

public void put();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=1
0: aload_0
1: ifnonnull 9
4: aload_0
5: getfield #10 // Field table:[LBTest;
8: astore_1
9: aload_1
10: iconst_0
11: aaload
12: astore_0
13: aload_0
14: getfield #16 // Field BTest.next:LBTest;
17: astore_0
18: goto 13
StackMapTable: number_of_entries = 2
frame_type = 9 /* same /
frame_type = 255 /
full_frame */
offset_delta = 3
locals = [ class "Ljava/lang/Object;" ]
stack = []
}

@myspringchen
Copy link
Author

Hi, in case that OpenJ9 correctly processes this corner case, please also let me know. :)

@myspringchen
Copy link
Author

I just got another test case. Run CTest.class on HotSpot and OpenJ9. OpenJ9 reports JVMCFRE068, while HotSpot reports a verify error (Inconsistent stackmap frames). Is JVMCFRE068 also related with verify errors (e.g., Bad local variable type/Inconsistent stackmap frames)?

OpenJ9:
Error: LinkageError occurred while loading main class CTest
java.lang.ClassFormatError: JVMCFRE068 class name is invalid; class=CTest, offset=0

HotSpot:
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.VerifyError: Inconsistent stackmap frames at branch target 23
Exception Details:
Location:
CTest.f2([Ljava/lang/String;)V @23: goto
Reason:
Type '[Ljava/lang/String;' (current frame, locals[0]) is not assignable to 'Ljava/lang/Object;' (stack map, locals[0])
Current Frame:
bci: @0
flags: { }
locals: { '[Ljava/lang/String;' }
stack: { }
Stackmap Frame:
bci: @23
flags: { }
locals: { 'Ljava/lang/Object;' }
stack: { }
Bytecode:
0x0000000: a700 17b8 000c 9a00 112a 0332 4bb1 4c2a
0x0000010: 0332 4cb8 000c 57a7 ffec
Exception Handler Table:
bci [3, 13] => handler: 14
Stackmap Table:
full_frame(@3,{Object[#14]},{})
same_locals_1_stack_item_frame(@14,Object[#10])
same_frame(@23)

at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
at java.lang.Class.privateGetMethodRecursive(Class.java:3048)
at java.lang.Class.getMethod0(Class.java:3018)
at java.lang.Class.getMethod(Class.java:1784)
at sun.launcher.LauncherHelper.validateMainClass(LauncherHelper.java:544)
at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:526)

javap -verbose CTest.class
public class CTest
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Utf8 CTest
#2 = Class #1 // CTest
#3 = Utf8 java/lang/Object
#4 = Class #3 // java/lang/Object
#5 = Utf8 f
#6 = Utf8 ()I
#7 = Utf8 f2
#8 = Utf8 ([Ljava/lang/String;)V
#9 = Utf8 java/lang/ClassNotFoundException
#10 = Class #9 // java/lang/ClassNotFoundException
#11 = NameAndType #5:#6 // f:()I
#12 = Methodref #2.#11 // CTest.f:()I
#13 = Utf8 Ljava/lang/Object;
#14 = Class #13 // "Ljava/lang/Object;"
#15 = Utf8 Code
#16 = Utf8 StackMapTable
{
static void f2(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_STATIC
Code:
stack=2, locals=2, args_size=1
0: goto 23
3: invokestatic #12 // Method f:()I
6: ifne 23
9: aload_0
10: iconst_0
11: aaload
12: astore_0
13: return
14: astore_1
15: aload_0
16: iconst_0
17: aaload
18: astore_1
19: invokestatic #12 // Method f:()I
22: pop
23: goto 3
Exception table:
from to target type
3 13 14 Class java/lang/ClassNotFoundException
StackMapTable: number_of_entries = 3
frame_type = 255 /* full_frame /
offset_delta = 3
locals = [ class "Ljava/lang/Object;" ]
stack = []
frame_type = 74 /
same_locals_1_stack_item /
stack = [ class java/lang/ClassNotFoundException ]
frame_type = 8 /
same */
}

@DanHeidinga
Copy link
Member

@pdbain-ibm Can you take a look at this?

@pdbain-ibm
Copy link
Contributor

@myspringchen would you please indicate which HotSpot build you used?

I tested with the latest build from OpenJDK:
$ java -version
openjdk version "9-internal"
OpenJDK Runtime Environment (build 9-internal+0-adhoc.jenkins.openjdk)
OpenJDK 64-Bit Server VM (build 9-internal+0-adhoc.jenkins.openjdk, mixed mode)

$ java ATest
Error: LinkageError occurred while loading main class ATest
java.lang.ClassFormatError: Illegal class name "Ljava/lang/Object;" in class file ATest

With OpenJ9:
$ java ATest
Error: LinkageError occurred while loading main class ATest
java.lang.ClassFormatError: JVMCFRE068 class name is invalid; class=ATest, offset=0

I get the same result with CTest. All tests use Java 9.

@pdbain-ibm
Copy link
Contributor

I do, however, see that HotSpot Java 8 has different behaviour:

$ jdk1.8.0_60/jre/bin/java ATest
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.VerifyError: Bad local variable type
Exception Details:

@myspringchen
Copy link
Author

Got the same format errors when HotSpot (build 9.0.4+11) is used, :)

It seems to be a minor defect in HotSpot for Java 8.

@pdbain-ibm
Copy link
Contributor

I believe the OpenJ9 behaviour is reasonable and correct.

The verifier is checking a classname "Ljava/lang/Object;" and throwing an error on the
semicolon. Semicolons are used for field descriptors and array classes.

bcvCheckClassName (J9CfrConstantPoolInfo * info) calls checkNameImpl(info, TRUE, FALSE);
checkNameImpl (J9CfrConstantPoolInfo * info, BOOLEAN isClass, BOOLEAN isMethod)
...
		case ';':
			if (isClass) { // TRUE
				/* Valid at the end of array classes */
				if (arity && ((c + 1) == end)) { // arity is 0, so false
					break;
				}
			}
			return -1;  // failure.

@DanHeidinga would you kindly check my findings? Thanks.

@pdbain-ibm
Copy link
Contributor

@myspringchen does this answer your question?
@DanHeidinga any comments?

Thanks

@myspringchen
Copy link
Author

@pdbain-ibm Thanks.
I reported this issue to java bug database (JDK-8199585). I guess some HotSpot versions (8uxx?) need to be fixed a little.

Regression details

8uxx - Pass
9 ea b136 - Pass
9 ea b137 - Fail --> Regression introduced here
9 GA - Fail
9.0.4 - Fail
10 ea b44 - Fail
11 ea b03 - Fail

This issue is introduced by JDK-8160699

@pdbain-ibm
Copy link
Contributor

Thank you. I suggest we close this issue as it seems to be a problem with OpenJDK Java 8 only.

@DanHeidinga
Copy link
Member

Thanks for the analysis on this @pdbain-ibm.

OpenJ9's behaviour is correct. There was OpenJDK changed their behaviour under https://bugs.java.com/view_bug.do?bug_id=JDK-8161224 to. Quoting:

 Enforce format checks for NameAndType strings 
This change enforces the unqualified name format checks for NameAndType strings as outlined in the JVM specification sections 4.4.6 and 4.2.2, meaning that some illegal names and descriptors that users may be utilizing in their classfiles will now be caught with a Class Format Error. This includes format checking for all strings under non-referenced NameAndType's. Users will see a change if they are using either:

(A) Java classfile version 6 or below and have an illegal NameAndType descriptor with no Methodref or Fieldref reference to it; or 
(B) Any Java classfile version and have an illegal NameAndType name with no Methodref or Fieldref reference to it

In both (A) and (B) the users will now receive a ClassFormatError for those illegal strings, which is an enforcement of unqualified name formats as delineated in JVMS 4.2.2.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants