changeset 54634:bce458ffed11

8217628: Verbose ArrayIndexOutOfBoundsException message also in JNI calls. Reviewed-by: mdoerr, dholmes, lfoltan
author goetz
date Tue, 29 Jan 2019 08:43:33 +0100
parents bc20d0376402
children 4cfa5f51eafa
files src/hotspot/share/prims/jni.cpp test/hotspot/jtreg/runtime/exceptionMsgs/ArrayIndexOutOfBoundsException/ArrayIndexOutOfBoundsExceptionTest.java test/hotspot/jtreg/runtime/exceptionMsgs/ArrayIndexOutOfBoundsException/libArrayIndexOutOfBoundsExceptionTest.c
diffstat 3 files changed, 572 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/share/prims/jni.cpp	Mon Jan 28 23:00:31 2019 +0100
+++ b/src/hotspot/share/prims/jni.cpp	Tue Jan 29 08:43:33 2019 +0100
@@ -2591,9 +2591,10 @@
     ret = JNIHandles::make_local(env, a->obj_at(index));
     return ret;
   } else {
-    char buf[jintAsStringSize];
-    sprintf(buf, "%d", index);
-    THROW_MSG_0(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), buf);
+    ResourceMark rm(THREAD);
+    stringStream ss;
+    ss.print("Index %d out of bounds for length %d", index, a->length());
+    THROW_MSG_0(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), ss.as_string());
   }
 JNI_END
 
@@ -2624,9 +2625,10 @@
       THROW_MSG(vmSymbols::java_lang_ArrayStoreException(), ss.as_string());
     }
   } else {
-    char buf[jintAsStringSize];
-    sprintf(buf, "%d", index);
-    THROW_MSG(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), buf);
+    ResourceMark rm(THREAD);
+    stringStream ss;
+    ss.print("Index %d out of bounds for length %d", index, a->length());
+    THROW_MSG(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), ss.as_string());
   }
 JNI_END
 
@@ -2801,6 +2803,19 @@
                                   , HOTSPOT_JNI_RELEASEDOUBLEARRAYELEMENTS_ENTRY(env, array, (double *) buf, mode),
                                   HOTSPOT_JNI_RELEASEDOUBLEARRAYELEMENTS_RETURN())
 
+static void check_bounds(jsize start, jsize copy_len, jsize array_len, TRAPS) {
+  ResourceMark rm(THREAD);
+  if (copy_len < 0) {
+    stringStream ss;
+    ss.print("Length %d is negative", copy_len);
+    THROW_MSG(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), ss.as_string());
+  } else if (start < 0 || (start > array_len - copy_len)) {
+    stringStream ss;
+    ss.print("Array region %d.." INT64_FORMAT " out of bounds for length %d",
+             start, (int64_t)start+(int64_t)copy_len, array_len);
+    THROW_MSG(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), ss.as_string());
+  }
+}
 
 #define DEFINE_GETSCALARARRAYREGION(ElementTag,ElementType,Result, Tag \
                                     , EntryProbe, ReturnProbe); \
