JDK-8066103 : C2's range check smearing allows out of bound array accesses
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 7u71,8u40,9
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2014-11-27
  • Updated: 2017-08-07
  • Resolved: 2014-12-09
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.
JDK 7 JDK 8 JDK 9
7u80Fixed 8u40Fixed 9 b44Fixed
Description
This test fails when m1 is compiled by C2 because C2's range check smearing changes the array bound check of the first access to test only for lowest constant values of all array accesses.

public class TestRangeCheckSmearing {

    static int m1(int[] array, int i, boolean allaccesses) {
        int res = 0;
        res += array[i+4];
        if (allaccesses) {
            res += array[i+3];
            res += array[i+2];
            res += array[i+1];
        }
        return res;
    }

    static public void main(String[] args) {
        int[] array = new int[10];
        
        for (int i = 0; i < 20000; i++) {
            m1(array, 0, (i % 2) == 0);
        }
        boolean exception = false;
        try {
            m1(array, 8, false);
        } catch(ArrayIndexOutOfBoundsException aioob) {
            exception = true;
            System.out.println("ArrayIndexOutOfBoundsException thrown for m1");
        }
        if (!exception) {
            throw new RuntimeException("ArrayIndexOutOfBoundsException not throw");
        }
    }
}

ILW=H(may crash the VM) L (most bad array access will hit somewhere in the heap, has gone unnoticed for a long time) H(none)
Comments
The current code optimizes this: if i <u array.length then uncommon trap // some dependent accesses // some other range check if i <u array.length then uncommon trap // some other dependent accesses to: if i <u array.length then uncommon trap // some dependent accesses // some other dependent accesses // some other range check It's incorrect. For instance: if i <u array.length then uncommon trap x = array[i] // some stuff that blocks range check smearing if i-1 <u array.length then uncommon trap x = array[i-1] if i-3 <u array.length then uncommon trap x = array[i-3] if i <u array.length then uncommon trap x = array[i] if i-2 <u array.length then uncommon trap x = array[i-2] Assuming the second series is optimized: if i <u array.length then uncommon trap x = array[i] // some stuff that blocks range check smearing if i-1 <u array.length then uncommon trap x = array[i-1] if i-3 <u array.length then uncommon trap x = array[i-3] if i <u array.length then uncommon trap x = array[i] x = array[i-2] and now if the stuff that blocks range check smearing is optimized out and if i <u array.length is processed we would end up with: if i <u array.length then uncommon trap x = array[i] x = array[i-2] if i-1 <u array.length then uncommon trap x = array[i-1] if i-3 <u array.length then uncommon trap x = array[i-3] And we can do an out of bound array access. The problem is that we can���t substitute a range check for another identical one if there are range checks in between.
04-12-2014

Confirm: ILW=H(may crash the VM) L (most bad array access will hit somewhere in the heap, has gone unnoticed for a long time) H(none) = P2
01-12-2014