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