-
Bug
-
Resolution: Unresolved
-
P4
-
None
-
8
-
x86_64
-
windows
ADDITIONAL SYSTEM INFORMATION :
OS:
Operating System Name: Windows 11
Operating System Architecture: amd64
Operating System Version: 10.0
OpenJDK version:
java version "1.8.0_441"
Java(TM) SE Runtime Environment (build 1.8.0_441-b07)
Java HotSpot(TM) 64-Bit Server VM (build 25.441-b07, mixed mode)
java version "11.0.26" 2025-01-21 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.26+7-LTS-187)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.26+7-LTS-187, mixed mode)
A DESCRIPTION OF THE PROBLEM :
Given a test case, we found that the execution results of this test case on different versions are different, the simplified test case can be found below. In summary, Hotspot(1.8.0_441) threw IncompatibleClassChangeError while the other ran normally.
REGRESSION : Last worked in version 8
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
The following code can be used to generate the test cases(.class file) that reproduces the above process:
```java
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class BytecodeUtil {
public static void main(String args[]) {
// create package
String baseDir = "./your_dir"; // your base dir
String packageName = "P0";
File folder = new File(baseDir + "/" + packageName);
folder.mkdirs();
String P0_I0_bytecodeInStr = "CAFEBABE00000034001C01000550302F49300700010100106A6176612F6C616E672F4F626A6563740700030100016D01001528294C6A6176612F6C616E672F496E74656765723B0100116A6176612F6C616E672F496E746567657207000703000000000100063C696E69743E010004284929560C000A000B0A0008000C0100047465737401000950302F48656C70657207000F010005676574433101000928294C50302F43313B0C001100120A001000130C000500060B000200150100046D61696E010016285B4C6A6176612F6C616E672F537472696E673B29560C000E00060B00020019010004436F64650601000200040000000000030002000500060001001B00000016000300010000000ABB0008591209B7000DB0000000000009000E00060001001B00000017000100010000000BB800144B2AB900160100B0000000000009001700180001001B000000100001000100000004B8001AB1000000000000" ;
String P0_C1_bytecodeInStr = "CAFEBABE00000034000C01000550302F43310700010100106A6176612F6C616E672F4F626A65637407000301000550302F49300700050100063C696E69743E0100032829560C000700080A00040009010004436F646500210002000400010006000000010001000700080001000B0000001100010001000000052AB7000AB1000000000000" ;
String P0_Helper_bytecodeInStr = "CAFEBABE00000034000F01000950302F48656C7065720700010100106A6176612F6C616E672F4F626A6563740700030100063C696E69743E0100032829560C000500060A00040007010005676574433101000928294C50302F43313B01000550302F433107000B0A000C0007010004436F64650021000200040000000000020001000500060001000E0000001100010001000000052AB70008B10000000000090009000A0001000E00000016000200010000000ABB000C59B7000D4B2AB0000000000000" ;
try (FileOutputStream fos = new FileOutputStream(folder.getAbsolutePath() + "/" + "I0.class")) {
byte[] P0_I0_bytecode = hexStringToByteArray(P0_I0_bytecodeInStr);
fos.write(P0_I0_bytecode);
} catch (IOException e) {
e.printStackTrace();
}
try (FileOutputStream fos = new FileOutputStream(folder.getAbsolutePath() + "/" + "C1.class")) {
byte[] P0_I0_bytecode = hexStringToByteArray(P0_C1_bytecodeInStr);
fos.write(P0_I0_bytecode);
} catch (IOException e) {
e.printStackTrace();
}
try (FileOutputStream fos = new FileOutputStream(folder.getAbsolutePath() + "/" + "Helper.class")) {
byte[] P0_Helper_bytecode = hexStringToByteArray(P0_Helper_bytecodeInStr);
fos.write(P0_Helper_bytecode);
} catch (IOException e) {
e.printStackTrace();
}
}
public static byte[] hexStringToByteArray(String hexString) {
int length = hexString.length();
byte[] byteArray = new byte[length / 2];
for (int i = 0; i < length; i += 2) {
int byteValue = Integer.parseInt(hexString.substring(i, i + 2), 16);
byteArray[i / 2] = (byte) byteValue;
}
return byteArray;
}
}
```
Note: modify the paths according to your needs.
Repoduce:
>>> path_to_jdk/Hotspot_1.8.0_441/bin/java -cp . P0.I0
>>> path_to_jdk/Hotspot_11.0.26/bin/java -cp . P0.I0
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
According to this result, we decompiled P0.I0 using javap. The results are as follows:
```
Classfile /D:/Lab/TestJDoc/JSmith-main/log/jvm-test/openj9-8/InvokeInterfaceSuccessTest/case_0/P0/I0.class
Last modified May 9, 2025; size 353 bytes
MD5 checksum 4cd47bd2dfdf95f618b9f18b955f9bf8
public interface P0.I0
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
Constant pool:
#1 = Utf8 P0/I0
#2 = Class #1 // P0/I0
#3 = Utf8 java/lang/Object
#4 = Class #3 // java/lang/Object
#5 = Utf8 m
#6 = Utf8 ()Ljava/lang/Integer;
#7 = Utf8 java/lang/Integer
#8 = Class #7 // java/lang/Integer
#9 = Integer 0
#10 = Utf8 <init>
#11 = Utf8 (I)V
#12 = NameAndType #10:#11 // "<init>":(I)V
#13 = Methodref #8.#12 // java/lang/Integer."<init>":(I)V
#14 = Utf8 test
#15 = Utf8 P0/Helper
#16 = Class #15 // P0/Helper
#17 = Utf8 getC1
#18 = Utf8 ()LP0/C1;
#19 = NameAndType #17:#18 // getC1:()LP0/C1;
#20 = Methodref #16.#19 // P0/Helper.getC1:()LP0/C1;
#21 = NameAndType #5:#6 // m:()Ljava/lang/Integer;
#22 = InterfaceMethodref #2.#21 // P0/I0.m:()Ljava/lang/Integer;
#23 = Utf8 main
#24 = Utf8 ([Ljava/lang/String;)V
#25 = NameAndType #14:#6 // test:()Ljava/lang/Integer;
#26 = InterfaceMethodref #2.#25 // P0/I0.test:()Ljava/lang/Integer;
#27 = Utf8 Code
{
public static java.lang.Integer test();
descriptor: ()Ljava/lang/Integer;
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=1, args_size=0
0: invokestatic #20 // Method P0/Helper.getC1:()LP0/C1;
3: astore_0
4: aload_0
5: invokeinterface #22, 1 // InterfaceMethod m:()Ljava/lang/Integer;
10: areturn
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=1, args_size=1
0: invokestatic #26 // InterfaceMethod test:()Ljava/lang/Integer;
3: return
}
```
We observe that the call to var0.m() in P0/I0.test() uses invokeinterface. Therefore, we referred to the sections on invokeinterface in both JVM SE8 and JVM SE11. According to JVM SE11: “Otherwise, if step 1 or step 2 of the lookup procedure selects a method that is not public, invokeinterface throws an IllegalAccessError.”
This indicates that the expected result for this test case in Hotspot(1.8.0_441) should be the throwing of an IllegalAccessError, rather than the IncompatibleClassChangeError shown in the output.
ACTUAL -
Hotspot(1.8.0_441):
```
Exception in thread "main" java.lang.IncompatibleClassChangeError: private interface method requires invokespecial, not invokeinterface: method P0.I0.m()Ljava/lang/Integer;
at P0.I0.test(Unknown Source)
at P0.I0.main(Unknown Source)
```
Hotspot(11.0.26) ran normally.
---------- BEGIN SOURCE ----------
After running BytecodeUtil.main() to get the test cases, you can derive the following test cases through decompilation:
```java
package P0;
public class C1 implements I0 {
public C1() {
}
}
```
```java
package P0;
public class Helper {
public Helper() {
}
public static C1 getC1() {
C1 var0 = new C1();
return var0;
}
}
```
```java
package P0;
public interface I0 {
private Integer m() {
return new Integer(0);
}
static Integer test() {
C1 var0 = Helper.getC1();
return var0.m();
}
static void main(String[] var0) {
test();
}
}
```
---------- END SOURCE ----------
OS:
Operating System Name: Windows 11
Operating System Architecture: amd64
Operating System Version: 10.0
OpenJDK version:
java version "1.8.0_441"
Java(TM) SE Runtime Environment (build 1.8.0_441-b07)
Java HotSpot(TM) 64-Bit Server VM (build 25.441-b07, mixed mode)
java version "11.0.26" 2025-01-21 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.26+7-LTS-187)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.26+7-LTS-187, mixed mode)
A DESCRIPTION OF THE PROBLEM :
Given a test case, we found that the execution results of this test case on different versions are different, the simplified test case can be found below. In summary, Hotspot(1.8.0_441) threw IncompatibleClassChangeError while the other ran normally.
REGRESSION : Last worked in version 8
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
The following code can be used to generate the test cases(.class file) that reproduces the above process:
```java
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class BytecodeUtil {
public static void main(String args[]) {
// create package
String baseDir = "./your_dir"; // your base dir
String packageName = "P0";
File folder = new File(baseDir + "/" + packageName);
folder.mkdirs();
String P0_I0_bytecodeInStr = "CAFEBABE00000034001C01000550302F49300700010100106A6176612F6C616E672F4F626A6563740700030100016D01001528294C6A6176612F6C616E672F496E74656765723B0100116A6176612F6C616E672F496E746567657207000703000000000100063C696E69743E010004284929560C000A000B0A0008000C0100047465737401000950302F48656C70657207000F010005676574433101000928294C50302F43313B0C001100120A001000130C000500060B000200150100046D61696E010016285B4C6A6176612F6C616E672F537472696E673B29560C000E00060B00020019010004436F64650601000200040000000000030002000500060001001B00000016000300010000000ABB0008591209B7000DB0000000000009000E00060001001B00000017000100010000000BB800144B2AB900160100B0000000000009001700180001001B000000100001000100000004B8001AB1000000000000" ;
String P0_C1_bytecodeInStr = "CAFEBABE00000034000C01000550302F43310700010100106A6176612F6C616E672F4F626A65637407000301000550302F49300700050100063C696E69743E0100032829560C000700080A00040009010004436F646500210002000400010006000000010001000700080001000B0000001100010001000000052AB7000AB1000000000000" ;
String P0_Helper_bytecodeInStr = "CAFEBABE00000034000F01000950302F48656C7065720700010100106A6176612F6C616E672F4F626A6563740700030100063C696E69743E0100032829560C000500060A00040007010005676574433101000928294C50302F43313B01000550302F433107000B0A000C0007010004436F64650021000200040000000000020001000500060001000E0000001100010001000000052AB70008B10000000000090009000A0001000E00000016000200010000000ABB000C59B7000D4B2AB0000000000000" ;
try (FileOutputStream fos = new FileOutputStream(folder.getAbsolutePath() + "/" + "I0.class")) {
byte[] P0_I0_bytecode = hexStringToByteArray(P0_I0_bytecodeInStr);
fos.write(P0_I0_bytecode);
} catch (IOException e) {
e.printStackTrace();
}
try (FileOutputStream fos = new FileOutputStream(folder.getAbsolutePath() + "/" + "C1.class")) {
byte[] P0_I0_bytecode = hexStringToByteArray(P0_C1_bytecodeInStr);
fos.write(P0_I0_bytecode);
} catch (IOException e) {
e.printStackTrace();
}
try (FileOutputStream fos = new FileOutputStream(folder.getAbsolutePath() + "/" + "Helper.class")) {
byte[] P0_Helper_bytecode = hexStringToByteArray(P0_Helper_bytecodeInStr);
fos.write(P0_Helper_bytecode);
} catch (IOException e) {
e.printStackTrace();
}
}
public static byte[] hexStringToByteArray(String hexString) {
int length = hexString.length();
byte[] byteArray = new byte[length / 2];
for (int i = 0; i < length; i += 2) {
int byteValue = Integer.parseInt(hexString.substring(i, i + 2), 16);
byteArray[i / 2] = (byte) byteValue;
}
return byteArray;
}
}
```
Note: modify the paths according to your needs.
Repoduce:
>>> path_to_jdk/Hotspot_1.8.0_441/bin/java -cp . P0.I0
>>> path_to_jdk/Hotspot_11.0.26/bin/java -cp . P0.I0
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
According to this result, we decompiled P0.I0 using javap. The results are as follows:
```
Classfile /D:/Lab/TestJDoc/JSmith-main/log/jvm-test/openj9-8/InvokeInterfaceSuccessTest/case_0/P0/I0.class
Last modified May 9, 2025; size 353 bytes
MD5 checksum 4cd47bd2dfdf95f618b9f18b955f9bf8
public interface P0.I0
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
Constant pool:
#1 = Utf8 P0/I0
#2 = Class #1 // P0/I0
#3 = Utf8 java/lang/Object
#4 = Class #3 // java/lang/Object
#5 = Utf8 m
#6 = Utf8 ()Ljava/lang/Integer;
#7 = Utf8 java/lang/Integer
#8 = Class #7 // java/lang/Integer
#9 = Integer 0
#10 = Utf8 <init>
#11 = Utf8 (I)V
#12 = NameAndType #10:#11 // "<init>":(I)V
#13 = Methodref #8.#12 // java/lang/Integer."<init>":(I)V
#14 = Utf8 test
#15 = Utf8 P0/Helper
#16 = Class #15 // P0/Helper
#17 = Utf8 getC1
#18 = Utf8 ()LP0/C1;
#19 = NameAndType #17:#18 // getC1:()LP0/C1;
#20 = Methodref #16.#19 // P0/Helper.getC1:()LP0/C1;
#21 = NameAndType #5:#6 // m:()Ljava/lang/Integer;
#22 = InterfaceMethodref #2.#21 // P0/I0.m:()Ljava/lang/Integer;
#23 = Utf8 main
#24 = Utf8 ([Ljava/lang/String;)V
#25 = NameAndType #14:#6 // test:()Ljava/lang/Integer;
#26 = InterfaceMethodref #2.#25 // P0/I0.test:()Ljava/lang/Integer;
#27 = Utf8 Code
{
public static java.lang.Integer test();
descriptor: ()Ljava/lang/Integer;
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=1, args_size=0
0: invokestatic #20 // Method P0/Helper.getC1:()LP0/C1;
3: astore_0
4: aload_0
5: invokeinterface #22, 1 // InterfaceMethod m:()Ljava/lang/Integer;
10: areturn
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=1, args_size=1
0: invokestatic #26 // InterfaceMethod test:()Ljava/lang/Integer;
3: return
}
```
We observe that the call to var0.m() in P0/I0.test() uses invokeinterface. Therefore, we referred to the sections on invokeinterface in both JVM SE8 and JVM SE11. According to JVM SE11: “Otherwise, if step 1 or step 2 of the lookup procedure selects a method that is not public, invokeinterface throws an IllegalAccessError.”
This indicates that the expected result for this test case in Hotspot(1.8.0_441) should be the throwing of an IllegalAccessError, rather than the IncompatibleClassChangeError shown in the output.
ACTUAL -
Hotspot(1.8.0_441):
```
Exception in thread "main" java.lang.IncompatibleClassChangeError: private interface method requires invokespecial, not invokeinterface: method P0.I0.m()Ljava/lang/Integer;
at P0.I0.test(Unknown Source)
at P0.I0.main(Unknown Source)
```
Hotspot(11.0.26) ran normally.
---------- BEGIN SOURCE ----------
After running BytecodeUtil.main() to get the test cases, you can derive the following test cases through decompilation:
```java
package P0;
public class C1 implements I0 {
public C1() {
}
}
```
```java
package P0;
public class Helper {
public Helper() {
}
public static C1 getC1() {
C1 var0 = new C1();
return var0;
}
}
```
```java
package P0;
public interface I0 {
private Integer m() {
return new Integer(0);
}
static Integer test() {
C1 var0 = Helper.getC1();
return var0.m();
}
static void main(String[] var0) {
test();
}
}
```
---------- END SOURCE ----------