JDK-6435614 : code fails with impossible ArrayIndexOutOfBounds Exception
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 6
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: solaris_10
  • CPU: sparc
  • Submitted: 2006-06-07
  • Updated: 2010-04-02
  • Resolved: 2006-07-11
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.
Other Other JDK 6
5.0u18-revFixed 5.0u19Fixed 6 b91Fixed
Related Reports
Relates :  
Description
FULL PRODUCT VERSION :
The code fails on the server compiler for 1.4.2, 1.5.0 and all the mustang builds I have, including
Java(TM) SE Runtime Environment (build 1.6.0-beta2-b85)
Java HotSpot(TM) Server VM (build 1.6.0-beta2-b85, mixed mode)


FULL OS VERSION :
SunOS eyas 5.9 Generic_118558-11 sun4u sparc SUNW,Sun-Fire-480R
SunOS noisy 5.10 Generic_118833-03 sun4u sparc SUNW,Sun-Fire-V490
Linux hoopoe 2.6.11.4-21.11-default #1 Thu Feb 2 20:54:26 UTC 2006 i686 i686 i386 GNU/Linux
Windows XP

This failure happens on every linux and Solaris version I've tried

A DESCRIPTION OF THE PROBLEM :
The attached code fails when run with the -server compiler.  It fails on Solaris+sparc and linux+x86 for the 1.4.2, 1.5 and 1.6 server JVMs.   The -client compiler runs the code fine.

The code fails immediately once the target function f() is compiled by HotSpot (I'm running with -XX:+PrintCompilation).

If I lower the CompileThreshold down to ~500, then the error no longer happens.

I'm guessing this is a loop unrolling problem.

The test case is a bit twisted; it was part of a much larger application which would fail intermitently because of this problem, but we were never able to reproduce the error.

THE PROBLEM WAS REPRODUCIBLE WITH -Xint FLAG: No

THE PROBLEM WAS REPRODUCIBLE WITH -server FLAG: Yes

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
compile and run the test code with the server compiler

EXPECTED VERSUS ACTUAL BEHAVIOR :
The results I expect:

hoopoe$ jdk1.6.0/bin/java -client Loop
done...


The results I get with the server compiler

hoopoe$ jdk1.6.0/bin/java -server Loop
i=2
index=252
w.length=2
ol.length=253
nl.length=2
java.lang.ArrayIndexOutOfBoundsException: 2
        at Loop.f(Loop.java:29)
        at Loop.main(Loop.java:5)

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------

public class Loop {
    
    public static void main(String[] args) throws Exception {
        for (int i = 0; i < 1000000; i++)
            f();
        System.out.println("done...");
    }
    
    
// a fake function to always return 2, but to prevent the optimizer from knowing this...
    private static int length() {
        double x = Math.random();
        if (x < 2)
            return 2;
        else
            return 10;
    }
    
    
    private static void f() {
        final int lag = 3;
        
        double[] nl = new double[length()];
        double[] ol = new double[253];
        double[] w = new double[nl.length];
        
        for(int i = 0; i < nl.length; i++) {
            try {
                if (i < lag)
                    w[i] = ol[ol.length - lag + i];
                else
                    w[i] = nl[i-lag];
            } catch (Exception e) {
		// the index i is 2, eve though that shouldn't be possible
		// because the array length of nl is always 2.
		// we're failing on the indexing of w[2]
                System.err.println("i="+i);
                System.err.println("index="+(ol.length - lag + i));
                System.err.println("w.length="+w.length);
                System.err.println("ol.length="+ol.length);
                System.err.println("nl.length="+nl.length);
                e.printStackTrace();
                System.exit(1);
            }
        }
    }
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
I can work around this by using the client compiler, which isn't acceptable on our large systems.  The server compiler does give a nice performance boost.

I can also defeat the (loop-unrolling?) optimization by adding a check for
if (i >= nl.length)
    throw new Exception();
which should never be taken.


So, even while I have a workaround in place, this has been a major problem for us.   While the test case here is trivial, this is part of a big application which would fail in random ways because of this problem.   In fact, we were never able to reproduce the problem until recently, and even then it would take hours of running each time to help isolate the problem.

I'm flagging this as a severe error (even though I have a workaround) because it is a severe  error.   Now that the -server compiler is the default on larger systems, it's important to not have these errors.

Comments
SUGGESTED FIX http://analemma.sfbay.sun.com/net/prt-archiver.sfbay/data/archived_workspaces/main/c2_baseline/2006/20060626094924.nips.bug6435614/workspace/webrevs/webrev-2006.06.26/index.html
26-06-2006

EVALUATION Range checks that do not dominate the loop backedge can lengthen the pre loop limit beyond the original loop limit, causing bogus range check exceptions from the pre loop. To prevent this, the pre limit is, for stride > 0, MINed (MAXed for stride < 0) with the main loop limit when a range check is eliminated that does not dominate the backedge.
20-06-2006