@@ -2814,12 +2829,9 @@
   EntryProbe; \
   DT_VOID_RETURN_MARK(Get##Result##ArrayRegion); \
   typeArrayOop src = typeArrayOop(JNIHandles::resolve_non_null(array)); \
-  if (start < 0 || len < 0 || (start > src->length() - len)) { \
-    THROW(vmSymbols::java_lang_ArrayIndexOutOfBoundsException()); \
-  } else { \
-    if (len > 0) { \
-      ArrayAccess<>::arraycopy_to_native(src, typeArrayOopDesc::element_offset<ElementType>(start), buf, len); \
-    } \
+  check_bounds(start, len, src->length(), CHECK); \
+  if (len > 0) {    \
+    ArrayAccess<>::arraycopy_to_native(src, typeArrayOopDesc::element_offset<ElementType>(start), buf, len); \
   } \
 JNI_END
 
@@ -2861,12 +2873,9 @@
   EntryProbe; \
   DT_VOID_RETURN_MARK(Set##Result##ArrayRegion); \
   typeArrayOop dst = typeArrayOop(JNIHandles::resolve_non_null(array)); \
-  if (start < 0 || len < 0 || (start > dst->length() - len)) { \
-    THROW(vmSymbols::java_lang_ArrayIndexOutOfBoundsException()); \
-  } else { \
-    if (len > 0) { \
-      ArrayAccess<>::arraycopy_from_native(buf, dst, typeArrayOopDesc::element_offset<ElementType>(start), len); \
-    } \
+  check_bounds(start, len, dst->length(), CHECK); \
+  if (len > 0) { \
+    ArrayAccess<>::arraycopy_from_native(buf, dst, typeArrayOopDesc::element_offset<ElementType>(start), len); \
   } \
 JNI_END
 
--- a/test/hotspot/jtreg/runtime/exceptionMsgs/ArrayIndexOutOfBoundsException/ArrayIndexOutOfBoundsExceptionTest.java	Mon Jan 28 23:00:31 2019 +0100
+++ b/test/hotspot/jtreg/runtime/exceptionMsgs/ArrayIndexOutOfBoundsException/ArrayIndexOutOfBoundsExceptionTest.java	Tue Jan 29 08:43:33 2019 +0100
@@ -1,6 +1,6 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2018 SAP SE. All rights reserved.
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019 SAP SE. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -51,6 +51,10 @@
  */
 public class ArrayIndexOutOfBoundsExceptionTest {
 
+    static {
+        System.loadLibrary("ArrayIndexOutOfBoundsExceptionTest");
+    }
+
     // Some fields used in the test.
     static int[] staticArray = new int[0];
     static long[][] staticLongArray = new long[0][0];
@@ -88,6 +92,26 @@
         }
     }
 
+    static native void  doNativeArrayStore(Object[] dst, Object element, int index);
+    static native Object doNativeArrayLoad(Object[] src, int index);
+
+    static native void doNativeBooleanArrayRegionLoad (boolean[] source, int start, int len);
+    static native void doNativeBooleanArrayRegionStore(boolean[] source, int start, int len);
+    static native void doNativeByteArrayRegionLoad    (byte[] source,    int start, int len);
+    static native void doNativeByteArrayRegionStore   (byte[] source,    int start, int len);
+    static native void doNativeShortArrayRegionLoad   (short[] source,   int start, int len);
+    static native void doNativeShortArrayRegionStore  (short[] source,   int start, int len);
+    static native void doNativeCharArrayRegionLoad    (char[] source,    int start, int len);
+    static native void doNativeCharArrayRegionStore   (char[] source,    int start, int len);
+    static native void doNativeIntArrayRegionLoad     (int[] source,     int start, int len);
+    static native void doNativeIntArrayRegionStore    (int[] source,     int start, int len);
+    static native void doNativeLongArrayRegionLoad    (long[] source,    int start, int len);
+    static native void doNativeLongArrayRegionStore   (long[] source,    int start, int len);
+    static native void doNativeFloatArrayRegionLoad   (float[] source,   int start, int len);
+    static native void doNativeFloatArrayRegionStore  (float[] source,   int start, int len);
+    static native void doNativeDoubleArrayRegionLoad  (double[] source,  int start, int len);
+    static native void doNativeDoubleArrayRegionStore (double[] source,  int start, int len);
+
     /**
      *
      */
@@ -439,5 +463,463 @@
             assertEquals(e.getMessage(),
                 "arraycopy: last destination index 7 out of bounds for float[5]");
         }
+
+
+        // Test native array access.
+
+
+        try {
+            System.out.println(doNativeArrayLoad(oa2, 77));
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Index 77 out of bounds for length 5");
+        }
+        try {
+            System.out.println(doNativeArrayLoad(oa1, -1));
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Index -1 out of bounds for length 10");
+        }
+
+        try {
+            doNativeArrayStore(oa1, "Some String", Integer.MIN_VALUE);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Index -2147483648 out of bounds for length 10");
+        }
+        try {
+            doNativeArrayStore(oa1, "Some String", 13);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Index 13 out of bounds for length 10");
+        }
+
+        // Boolean
+
+        // Native array region loads.
+        // Boolean, len negative.
+        try {
+            doNativeBooleanArrayRegionLoad(za2, 3, -77);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Length -77 is negative");
+        }
+        // Boolean, index negative.
+        try {
+            doNativeBooleanArrayRegionLoad(za2, -3, 3);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Array region -3..0 out of bounds for length 10");
+        }
+        // Boolean, index+len too big.
+        try {
+            doNativeBooleanArrayRegionLoad(za2, 3, Integer.MAX_VALUE-1);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Array region 3..2147483649 out of bounds for length 10");
+        }
+        // Native array region stores
+        // Boolean, len negative.
+        try {
+            doNativeBooleanArrayRegionStore(za2, 3, -77);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Length -77 is negative");
+        }
+        // Boolean, index negative.
+        try {
+            doNativeBooleanArrayRegionStore(za2, -3, 3);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Array region -3..0 out of bounds for length 10");
+        }
+        // Boolean, index+len too big.
+        try {
+            doNativeBooleanArrayRegionStore(za2, 3, Integer.MAX_VALUE);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Array region 3..2147483650 out of bounds for length 10");
+        }
+
+        // Byte
+
+        // Native array region loads.
+        // Byte, len negative.
+        try {
+            doNativeByteArrayRegionLoad(ba1, 3, -77);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Length -77 is negative");
+        }
+        // Byte, index negative.
+        try {
+            doNativeByteArrayRegionLoad(ba1, -3, 3);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Array region -3..0 out of bounds for length 0");
+        }
+        // Byte, index+len too big.
+        try {
+            doNativeByteArrayRegionLoad(ba2, 3, Integer.MAX_VALUE-1);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Array region 3..2147483649 out of bounds for length 10");
+        }
+        // Native array region stores
+        // Byte, len negative.
+        try {
+            doNativeByteArrayRegionStore(ba2, 3, -77);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Length -77 is negative");
+        }
+        // Byte, index negative.
+        try {
+            doNativeByteArrayRegionStore(ba2, -3, 3);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Array region -3..0 out of bounds for length 10");
+        }
+        // Byte, index+len too big.
+        try {
+            doNativeByteArrayRegionStore(ba2, 3, Integer.MAX_VALUE);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Array region 3..2147483650 out of bounds for length 10");
+        }
+
+        // Short
+
+        // Native array region loads.
+        // Short, len negative.
+        try {
+            doNativeShortArrayRegionLoad(sa2, 3, -77);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Length -77 is negative");
+        }
+        // Short, index negative.
+        try {
+            doNativeShortArrayRegionLoad(sa2, -3, 3);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Array region -3..0 out of bounds for length 10");
+        }
+        // Short, index+len too big.
+        try {
+            doNativeShortArrayRegionLoad(sa2, 3, Integer.MAX_VALUE-1);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Array region 3..2147483649 out of bounds for length 10");
+        }
+        // Native array region stores
+        // Short, len negative.
+        try {
+            doNativeShortArrayRegionStore(sa2, 3, -77);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Length -77 is negative");
+        }
+        // Short, index negative.
+        try {
+            doNativeShortArrayRegionStore(sa2, -3, 3);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Array region -3..0 out of bounds for length 10");
+        }
+        // Short, index+len too big.
+        try {
+            doNativeShortArrayRegionStore(sa2, 3, Integer.MAX_VALUE);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Array region 3..2147483650 out of bounds for length 10");
+        }
+
+        // Char
+
+        // Native array region loads.
+        // Char, len negative.
+        try {
+            doNativeCharArrayRegionLoad(ca2, 3, -77);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Length -77 is negative");
+        }
+        // Char, index negative.
+        try {
+            doNativeCharArrayRegionLoad(ca2, -3, 3);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Array region -3..0 out of bounds for length 10");
+        }
+        // Char, index+len too big.
+        try {
+            doNativeCharArrayRegionLoad(ca2, 3, Integer.MAX_VALUE-1);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Array region 3..2147483649 out of bounds for length 10");
+        }
+        // Native array region stores
+        // Char, len negative.
+        try {
+            doNativeCharArrayRegionStore(ca2, 3, -77);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Length -77 is negative");
+        }
+        // Char, index negative.
+        try {
+            doNativeCharArrayRegionStore(ca2, -3, 3);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Array region -3..0 out of bounds for length 10");
+        }
+        // Char, index+len too big.
+        try {
+            doNativeCharArrayRegionStore(ca2, 3, Integer.MAX_VALUE);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Array region 3..2147483650 out of bounds for length 10");
+        }
+
+        // Int
+
+        // Native array region loads.
+        // Int, len negative.
+        try {
+            doNativeIntArrayRegionLoad(ia2, 3, -77);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Length -77 is negative");
+        }
+        // Int, index negative.
+        try {
+            doNativeIntArrayRegionLoad(ia2, -3, 3);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Array region -3..0 out of bounds for length 10");
+        }
+        // Int, index+len too big.
+        try {
+            doNativeIntArrayRegionLoad(ia2, 3, Integer.MAX_VALUE-1);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Array region 3..2147483649 out of bounds for length 10");
+        }
+        // Native array region stores
+        // Int, len negative.
+        try {
+            doNativeIntArrayRegionStore(ia2, 3, -77);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Length -77 is negative");
+        }
+        // Int, index negative.
+        try {
+            doNativeIntArrayRegionStore(ia2, -3, 3);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Array region -3..0 out of bounds for length 10");
+        }
+        // Int, index+len too big.
+        try {
+            doNativeIntArrayRegionStore(ia2, 3, Integer.MAX_VALUE);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Array region 3..2147483650 out of bounds for length 10");
+        }
+
+        // Long
+
+        // Native array region loads.
+        // Long, len negative.
+        try {
+            doNativeLongArrayRegionLoad(la2, 3, -77);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Length -77 is negative");
+        }
+        // Long, index negative.
+        try {
+            doNativeLongArrayRegionLoad(la2, -3, 3);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Array region -3..0 out of bounds for length 10");
+        }
+        // Long, index+len too big.
+        try {
+            doNativeLongArrayRegionLoad(la2, 3, Integer.MAX_VALUE-1);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Array region 3..2147483649 out of bounds for length 10");
+        }
+        // Native array region stores
+        // Long, len negative.
+        try {
+            doNativeLongArrayRegionStore(la2, 3, -77);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Length -77 is negative");
+        }
+        // Long, index negative.
+        try {
+            doNativeLongArrayRegionStore(la2, -3, 3);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Array region -3..0 out of bounds for length 10");
+        }
+        // Long, index+len too big.
+        try {
+            doNativeLongArrayRegionStore(la2, 3, Integer.MAX_VALUE);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Array region 3..2147483650 out of bounds for length 10");
+        }
+
+        // Float
+
+        // Native array region loads.
+        // Float, len negative.
+        try {
+            doNativeFloatArrayRegionLoad(fa2, 3, -77);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Length -77 is negative");
+        }
+        // Float, index negative.
+        try {
+            doNativeFloatArrayRegionLoad(fa2, -3, 3);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Array region -3..0 out of bounds for length 10");
+        }
+        // Float, index+len too big.
+        try {
+            doNativeFloatArrayRegionLoad(fa2, 3, Integer.MAX_VALUE-1);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Array region 3..2147483649 out of bounds for length 10");
+        }
+        // Native array region stores
+        // Float, len negative.
+        try {
+            doNativeFloatArrayRegionStore(fa2, 3, -77);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Length -77 is negative");
+        }
+        // Float, index negative.
+        try {
+            doNativeFloatArrayRegionStore(fa2, -3, 3);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Array region -3..0 out of bounds for length 10");
+        }
+        // Float, index+len too big.
+        try {
+            doNativeFloatArrayRegionStore(fa2, 3, Integer.MAX_VALUE);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Array region 3..2147483650 out of bounds for length 10");
+        }
+
+        // Double
+
+        // Native array region loads.
+        // Double, len negative.
+        try {
+            doNativeDoubleArrayRegionLoad(da2, 3, -77);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Length -77 is negative");
+        }
+        // Double, index negative.
+        try {
+            doNativeDoubleArrayRegionLoad(da2, -3, 3);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Array region -3..0 out of bounds for length 10");
+        }
+        // Double, index+len too big.
+        try {
+            doNativeDoubleArrayRegionLoad(da2, 3, Integer.MAX_VALUE-1);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Array region 3..2147483649 out of bounds for length 10");
+        }
+        // Native array region stores
+        // Double, len negative.
+        try {
+            doNativeDoubleArrayRegionStore(da2, 3, -77);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Length -77 is negative");
+        }
+        // Double, index negative.
+        try {
+            doNativeDoubleArrayRegionStore(da2, -3, 3);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Array region -3..0 out of bounds for length 10");
+        }
+        // Double, index+len too big.
+        try {
+            doNativeDoubleArrayRegionStore(da2, 3, Integer.MAX_VALUE);
+            fail();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            assertEquals(e.getMessage(),
+                "Array region 3..2147483650 out of bounds for length 10");
+        }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/exceptionMsgs/ArrayIndexOutOfBoundsException/libArrayIndexOutOfBoundsExceptionTest.c	Tue Jan 29 08:43:33 2019 +0100
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019 SAP SE. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include <jni.h>
+
+JNIEXPORT void JNICALL
+  Java_ArrayIndexOutOfBoundsExceptionTest_doNativeArrayStore(JNIEnv *env, jclass klass,
+                                                             jobjectArray array, jobject element, jint index) {
+  (*env)->SetObjectArrayElement(env, array, index, element);
+}
+
+JNIEXPORT jobject JNICALL
+  Java_ArrayIndexOutOfBoundsExceptionTest_doNativeArrayLoad(JNIEnv *env, jclass klass,
+                                                            jobjectArray array, jint index) {
+  return (*env)->GetObjectArrayElement(env, array, index);
+}
+
+
+#define REGIONACCESS(ElementType,NameType) \
+JNIEXPORT void JNICALL \
+  Java_ArrayIndexOutOfBoundsExceptionTest_doNative##NameType##ArrayRegionLoad(JNIEnv *env, jclass klass, \
+                                                                     ElementType##Array array, jint start, jint len) { \
+  ElementType clone[100]; \
+  (*env)->Get##NameType##ArrayRegion(env, array, start, len, clone); \
+} \
+JNIEXPORT void JNICALL \
+  Java_ArrayIndexOutOfBoundsExceptionTest_doNative##NameType##ArrayRegionStore(JNIEnv *env, jclass klass, \
+                                                                      ElementType##Array array, jint start, jint len) { \
+  ElementType content[100]; \
+  (*env)->Set##NameType##ArrayRegion(env, array, start, len, content); \
+}
+
+REGIONACCESS(jboolean, Boolean)
+REGIONACCESS(jbyte,    Byte)
+REGIONACCESS(jshort,   Short)
+REGIONACCESS(jchar,    Char)
+REGIONACCESS(jint,     Int)
+REGIONACCESS(jlong,    Long)
+REGIONACCESS(jfloat,   Float)
+REGIONACCESS(jdouble,  Double)