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