JDK-8259961 : Exception message from arraycopy in JDK 11.0.5 is different from OpenJDK 8u232
  • Type: Bug
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 8
  • Priority: P3
  • Status: Closed
  • Resolution: Not an Issue
  • OS: linux
  • CPU: x86_64
  • Submitted: 2021-01-15
  • Updated: 2021-09-24
  • Resolved: 2021-09-24
Related Reports
Relates :  
Description
ADDITIONAL SYSTEM INFORMATION :
openjdk version "1.8.0_232"
OpenJDK Runtime Environment (build 1.8.0_232-b09)
OpenJDK 64-Bit Server VM (build 25.232-b09, mixed mode)

openjdk version "9.0.4"
OpenJDK Runtime Environment (build 9.0.4+11)
OpenJDK 64-Bit Server VM (build 9.0.4+11, mixed mode)

openjdk version "11.0.5" 2019-10-15
OpenJDK Runtime Environment 18.9 (build 11.0.5+10)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.5+10, mixed mode)


A DESCRIPTION OF THE PROBLEM :
We made some changes to a class file in the Apache Ant project, and let several JVMs execute the corresponding JUnit test. We found that in the third test case, J9(8u232), J9(9.0.4), J9(11.0.5), OpenJDK 11.0.5 threw an org.junit.ComparisonFailure while OpenJDK 8u232 and 9.0.4 threw a java.lang.AssertionError. After inspecting into the source code of JUnit, we found the JVM just executed the different path in the method `assertEquals` of `org.junit.Assert`(junit-4.12.jar):
```java
    static public void assertEquals(String message, Object expected,
            Object actual) {
        if (equalsRegardingNull(expected, actual)) {
            return;
        } else if (expected instanceof String && actual instanceof String) {
            String cleanMessage = message == null ? "" : message;
            throw new ComparisonFailure(cleanMessage, (String) expected, (String) actual);  // J9(8u232), J9(9.0.4), J9(11.0.5), OpenJDK 11.0.5 executed this line
        } else {
            failNotEquals(message, expected, actual);  // OpenJDK 8u232, 9.0.4 executed this line
        }
    }
```

Take OpenJDK (8u232-b09), J9 (8u232-b09) and OpenJDK(11.0.5) as an example:
OpenJDK (8u232-b09):
```
3) testParse(org.apache.tools.zip.ExtraFieldUtilsTest)
java.lang.AssertionError: message expected:<bad extra field starting at 18.  Block length of 1 bytes exceeds remaining data of 0 bytes.> but was:<null>
	at org.junit.Assert.fail(Assert.java:88)
	at org.junit.Assert.failNotEquals(Assert.java:834)
	at org.junit.Assert.assertEquals(Assert.java:118)
	at org.apache.tools.zip.ExtraFieldUtilsTest.testParse(ExtraFieldUtilsTest.java:91)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        ...
```
J9 (8u232-b09):
```
3) testParse(org.apache.tools.zip.ExtraFieldUtilsTest)
org.junit.ComparisonFailure: message expected:<[bad extra field starting at 18.  Block length of 1 bytes exceeds remaining data of 0 bytes.]> but was:<[Array index out of range: 22]>
	at org.junit.Assert.assertEquals(Assert.java:115)
	at org.apache.tools.zip.ExtraFieldUtilsTest.testParse(ExtraFieldUtilsTest.java:91)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        ...
```

OpenJDK(11.0.5)
```
3) testParse(org.apache.tools.zip.ExtraFieldUtilsTest)
org.junit.ComparisonFailure: message expected:<[bad extra field starting at 18.  Block length of 1 bytes exceeds remaining data of 0 bytes.]> but was:<[arraycopy: last source index 23 out of bounds for byte[22]]>
        at org.junit.Assert.assertEquals(Assert.java:115)
        at org.apache.tools.zip.ExtraFieldUtilsTest.testParse(ExtraFieldUtilsTest.java:91)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        ...
```

REGRESSION : Last worked in version 8

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. download https://github.com/eclipse/openj9/files/5821001/DifferentExecutionPath.zip
2. extract the DifferentExecutionPath.zip
3. In directory DifferentExecutionPath, run command `java -cp sootOutput/junit-ant/:hamcrest-core-1.3.jar:junit-4.12.jar org.junit.runner.JUnitCore org.apache.tools.zip.ExtraFieldUtilsTest`

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
3) testParse(org.apache.tools.zip.ExtraFieldUtilsTest)
org.junit.ComparisonFailure: message expected:<[bad extra field starting at 18.  Block length of 1 bytes exceeds remaining data of 0 bytes.]> but was:<[Array index out of range: 22]>
	at org.junit.Assert.assertEquals(Assert.java:115)
	at org.apache.tools.zip.ExtraFieldUtilsTest.testParse(ExtraFieldUtilsTest.java:91)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        ...
