Why does this code sometimes produce ArrayOutOfBoundsException? How is that even possible for String.valueOf(int)
?
public static String ipToString(B
I am leaving the code snippet here, as it still ought to be run faster than the original code - at a cost of memory - but be advised it doesn't actually fix the problem.
private static final String[] STRING_CACHE = new String[256];
static {
for(int i = 0; i <= 255; i++) {
STRING_CACHE[i] = String.valueOf(i);
}
}
public static String ipToString(ByteString bs) {
if (bs == null || bs.isEmpty()) {
return null;
} else {
StringBuilder sb = new StringBuilder();
boolean started = false;
for (Byte byt : bs) {
if (started) {
sb.append(".");
}
sb.append(STRING_CACHE[byt & 0xFF]);
started = true;
}
return sb.toString();
}
}
This is a JIT compiler bug that has been introduced in JDK 8u20 as a side-effect of another fix:
JDK-8042786
The problem is related to auto-boxing elimination optimization.
The work-around is to switch the optimization off by -XX:-EliminateAutoBox
JVM flag
Looks like the problem also exists in the most recent JDK 9 source base.
I've submitted the bug report: https://bugs.openjdk.java.net/browse/JDK-8058847 with 100% reproducible minimal test case included.
I can reliably reproduce your issue with this code:
public class Main
{
public static StringBuilder intToString(byte[] bs) {
final StringBuilder sb = new StringBuilder();
boolean started = false;
for (Byte byt : bs) {
if (started) sb.append(".");
sb.append(String.valueOf(byt & 0xFF));
started = true;
}
return sb;
}
public static void main(String[] args) {
final byte[] bs = {-2, -1, 0, 1, 2};
while (true) intToString(bs);
}
}
The issue will almost certainly be traced to a JIT compiler bug. Your observation that, once it happens the first time, it happens reliably on every subsequent call, points cleanly to a JIT compilation event which introduces the buggy code into the codepath.
If that's available to you, you could activate diagnostic JVM options which will print all compilation events (-XX:PrintCompilation
). Then you may be able to correlate such an event with the moment when the exception starts appearing.