Skip to content

Correct error for putfield with static field before super()#23491

Draft
theresa-m wants to merge 1 commit intoeclipse-openj9:masterfrom
theresa-m:fix_strictinstancefieldstest
Draft

Correct error for putfield with static field before super()#23491
theresa-m wants to merge 1 commit intoeclipse-openj9:masterfrom
theresa-m:fix_strictinstancefieldstest

Conversation

@theresa-m
Copy link
Contributor

OpenJ9's behavior does not match the ri's error handling when trying to set a static field with the putfield bytecode before initializing the class's superclass. Example:

  public static int x;
    descriptor: I
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC

  public BadExample();
    descriptor: ()V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: iconst_5
         2: putfield      #10                 // Field x:I
         5: aload_0
         6: invokespecial #12                 // Method java/lang/Object."<init>":()V
         9: return

Case 1: applicable from Java 8+

ri throws an java.lang.IncompatibleClassChangeError

OpenJ9 throws

Exception in thread "main" java.lang.VerifyError: JVMVRFY021 thrown object not throwable; class=BadExample, method=<init>()V, pc=2
Exception Details:
  Location:
    BadExample.<init>()V @2: JBputfield
  Reason:
    Type 'uninitializedThis' (current frame, stack[0]) is not assignable to 'BadExample'
  Current Frame:
    bci: @2
    flags: { flagThisUninit }
    locals: { 'uninitializedThis' }
    stack: { 'uninitializedThis' }
	at Test.main(Test.java:4)

Case 2: strict static fields (Project Valhalla)

ri throws

Exception in thread "main" java.lang.VerifyError: Initializing unknown strict field: y:I
Exception Details:
  Location:
    StrictFieldNotSubset.<init>()V @2: putfield
  Reason:
    Invalid use of strict instance fields
  Current Frame:
    bci: @2
    flags: { flagThisUninit }
    locals: { uninitializedThis }
    stack: { uninitializedThis, integer }
  Bytecode:
    0000000: 2a04 b500 012a b700 02b1

OpenJ9 throws

Exception in thread "main" java.lang.VerifyError: JVMVRFY012 stack shape inconsistent; class=StrictFieldNotSubset, method=<init>()V, pc=2
Exception Details:
  Location:
    StrictFieldNotSubset.<init>()V @2: JBputfield
  Reason:
    Type 'uninitializedThis' (current frame, stack[0]) is not assignable to 'StrictFieldNotSubset'
  Current Frame:
    bci: @2
    flags: { flagThisUninit }
    locals: { 'uninitializedThis' }
    stack: { 'uninitializedThis' }
JavaTest Message: shutting down test

Solution

In order to handle this correctly static fields must be returned from findFieldFromCurrentRomClass. In case 1 this would allow static fields to bypass the verifier and in case 2 the field will be handled specially if it is strict.

With this change OpenJ9 throws java.lang.IncompatibleClassChangeError
for case 1 and the following for case 2:

JVMVRFY045 Initializing unknown strict field; class=StrictFieldNotSubset, method=<init>()V, pc=2
Exception Details:
  Location:
    StrictFieldNotSubset.<init>()V @2: JBputfield
  Reason:
    Invalid use of strict instance fields, field is static.
	at StrictInstanceFieldsTest.negativeTest(StrictInstanceFieldsTest.java:59)
	at StrictInstanceFieldsTest.main(StrictInstanceFieldsTest.java:110)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
	at java.base/java.lang.reflect.Method.invoke(Method.java:571)
	at com.sun.javatest.regtest.agent.MainMethodHelper.executeModernMainClass(MainMethodHelper.java:55)
	at com.sun.javatest.regtest.agent.MainWrapper$MainTask.run(MainWrapper.java:138)
	at java.base/java.lang.Thread.run(Thread.java:1538)

OpenJ9's behavior does not match the ri's error handling
when trying to set a static field with the putfield bytecode
before initializing the class's superclass. Example:

```
  public static int x;
    descriptor: I
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC

  public BadExample();
    descriptor: ()V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: iconst_5
         2: putfield      eclipse-openj9#10                 // Field x:I
         5: aload_0
         6: invokespecial eclipse-openj9#12                 // Method java/lang/Object."<init>":()V
         9: return
```

Case 1: applicable from Java 8+

ri throws an `java.lang.IncompatibleClassChangeError`

OpenJ9 throws
```
Exception in thread "main" java.lang.VerifyError: JVMVRFY021 thrown object not throwable; class=BadExample, method=<init>()V, pc=2
Exception Details:
  Location:
    BadExample.<init>()V @2: JBputfield
  Reason:
    Type 'uninitializedThis' (current frame, stack[0]) is not assignable to 'BadExample'
  Current Frame:
    bci: @2
    flags: { flagThisUninit }
    locals: { 'uninitializedThis' }
    stack: { 'uninitializedThis' }
	at Test.main(Test.java:4)
```
Case 2: strict static fields (Project Valhalla)

ri throws
```
Exception in thread "main" java.lang.VerifyError: Initializing unknown strict field: y:I
Exception Details:
  Location:
    StrictFieldNotSubset.<init>()V @2: putfield
  Reason:
    Invalid use of strict instance fields
  Current Frame:
    bci: @2
    flags: { flagThisUninit }
    locals: { uninitializedThis }
    stack: { uninitializedThis, integer }
  Bytecode:
    0000000: 2a04 b500 012a b700 02b1
```

OpenJ9 throws
```
Exception in thread "main" java.lang.VerifyError: JVMVRFY012 stack shape inconsistent; class=StrictFieldNotSubset, method=<init>()V, pc=2
Exception Details:
  Location:
    StrictFieldNotSubset.<init>()V @2: JBputfield
  Reason:
    Type 'uninitializedThis' (current frame, stack[0]) is not assignable to 'StrictFieldNotSubset'
  Current Frame:
    bci: @2
    flags: { flagThisUninit }
    locals: { 'uninitializedThis' }
    stack: { 'uninitializedThis' }
JavaTest Message: shutting down test
```

Solution

In order to handle this correctly static fields must be returned from findFieldFromCurrentRomClass.
In case 1 this would allow static fields to bypass the verifier and in case 2 the field
will be handled specially if it is strict.

With this change OpenJ9 throws `java.lang.IncompatibleClassChangeError`
 for case 1 and the following for case 2:
```
JVMVRFY045 Initializing unknown strict field; class=StrictFieldNotSubset, method=<init>()V, pc=2
Exception Details:
  Location:
    StrictFieldNotSubset.<init>()V @2: JBputfield
  Reason:
    Invalid use of strict instance fields, field is static.
	at StrictInstanceFieldsTest.negativeTest(StrictInstanceFieldsTest.java:59)
	at StrictInstanceFieldsTest.main(StrictInstanceFieldsTest.java:110)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
	at java.base/java.lang.reflect.Method.invoke(Method.java:571)
	at com.sun.javatest.regtest.agent.MainMethodHelper.executeModernMainClass(MainMethodHelper.java:55)
	at com.sun.javatest.regtest.agent.MainWrapper$MainTask.run(MainWrapper.java:138)
	at java.base/java.lang.Thread.run(Thread.java:1538)
```

Signed-off-by: Theresa Mammarella <Theresa.T.Mammarella@ibm.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp:vm project:valhalla Used to track Project Valhalla related work

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant