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

Array Out Of Bounds Exception causes variable corruption

    XMLWordPrintable

Details

    • b44
    • x86
    • other
    • Verified

    Backports

      Description

        FULL PRODUCT VERSION :
        java.version=1.8.0_25 (or any Java 8) tested 1.8.0_05 and 1.8.0_40

        ADDITIONAL OS VERSION INFORMATION :
        Apple OS X 10.9.4
        Microsoft Windows [Version 6.1.7600]

        A DESCRIPTION OF THE PROBLEM :
        Accessing array out of bounds, resulting in an IndexOutOfBoundsException being thrown can cause corruption of stack based variable between where the `IndexOutOfBoundsException` is thrown and where the exception is caught.

        This seems to occur on ALL versions of Java 8 and has been reproduced on Apple OS-X 10.9.4 and Windows 7 64bit

        The exact time that the corruption occurs varies from run to run and from OS to OS

        REGRESSION. Last worked in version 7u71

        ADDITIONAL REGRESSION INFORMATION:
        Appears to work with all Java 7 versions

        STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        Run the JUnit text program supplied with a Java 8 JVM

        EXPECTED VERSUS ACTUAL BEHAVIOR :
        EXPECTED -
        java.version=1.8.0_40-ea
        expected 1.00000, sum.getSum() = 1.00000
        expected 2.00000, sum.getSum() = 2.00000
        .
        .
        .
        expected 100000.00000, sum.getSum() = 100000.00000

        ACTUAL -
        java.version=1.8.0_40-ea
        expected 1.00000, sum.getSum() = 1.00000
        expected 2.00000, sum.getSum() = 2.00000
        .
        .
        .
        expected 645.000, sum.getSum() = 645.000
        expected 646.000, sum.getSum() = 645.000 <<<< Looky here!!!!!!!

        ERROR MESSAGES/STACK TRACES THAT OCCUR :
        testAdd Failed: expected: <646.0> but was: <645.0>

        REPRODUCIBILITY :
        This bug can be reproduced always.

        ---------- BEGIN SOURCE ----------
        import org.junit.Assert;
        import org.junit.Test;

        /**
         *
         * @author michaelellis
         */
        public class SumTest {

            @Test
            public void testAdd() {
                System.out.printf("java.version=%s%n", System.getProperty("java.version"));
                final Sum sum = new Sum();
                for (int i = 1; i <= 100000; ++i) {
                    sum.add(1);
                    System.out.printf("expected %g, sum.getSum() = %g%n", (double)i, sum.getSum());
                    Assert.assertEquals((double) i, sum.getSum(), 0.0001);
                }
            }

        }

        class Sum {

            protected double[] sums;

            /**
             * Construct empty Sum
             */
            public Sum() {
                sums = new double[0];
            }

            /**
             * Return the sum of all numbers added to this Sum
             *
             * @return the sum
             */
            final public double getSum() {
                double sum = 0;
                for (final double s : sums) {
                    sum += s;
                }

                return sum;
            }

            /**
             * Add a new number to this Sum
             *
             * @param a number to be added.
             */
            final public void add(final double a) {
                try {
                    sums[sums.length] = -1; // Cause IndexOutOfBoundsException
                } catch (final IndexOutOfBoundsException e) {
                    /**
                     * SHOW STOPPER
                     *
                     * By now the variable a can be corrupted!!!!
                     */
                    final double[] oldSums = sums;
                    sums = new double[oldSums.length + 1]; // Extend sums
                    System.arraycopy(oldSums, 0, sums, 0, oldSums.length);
                    sums[oldSums.length] = a; // Append a
                }
            }
        }

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

        CUSTOMER SUBMITTED WORKAROUND :
        Do not rely on being able to use stack variables after an IndexOutOfBoundException.

        This is a real Java8 Show Stopper. Any code that relies of IndexOutOfBoundsException rather than explicitly testing array lengths is susceptible to failure under Java 8. For example the ImgLib 2 project fails its JUnit Tests under Java 8 (This test program was devised after finding the bug with ImgLib class RealSum.

        SUPPORT :
        YES

        Attachments

          Issue Links

            Activity

              People

                iveresov Igor Veresov
                webbuggrp Webbug Group
                Votes:
                0 Vote for this issue
                Watchers:
                6 Start watching this issue

                Dates

                  Created:
                  Updated:
                  Resolved: