# HG changeset patch # User goetz # Date 1548747813 -3600 # Node ID bce458ffed11957a332c6fa3b2a9363d7bef447e # Parent bc20d037640298afb2b72655685382177c2751ae 8217628: Verbose ArrayIndexOutOfBoundsException message also in JNI calls. Reviewed-by: mdoerr, dholmes, lfoltan diff -r bc20d0376402 -r bce458ffed11 src/hotspot/share/prims/jni.cpp --- 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(start), buf, len); \ - } \ + check_bounds(start, len, src->length(), CHECK); \ + if (len > 0) { \ + ArrayAccess<>::arraycopy_to_native(src, typeArrayOopDesc::element_offset(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(start), len); \ - } \ + check_bounds(start, len, dst->length(), CHECK); \ + if (len > 0) { \ + ArrayAccess<>::arraycopy_from_native(buf, dst, typeArrayOopDesc::element_offset(start), len); \ } \ JNI_END diff -r bc20d0376402 -r bce458ffed11 test/hotspot/jtreg/runtime/exceptionMsgs/ArrayIndexOutOfBoundsException/ArrayIndexOutOfBoundsExceptionTest.java --- 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"); + } } } diff -r bc20d0376402 -r bce458ffed11 test/hotspot/jtreg/runtime/exceptionMsgs/ArrayIndexOutOfBoundsException/libArrayIndexOutOfBoundsExceptionTest.c --- /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 + +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)