1 /* 2 * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @bug 8155608 27 * @summary Verifies that string intrinsics throw array out of bounds exceptions. 28 * @library /compiler/patches /test/lib 29 * @build java.base/java.lang.Helper 30 * @run main/othervm -Xbatch -XX:CompileThreshold=100 compiler.intrinsics.string.TestStringIntrinsicRangeChecks 31 */ 32 package compiler.intrinsics.string; 33 34 import java.lang.Helper; 35 import java.lang.reflect.InvocationTargetException; 36 import java.lang.reflect.Method; 37 38 public class TestStringIntrinsicRangeChecks { 39 // Prepare test arrays 40 private static int SIZE = 16; 41 private static byte[] byteArray = new byte[SIZE]; 42 private static char[] charArray = new char[SIZE]; 43 44 public static void check(Method m, boolean shouldThrow, Object... args) throws Exception { 45 // Prepare error message 46 String message = m.getName() + "("; 47 for (int i = 0; i < args.length; ++i) { 48 message += args[i]; 49 message += (i+1 < args.length) ? ", " : ")"; 50 } 51 52 try { 53 m.invoke(null, args); 54 } catch (InvocationTargetException e) { 55 // Get actual exception 56 Throwable t = e.getTargetException(); 57 if (!shouldThrow) { 58 throw new RuntimeException("Unexpected exception thrown for " + message, e); 59 } 60 if (t instanceof StringIndexOutOfBoundsException || 61 t instanceof ArrayIndexOutOfBoundsException) { 62 // Expected exception. Make sure that the exception was not thrown in UTF16.putChar/getChar 63 // because the corresponding intrinsics are unchecked and the Java code should do all the checks. 64 StackTraceElement[] stack = t.getStackTrace(); 65 if (stack.length != 0) { 66 String methodName = stack[0].getMethodName(); 67 if (methodName.equals("putChar") || methodName.equals("getChar")) { 68 throw new RuntimeException("Exception thrown in " + methodName + " for " + message, t); 69 } 70 } 71 } 72 return; 73 } 74 if (shouldThrow) { 75 throw new RuntimeException("No exception thrown for " + message); 76 } 77 } 78 79 public static void main(String[] args) throws Exception { 80 // Get intrinsified String API methods 81 Method compressByte = Helper.class.getMethod("compressByte", byte[].class, int.class, int.class, int.class, int.class); 82 Method compressChar = Helper.class.getMethod("compressChar", char[].class, int.class, int.class, int.class, int.class); 83 Method inflateByte = Helper.class.getMethod("inflateByte", byte[].class, int.class, int.class, int.class, int.class); 84 Method inflateChar = Helper.class.getMethod("inflateChar", byte[].class, int.class, int.class, int.class, int.class); 85 Method toBytes = Helper.class.getMethod("toBytes", char[].class, int.class, int.class); 86 Method getChars = Helper.class.getMethod("getChars", byte[].class, int.class, int.class, int.class, int.class); 87 88 // Check different combinations of arguments (source/destination offset and length) 89 for (int srcOff = 0; srcOff < SIZE; ++srcOff) { 90 for (int dstOff = 0; dstOff < SIZE; ++dstOff) { 91 for (int len = 0; len < SIZE; ++len) { 92 // Check for potential overlows in source or destination array 93 boolean srcOverflow = (srcOff + len) > SIZE; 94 boolean srcOverflowB = (2*srcOff + 2*len) > SIZE; 95 boolean dstOverflow = (dstOff + len) > SIZE; 96 boolean dstOverflowB = (2*dstOff + 2*len) > SIZE; 97 boolean getCharsOver = (srcOff < len) && ((2*(len-1) >= SIZE) || ((dstOff + len - srcOff) > SIZE)); 98 // Check if an exception is thrown and bail out if result is inconsistent with above 99 // assumptions (for example, an exception was not thrown although an overflow happened). 100 check(compressByte, srcOverflowB || dstOverflow, byteArray, srcOff, SIZE, dstOff, len); 101 check(compressChar, srcOverflow || dstOverflow, charArray, srcOff, SIZE, dstOff, len); 102 check(inflateByte, srcOverflow || dstOverflowB, byteArray, srcOff, SIZE, dstOff, len); 103 check(inflateChar, srcOverflow || dstOverflow, byteArray, srcOff, SIZE, dstOff, len); 104 check(toBytes, srcOverflow, charArray, srcOff, len); 105 check(getChars, getCharsOver, byteArray, srcOff, len, SIZE, dstOff); 106 } 107 } 108 } 109 } 110 }