How is ArrayOutOfBoundsException possible in String.valueOf(int)?

后端 未结 3 896
無奈伤痛
無奈伤痛 2021-02-05 03:30

Why does this code sometimes produce ArrayOutOfBoundsException? How is that even possible for String.valueOf(int)?

public static String ipToString(B         


        
相关标签:
3条回答
  • 2021-02-05 03:34

    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();
      }
    }
    
    0 讨论(0)
  • 2021-02-05 03:44

    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.

    0 讨论(0)
  • 2021-02-05 03:47

    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.

    0 讨论(0)
提交回复
热议问题