Openj9: Unexpected java.lang.ArrayIndexOutOfBoundsException when running with -XX:+CompactStrings

Created on 30 Jan 2021  路  3Comments  路  Source: eclipse/openj9

Java -version output

openjdk version "11.0.9" 2020-10-20
OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.9+11)
Eclipse OpenJ9 VM AdoptOpenJDK (build openj9-0.23.0, JRE 11 Linux amd64-64-Bit Compressed References 20201022_810 (JIT enabled, AOT enabled)
OpenJ9 - 0394ef754
OMR - 582366ae5
JCL - 3b09cfd7e9 based on jdk-11.0.9+11)

Summary of problem

I have a program that never normally crashes, but when I run it with -XX:+CompactStrings I get a fairly-reproducible crash.

java.lang.ArrayIndexOutOfBoundsException: null
at com.ibm.jit.JITHelpers.getCharFromArrayByIndex(JITHelpers.java:523) ~[?:?]
at java.lang.String.decompressedArrayCopy(String.java:352) ~[?:?]
at java.lang.String.(String.java:674) ~[?:?]
at xxx.MultilineTextHelper.getTextLines(MultilineTextHelper.java:120) ~[xxx.jar:?]
at xxx.MultilineTextHelper.getTextLines(MultilineTextHelper.java:86) ~[xxx.jar:?]

The line that this fails on (120) is:
newLine = fullNormalizedText.substring(baseOffset, newOffset) + '\u205e';

Diagnostic files

Program doesn't crash. It just produces incorrect results.

Diagnosis

What I think is happening is that after a while the optimiser kicks in and notices the "string + character" initialiser for the string, and converts it to new String(String s, char c). In my case s is an ASCII string, of roughly 400 bytes.

Line 674 now corresponds to https://github.com/eclipse/openj9/blob/0ad4ed91031ecc8d8daa16dac4d9a484c78747b2/jcl/src/java.base/share/classes/java/lang/String.java#L721 , but things start to go wrong on https://github.com/eclipse/openj9/blob/0ad4ed91031ecc8d8daa16dac4d9a484c78747b2/jcl/src/java.base/share/classes/java/lang/String.java#L710.

What I believe is happening is that s.coder == LATIN1, however c <= 255 is false, since c is '\u205e'. So we go to the else block. This allocates an byte array big enough to hold 400 characters, aka 800 bytes, and then calls decompressedArrayCopy(s.value, 0, value, 0, slen);. However this expects to copy from an uncompressed array to an uncompressed array. What it ends up doing is copying from a compressed array to an uncompressed array. Roughly half way through, it runs out of source bytes and throws the ArrayIndexOutOfBoundsException.

I'm not sure what the exact resolution should be, but there should either be a compressedToDecompressedArrayCopy method, and that should be used, or the array needs to be decompressed before copying.

vm userRaised

Most helpful comment

Yes, it seems we should be calling decompress in the else path to decompress the compressed string, and then we need to copy c into the buffer. @dchopra001 could you look into providing a fix for this? Let's also check the other private constructors to ensure the same issue does not exist.

Here is an example in another private constructor where do decompress:
https://github.com/eclipse/openj9/blob/0ad4ed91031ecc8d8daa16dac4d9a484c78747b2/jcl/src/java.base/share/classes/java/lang/String.java#L986-L991

All 3 comments

@fjeremic fyi

Yes, it seems we should be calling decompress in the else path to decompress the compressed string, and then we need to copy c into the buffer. @dchopra001 could you look into providing a fix for this? Let's also check the other private constructors to ensure the same issue does not exist.

Here is an example in another private constructor where do decompress:
https://github.com/eclipse/openj9/blob/0ad4ed91031ecc8d8daa16dac4d9a484c78747b2/jcl/src/java.base/share/classes/java/lang/String.java#L986-L991

I'll tentatively tag this for the 0.25 milestone as there should be time to get a fix in before the release.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mpirvu picture mpirvu  路  6Comments

xliang6 picture xliang6  路  3Comments

pshipton picture pshipton  路  3Comments

xliang6 picture xliang6  路  6Comments

mikezhang1234567890 picture mikezhang1234567890  路  5Comments