ACTUAL -
3) testParse(org.apache.tools.zip.ExtraFieldUtilsTest)
java.lang.AssertionError: message expected:<bad extra field starting at 18.  Block length of 1 bytes exceeds remaining data of 0 bytes.> but was:<null>
	at org.junit.Assert.fail(Assert.java:88)
	at org.junit.Assert.failNotEquals(Assert.java:834)
	at org.junit.Assert.assertEquals(Assert.java:118)
	at org.apache.tools.zip.ExtraFieldUtilsTest.testParse(ExtraFieldUtilsTest.java:91)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        ...

---------- BEGIN SOURCE ----------
See Steps to Reproduce
---------- END SOURCE ----------

FREQUENCY : always



Comments
This is not a bug. The message "arraycopy: last source index 23 out of bounds for byte[22]" was introduced in JDK 11 by JDK-8201593 (Print array length in ArrayIndexOutOfBoundsException.). The test should not rely on the error message to be a specific value, since the content of the error message is not specified by the Java Language Spec.
24-09-2021

additional information from submitter: ================================================== After inspecting into the source code of JUnit, we found the JVM just executed the different path in the method `assertEquals` of `org.junit.Assert`(junit-4.12.jar): ```java static public void assertEquals(String message, Object expected, Object actual) { if (equalsRegardingNull(expected, actual)) { return; } else if (expected instanceof String && actual instanceof String) { String cleanMessage = message == null ? "" : message; throw new ComparisonFailure(cleanMessage, (String) expected, (String) actual); // J9 (8u275, 9.0.4, 11.0.9) and OpenJDK(11.0.9) executed this line } else { failNotEquals(message, expected, actual); // OpenJDK (8u275, 9.0.4) executed this line } } ``` I found that for openjdk8u275 and openjdk9.0.4, e.getMessage() returns null, while e.getMessage() of J9 returns `Array index out of range: 22`. But e.getMessage() should not be null. ==================================================
19-01-2021

Issue is reproduced. JDK 8u271 returns java.lang.AssertionError while JDK 11 and above return org.junit.ComparisonFailure for "3) testParse(org.apache.tools.zip.ExtraFieldUtilsTest)" OS: Oracle Linux(7.6.64.1) JDK 8u271 : Fail JDK 11.0.9 : Pass JDK 16ea32:Pass JDK 17ea5: Pass Output: =================================== JDK 8u271 3)testParse(org.apache.tools.zip.ExtraFieldUtilsTest) java.lang.AssertionError: message expected:<bad extra field starting at 18. Block length of 1 bytes exceeds remaining data of 0 bytes.> but was:<null> at org.junit.Assert.fail(Assert.java:88) at org.junit.Assert.failNotEquals(Assert.java:834) at org.junit.Assert.assertEquals(Assert.java:118) =================================== =================================== JDK 11.0.9 3) testParse(org.apache.tools.zip.ExtraFieldUtilsTest) org.junit.ComparisonFailure: message expected:<[bad extra field starting at 18. Block length of 1 bytes exceeds remaining data of 0 bytes.]> but was:<[arraycopy: last source index 23 out of bounds for byte[22]]> at org.junit.Assert.assertEquals(Assert.java:115) at org.apache.tools.zip.ExtraFieldUtilsTest.testParse(ExtraFieldUtilsTest.java:91) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) =================================== =================================== JDK 16+32 3) testParse(org.apache.tools.zip.ExtraFieldUtilsTest) org.junit.ComparisonFailure: message expected:<[bad extra field starting at 18. Block length of 1 bytes exceeds remaining data of 0 bytes.]> but was:<[arraycopy: last source index 23 out of bounds for byte[22]]> at org.junit.Assert.assertEquals(Assert.java:115) at org.apache.tools.zip.ExtraFieldUtilsTest.testParse(ExtraFieldUtilsTest.java:91) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:78) =================================== =================================== JDK-17+5 3) testParse(org.apache.tools.zip.ExtraFieldUtilsTest) org.junit.ComparisonFailure: message expected:<[bad extra field starting at 18. Block length of 1 bytes exceeds remaining data of 0 bytes.]> but was:<[arraycopy: last source index 23 out of bounds for byte[22]]> at org.junit.Assert.assertEquals(Assert.java:115) at org.apache.tools.zip.ExtraFieldUtilsTest.testParse(ExtraFieldUtilsTest.java:91) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:78) ==================================== Moving it to dev team for further analysis.
19-01-2021