2012-06-21

HotSpot bug in Java 7u4, 7u5, 7u6(rc) with StringBuilder optimisation

I found an odd bug that seems to be related with the new Java7 optimisations regarding StringBuilder concatenation. The following code works, until HotSpot kicks in, and replaces the interpreted code with optimized code, after a few thousand iterations.

Code that corrupts the concatenated string when compiled with Eclipse:
public class Main {
 
        public static void main(String[] args) throws Exception {
 
                System.out.println("Java Version: " + System.getProperty("java.vm.version"));
 
                long[] durations = new long[60];
 
                for (int i = 0; true; i++) {

                        // this empty for-loop is required to reproduce this bug 
                        for (long duration : durations) {
                                // do nothing
                        }
 
                        {
                                String s = "test";
                                int len = s.length();
 
                                s = s + s;
                                len = len + len;
 
                                s = s + s;
                                len = len + len;
 
                                s = s + s;
                                len = len + len;
 
                                if (s.length() != len) {
                                        System.out.println("Failed at iteration: " + i);
                                        System.out.println("Length mismatch: " + s.length() + " <> " + len);
                                        System.out.println("Expected: \"" + "test" + "test" + "test" + "test" + "test" + "test" + "test" + "test" + "\"");
                                        System.out.println("Actual:   \"" + s + "\"");
                                        System.exit(0);
                                }
                        }
                }
        }
}


Code that corrupts the concatenated string when compiled with Javac:
public class Main {
 
        public static void main(String[] args) throws Exception {
 
                System.out.println("Java Version: " + System.getProperty("java.vm.version"));
 
                long[] durations = new long[60];
 
                for (int i = 0; true; i++) {
 
                        // this empty for-loop is required to reproduce this bug
                        for (long duration : durations) {
                                // do nothing
                        }
 
                        {
                                String s = "test";
                                int len = s.length();
 
                                s = new StringBuilder(String.valueOf(s)).append(s).toString();
                                len = len + len;
 
                                s = new StringBuilder(String.valueOf(s)).append(s).toString();
                                len = len + len;
 
                                s = new StringBuilder(String.valueOf(s)).append(s).toString();
                                len = len + len;
 
                                if (s.length() != len) {
                                        System.out.println("Failed at iteration: " + i);
                                        System.out.println("Length mismatch: " + s.length() + " <> " + len);
                                        System.out.println("Expected: \"" + "test" + "test" + "test" + "test" + "test" + "test" + "test" + "test" + "\"");
                                        System.out.println("Actual:   \"" + s + "\"");
                                        System.exit(0);
                                }
                        }
                }
        }
}


Output:
Java Version: 23.0-b21
Failed at iteration: 11983
Length mismatch: 16 <> 32
Expected: "testtesttesttesttesttesttesttest"
Actual:   "nullnulltesttest"

1 comment:

  1. Disable OptimizeStringConcat as a work around, i.e. add -XX:-OptimizeStringConcat. OptimizeStringConcat was enabled by default in 7u4. In previous versions it was disabled by default.

    ReplyDelete