JDK-7179138 : Incorrect result with String concatenation optimization
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: hs24
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2012-06-22
  • Updated: 2013-09-04
  • Resolved: 2012-07-03
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 7 JDK 8 Other
7u40Fixed 8Fixed hs23.2Fixed
Description
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"

Posted by Riven at 4:09 PM
On Jun 22, 2012, at 9:12 AM, Damjan Jovanovic wrote:

> > In JDK 1.7.0_04 amd64 and 1.7.0_05 x86, both on Ubuntu 12.04 amd64:
> > 
> > -XX:+OptimizeStringConcat reproduces the bug in the Javac example from
> > http://riven8192.blogspot.com/2012/06/hotspot-bug-in-java-7u4-7u5-7u6rc-with.html
> > -XX:-OptimizeStringConcat works correctly (it should infinite loop)
> > 
> > Regards
> > 
> > On Fri, Jun 22, 2012 at 3:47 PM, Charlie Hunt <###@###.###> wrote:
>> >> Could you try your experiment with -XX:-OptimizeStringConcat to see if the
>> >> unexpected behavior goes away?
>> >> 
>> >> IIRC, -XX:+OptimizeStringConcat was made the default in 7u4.
>> >> 
>> >> charlie ...
>> >> 
>> >> On Jun 21, 2012, at 4:39 PM, Skip Balk wrote:
>> >> 
>> >> Dear HotSpot developers,
>> >> 
>> >> 
>> >> This is the first time I post anything on any mailinglist, so please forgive
>> >> me if my message is not quite up to the standards you are used to.
>> >> 
>> >> Last week, I encountered a bug in simple String concatenation, like:
>> >> 
>> >> String s = "test";
>> >>     s = s+s;
>> >>     s = s+s;
>> >>     s = s+s;
>> >> 
>> >> yielding the string: "nullnulltesttest" instead of
>> >> "testtesttesttesttesttesttesttest". The first Java version that seems to
>> >> suffer from this bug is Java 7u4, and is confirmed to occur in 7u5, 7u6(rc).
>> >> It has been further reproduced on 32bit, 64bit, clientvm and servervm.
>> >> 
>> >> After a few thousand (interpreted) runs of this code, it starts to give
>> >> these incorrect results, leading me to assume that a HotSpot optimisation is
>> >> the root cause of this problem, which is backed by the fact that when
>> >> running the java process with the -Xint argument, the bug does not occur.
>> >> 
>> >> Unfortunately, today I discovered that with my trivial sourcecode, the issue
>> >> only occured with the Eclipse compiler. The Javac output seemed to be
>> >> 'friendly' to HotSpot.
>> >> 
>> >> Upon further investigation, it turned out that "s=s+s" was compiled to
>> >> different bytecode by Javac and Eclipse:
>> >>     Eclipse: s = new StringBuilder(String.valueOf(s)).append(s).toString();
>> >>     Javac:   s = new StringBuilder().append(s).append(s).toString();
>> >> When writing the version Eclipse produces in Java sourcecode, the javac
>> >> compiler also produced the bytecode that made HotSpot trip.
>> >> 
>> >> Without further ado: here are the full code-dumps (both for eclipse and
>> >> javac)
>> >>     http://riven8192.blogspot.com/2012/06/hotspot-bug-in-java-7u4-7u5-7u6rc-with.html
>> >> 
>> >> "javap -c" output, with sourcecode containing "s=s+s"
>> >>     Javac:   http://pastebin.com/raw.php?i=pC3kRC6c
>> >>     Eclipse: http://pastebin.com/raw.php?i=Pbj0fyZ8
>> >> 
>> >> Console output:
>> >>     Java Version: 23.0-b21
>> >>     Failed at iteration: 11983
>> >>     Length mismatch: 16 <> 32
>> >>     Expected: "testtesttesttesttesttesttesttest"
>> >>     Actual:   "nullnulltesttest"
>> >> 
>> >> Last but not least, this bug seems to be triggered by the empty-for-loop,
>> >> which leads me to believe this is a case of too aggresive dead code removal.
>> >> I hope you can
>> >> 
>> >> 
>> >> With kind regards,
>> >>     Riven (http://www.java-gaming.org/ administrator)
>> >> 
>> >>

Comments
Closed as already verified during 7u40 bug verification process.
31-07-2013

EVALUATION http://hg.openjdk.java.net/lambda/lambda/hotspot/rev/751bd303aa45
29-06-2012

EVALUATION http://hg.openjdk.java.net/hsx/hsx23.2/hotspot/rev/cfb193817fec
28-06-2012

EVALUATION http://hg.openjdk.java.net/hsx/hotspot-comp/hotspot/rev/751bd303aa45
26-06-2012