Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8262739

String inflation C2 intrinsic prevents insertion of anti-dependencies

    XMLWordPrintable

Details

    • b93
    • 9
    • b16
    • Verified

    Backports

      Description

        ADDITIONAL SYSTEM INFORMATION :
        Reproduced on Mac OS with both Java 11 and Java 15

        A DESCRIPTION OF THE PROBLEM :
        We observed that the reverse() method of the org.apache.commons.lang.StringUtils class contained in Apache commons-lang version 2.6 started returning incorrect results after thousands of iterations.

        The reason we suspect an issue with compact strings and the optimizer is because:

        1. The bug only reproduces with strings which can be represented compactly (all code points < 256)
        2. The bug only reproduces after calling the method in a loop for an indeterminate number of times (the range we've seen is from a minimum of around 50K iterations to a maximum of around 135K iterations).
        3. The bug does not reproduce when compact strings are disabled via -XX:-CompactStrings
        4. The bug does not reproduce when the optimizer is disabled via -Djava.compiler=NONE

        STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        Run the attached source code. A couple of ways you can reproduce it:

        1. Clone the repository I created at https://github.com/jyemin/compact-strings-bug and execute "./gradlew run".
        2. Manually download commons-lang jar file from https://repo1.maven.org/maven2/commons-lang/commons-lang/2.6/ and compile the attached source code with this jar in your classpath

        EXPECTED VERSUS ACTUAL BEHAVIOR :
        EXPECTED -
        Expected that the following would be printed:

          Original string: 123456
          Expected reversed string: 654321

          Completed normally. Exiting.
        ACTUAL -
        Instead, the following is printed:

          Original string: 123456
          Expected reversed string: 654321

          Iteration: 118306
          Actual: 654326

          Iteration: 118307
          Actual: 654326

          Iteration: 118308
          Actual: 654326

          Iteration: 118309
          Actual: 654326

          Iteration: 118310
          Actual: 654326

          Exiting after 5 failures

        A few additional observations:

        1. The number of iterations before it starts returning incorrect results varies, but once it starts behaving incorrectly, every subsequent call behaves incorrectly, in exactly the same way
        2. It also seems to be the case that there is a single incorrect character in the reversed string. It's always the last character, and instead of being the expected first character from the original string, it's the last character from the original string.


        ---------- BEGIN SOURCE ----------
        import org.apache.commons.lang.StringUtils;

        public class CompactStringBug {

            protected static final int MAX_FAILURES = 5;

            public static void main(String[] args) {
                final String id = "123456";
                final String expectedReversedId = "654321";

                /*
                  The bug does not reproduce if you include a multibyte character in the string
                */
        // final String id = "12345\u1234";
        // final String expectedReversedId = "\u123454321";

                System.out.println("Original string: " + id);
                System.out.println("Expected reversed string: " + expectedReversedId);
                System.out.println();

                int failures = 0;
                for (int i = 0; i < Integer.MAX_VALUE; i++) {
                    String reversedId = StringUtils.reverse(id);
                    if (!expectedReversedId.equals(reversedId)) {
                        failures++;
                        System.out.println("Iteration: " + i);
                        System.out.println("Actual: " + reversedId);
                        System.out.println();
                        if (failures == MAX_FAILURES) {
                            System.out.println("Exiting after " + MAX_FAILURES + " failures");
                            System.exit(1);
                        }
                    }
                }
                System.out.println("Completed normally. Exiting.");
            }
        }
        ---------- END SOURCE ----------

        CUSTOMER SUBMITTED WORKAROUND :
        We've found a number of workarounds. The most straightforward is to replace use of commons-lang StringUtils with java.lang.StringBuilder#reverse.

        These are some other ways we've worked around the bug during analysis, but only the first is practicable in production:

        1. Disable compact strings, e.g. by starting java with -XX:-CompactStrings
        2. Disable the optimizer, e.g. by starting java with -Djava.compiler=NONE
        3. Ensure that at least one character in the string is multibyte (i.e. code point > 255)


        FREQUENCY : always


        Attachments

          Issue Links

            Activity

              People

                thartmann Tobias Hartmann
                webbuggrp Webbug Group
                Votes:
                0 Vote for this issue
                Watchers:
                9 Start watching this issue

                Dates

                  Created:
                  Updated:
                  Resolved: