JDK-8204322 : "+=" applied to String operands can provoke side effects
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 9,10,11
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: x86_64
  • Submitted: 2018-06-04
  • Updated: 2022-02-24
  • Resolved: 2018-06-06
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 10 JDK 11
10.0.2Fixed 11 b17Fixed
Related Reports
Relates :  
Description
ADDITIONAL SYSTEM INFORMATION :
OS: Windows, Unix
Java: all versions of Java 9+

A DESCRIPTION OF THE PROBLEM :
When using the += operator, it seems that javac duplicates the code before the +=.

Example:

array[i++%n] += i + " ";

This code is compiled as if it were:

array[i++%n] = array[i++%n] + i + " ";

REGRESSION : Last worked in version 8u172

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run and execute the source code for the executable test

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
1 4 7 10 13 16 19 22 25 28 31 34 37 40 43 46 49 52 55 58 61 64 67 70 73 76 79 82 85 88 91 94 97 100 
2 5 8 11 14 17 20 23 26 29 32 35 38 41 44 47 50 53 56 59 62 65 68 71 74 77 80 83 86 89 92 95 98 101 
3 6 9 12 15 18 21 24 27 30 33 36 39 42 45 48 51 54 57 60 63 66 69 72 75 78 81 84 87 90 93 96 99 
ACTUAL -
2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54 56 58 60 62 64 66 68 70 72 74 76 78 80 82 84 86 88 90 92 94 96 98 
2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54 56 58 60 62 64 66 68 70 72 74 76 78 80 82 84 86 88 90 92 94 96 98 100 102 
2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54 56 58 60 62 64 66 68 70 72 74 76 78 80 82 84 86 88 90 92 94 96 98 100 

---------- BEGIN SOURCE ----------
import java.util.*;
public class Main {
  public static void main(String[] args) {
    int size = 3;
    String[] array = new String[size];
    Arrays.fill(array, "");
    for(int i = 0; i <= 100; ) {
      System.out.println(i);
      array[i++%size] += i + " ";
    }
    for(String element: array) {
      System.out.println(element);
    }
  }
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
None found.

FREQUENCY : always



Comments
Given [~shade]'s request/support, I concur that this should be backported.
07-06-2018

Fix Request -------------------------- Adding jdk10u-fix-request. This is a serious regression that should be fixed in current JDK 10. The risk is minimal, because it fixes the already broken path and touches other paths lightly. Both the javac change and the regression test are cleanly backportable.
06-06-2018

URL: http://hg.openjdk.java.net/jdk/jdk/rev/6659a8f57d78 User: vromero Date: 2018-06-06 15:46:14 +0000
06-06-2018

Slightly better regression test: http://cr.openjdk.java.net/~shade/8204322/webrev.02/
05-06-2018

Agreed. Vincente, regression test is here: http://cr.openjdk.java.net/~shade/8204322/webrev.01/
05-06-2018

The bug is specifically in StringConcat.Indy.makeConcat(JCTree.JCAssignOp), which evaluates the lhs, and then calls emit, passing the lhs in the list of args, which will evaluate it again.
05-06-2018

Workaround: compile with -XDstringConcat=inline. The test fails with -XDstringConcat=indy and -XDstringConcat=indyWithConstants, pointing to the bug somewhere around here: http://hg.openjdk.java.net/jdk/jdk/file/4d6a5c267541/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/StringConcat.java#l252
05-06-2018

I confirm with Vicente that issue started from 9 ea b104 onwards. 8u172 - Pass 9 ea b103 - Pass 9 ea b104 - Fail // Regression introduced here, possibly due to "JDK-8148483: JEP 280 Integration" 9 GA - Fail 10 GA - Fail 11 ea b15 - Fail Assigning to you Vicente.
05-06-2018

yep it was the implementation for indy string concatenation the one that introduced the bug JDK-8148483
05-06-2018

This originated from this Stack Overflow question: https://stackoverflow.com/questions/50683786/why-does-arrayin-i-give-different-results-in-java-8-and-java-10 Discussion seems to center around += with String values. (Seems like it has to do with indy string concatenation, but that's just a guess on my part.) It also occurs in other simliar cases, such as this one suggested by Didier L: static class Foo { String field = ""; Foo() { System.out.println("Foo()"); } } public static void main(String[] args) { new Foo().field += "a"; } This prints "Foo()" twice on the affected versions.
04-06-2018

simplified code: public class JavacEvalBug { static int test() { System.out.println("evaluated"); return 0; } public static void main(String[] args) { String[] array = {""}; array[test()] += "a"; } } prints `evaluated` once when compiled with Java 8, and prints `evaluated` twice when compiled with Java 10 GA
04-06-2018