RFR: 8204322: "+=" applied to String operands can provoke side effects

B. Blaser bsrbnd at gmail.com
Wed Jun 6 15:50:38 UTC 2018


Hi Vicente,

On 6 June 2018 at 15:23, Vicente Romero <vicente.romero at oracle.com> wrote:
> Please review the fix for [1] at [2]. Javac was generating incorrect code
> for the case when the `+=` operand was applied to Strings and it is visible
> for test cases like:
>
> public class Test {
>    static int test() {
>        System.out.println("evaluated");
>        return 0;
>    }
>
>    public static void main(String[] args) {
>        String[] array = {""};
>        array[test()] += "a";
>    }
> }
>
> the string "evaluated" is printed twice. Some items were missing in the
> stack, the solution is to duplicate those missing items plus not to evaluate
> the lhs expression twice.
>
> Thanks in advance for the comments,
> Vicente
>
> Thanks to Aleksey Shipilev for the great regression test.
>
> [1] https://bugs.openjdk.java.net/browse/JDK-8204322
> [2] http://cr.openjdk.java.net/~vromero/8204322/webrev.01/
>

I hope I'm not too late, but I was also trying to solve this problem
(here under).
So, our solutions are quite identical (yours being a bit better), but
I think you could avoid 'boolean first' using 'arg == args.head'
instead.

Cheers,
Bernard


diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/StringConcat.java
b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/StringConcat.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/StringConcat.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/StringConcat.java
@@ -261,18 +261,18 @@
         public Item makeConcat(JCTree.JCAssignOp tree) {
             List<JCTree> args = collectAll(tree.lhs, tree.rhs);
             Item l = gen.genExpr(tree.lhs, tree.lhs.type);
-            emit(args, tree.type, tree.pos());
+            emit(l, args, tree.type, tree.pos());
             return l;
         }

         @Override
         public Item makeConcat(JCTree.JCBinary tree) {
             List<JCTree> args = collectAll(tree.lhs, tree.rhs);
-            emit(args, tree.type, tree.pos());
+            emit(null, args, tree.type, tree.pos());
             return gen.getItems().makeStackItem(syms.stringType);
         }

-        protected abstract void emit(List<JCTree> args, Type type,
JCDiagnostic.DiagnosticPosition pos);
+        protected abstract void emit(Item lhs, List<JCTree> args,
Type type, JCDiagnostic.DiagnosticPosition pos);

         /** Peel the argument list into smaller chunks. */
         protected List<List<JCTree>> split(List<JCTree> args) {
@@ -318,7 +318,7 @@
         }

         /** Emit the indy concat for all these arguments, possibly
peeling along the way */
-        protected void emit(List<JCTree> args, Type type,
JCDiagnostic.DiagnosticPosition pos) {
+        protected void emit(Item lhs, List<JCTree> args, Type type,
JCDiagnostic.DiagnosticPosition pos) {
             List<List<JCTree>> split = split(args);

             for (List<JCTree> t : split) {
@@ -333,7 +333,13 @@
                     } else {
                         dynamicArgs.add(sharpestAccessible(arg.type));
                     }
-                    gen.genExpr(arg, arg.type).load();
+
+                    if (lhs != null && arg == args.head) {
+                        lhs.duplicate();
+                        lhs.load();
+                    }
+                    else
+                        gen.genExpr(arg, arg.type).load();
                 }

                 doCall(type, pos, dynamicArgs.toList());
@@ -402,7 +408,7 @@
         }

         @Override
-        protected void emit(List<JCTree> args, Type type,
JCDiagnostic.DiagnosticPosition pos) {
+        protected void emit(Item lhs, List<JCTree> args, Type type,
JCDiagnostic.DiagnosticPosition pos) {
             List<List<JCTree>> split = split(args);

             for (List<JCTree> t : split) {
@@ -433,7 +439,13 @@
                         // Ordinary arguments come through the
dynamic arguments.
                         recipe.append(TAG_ARG);
                         dynamicArgs.add(sharpestAccessible(arg.type));
-                        gen.genExpr(arg, arg.type).load();
+
+                        if (lhs != null && arg == args.head) {
+                            lhs.duplicate();
+                            lhs.load();
+                        }
+                        else
+                            gen.genExpr(arg, arg.type).load();
                     }
                 }


More information about the compiler-dev mailing list