1 /* 2 * Copyright (c) 2000, 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 * @key stress 27 * 28 * @summary converted from VM testbase nsk/stress/stack/stack018. 29 * VM testbase keywords: [stress, diehard, stack, nonconcurrent, exclude] 30 * VM testbase comments: 8139875 31 * VM testbase readme: 32 * DESCRIPTION 33 * This test provokes multiple stack overflows by invocations via 34 * reflection -- repeatedly multiple times, and in multiple threads. 35 * Recursive method is invoked for the given fixed depth of recursion 36 * (though, for a large depth). The test measures a number of recursive 37 * invocations until stack overflow, and then tries to reproduce similar 38 * stack overflows 10 times in each of 10 threads -- each time by trying 39 * to invoke the same recursive method for the given fixed depth 40 * of invocations (which is 10 times that crucial depth just measured). 41 * The test is deemed passed, if VM have not crashed, and 42 * if exception other than due to stack overflow was not 43 * thrown. 44 * COMMENTS 45 * This test crashes HS versions 2.0, 1.3, and 1.4 on both 46 * Solaris and Win32 platforms. 47 * See the bug: 48 * 4366625 (P4/S4) multiple stack overflow causes HS crash 49 * 50 * @ignore 8139875 51 * @requires vm.opt.DeoptimizeALot == null | vm.opt.DeoptimizeALot == false 52 * @run main/othervm nsk.stress.stack.stack018 -eager 53 */ 54 55 package nsk.stress.stack; 56 57 58 import nsk.share.Harakiri; 59 60 import java.io.PrintStream; 61 import java.lang.reflect.InvocationTargetException; 62 import java.lang.reflect.Method; 63 64 public class stack018 extends Thread { 65 private final static int THREADS = 10; 66 private final static int CYCLES = 10; 67 private final static int STEP = 100; 68 private final static int RESERVE = 100; 69 70 public static void main(String[] args) { 71 int exitCode = run(args, System.out); 72 System.exit(exitCode + 95); 73 } 74 75 public static int run(String args[], PrintStream out) { 76 verbose = false; 77 boolean eager = false; 78 for (int i = 0; i < args.length; i++) 79 if (args[i].toLowerCase().equals("-verbose")) 80 verbose = true; 81 else if (args[i].toLowerCase().equals("-eager")) 82 eager = true; 83 if (!eager) 84 Harakiri.appoint(Harakiri.parseAppointment(args)); 85 stack018.out = out; 86 stack018 test = new stack018(); 87 return test.doRun(); 88 } 89 90 private static boolean verbose; 91 private static PrintStream out; 92 93 private void display(Object message) { 94 if (!verbose) 95 return; 96 synchronized (out) { 97 out.println(message.toString()); 98 } 99 } 100 101 private int doRun() { 102 // 103 // Measure maximal recursion depth until stack overflow: 104 // 105 int maxDepth = 0; 106 for (depthToTry = 0; ; depthToTry += STEP) 107 try { 108 invokeRecurse(depthToTry); 109 maxDepth = depthToTry; 110 } catch (Throwable exception) { 111 Throwable target = getTargetException(exception); 112 if ((target instanceof StackOverflowError) || 113 (target instanceof OutOfMemoryError)) 114 break; // OK. 115 target.printStackTrace(out); 116 if (target instanceof ThreadDeath) 117 throw (ThreadDeath) target; 118 return 2; 119 } 120 out.println("Maximal recursion depth: " + maxDepth); 121 122 // 123 // Run the tested threads: 124 // 125 stack018 threads[] = new stack018[THREADS]; 126 for (int i = 0; i < threads.length; i++) { 127 threads[i] = new stack018(); 128 threads[i].setName("Thread: " + (i + 1) + "/" + THREADS); 129 threads[i].depthToTry = RESERVE * maxDepth; 130 threads[i].start(); 131 } 132 for (int i = 0; i < threads.length; i++) 133 if (threads[i].isAlive()) 134 try { 135 threads[i].join(); 136 } catch (InterruptedException exception) { 137 exception.printStackTrace(out); 138 return 2; 139 } 140 141 // 142 // Check if unexpected exceptions were thrown: 143 // 144 int exitCode = 0; 145 for (int i = 0; i < threads.length; i++) 146 if (threads[i].thrown != null) { 147 out.println("# " + threads[i].getName() 148 + ": " + threads[i].thrown); 149 exitCode = 2; 150 } 151 152 if (exitCode != 0) 153 out.println("# TEST FAILED"); 154 return exitCode; 155 } 156 157 private int depthToTry = 0; 158 private Throwable thrown = null; 159 160 public void run() { 161 String threadName = Thread.currentThread().getName(); 162 for (int i = 1; i <= CYCLES; i++) 163 try { 164 display(threadName + ", iteration: " + i + "/" + CYCLES); 165 invokeRecurse(depthToTry); 166 throw new Error("TEST_RFE: try deeper invocations!"); 167 168 } catch (Throwable exception) { 169 Throwable target = getTargetException(exception); 170 if ((target instanceof StackOverflowError) || 171 (target instanceof OutOfMemoryError)) 172 continue; // OK. 173 if (target instanceof ThreadDeath) 174 throw (ThreadDeath) target; 175 thrown = target; 176 break; 177 } 178 } 179 180 private static Throwable getTargetException(Throwable exception) { 181 Throwable target; 182 // 183 // Unwrap deep chain of exceptions to find StackOverflowError: 184 // 185 for ( 186 target = exception; 187 target instanceof InvocationTargetException; 188 target = ((InvocationTargetException) target).getTargetException() 189 ) 190 ; 191 return target; 192 } 193 194 private Method method = null; 195 private Object params[] = null; 196 197 private void invokeRecurse(int depth) throws Exception { 198 if (method == null) { 199 // 200 // Optimization trick: allocate once, use everywhere. 201 // 202 method = stack018.class.getMethod("recurse"); 203 params = new Object[]{}; 204 } 205 this.depth = depth; // actual parameter 206 method.invoke(this, params); 207 } 208 209 private int depth = 0; // actual parameter for recurse() 210 211 public void recurse() throws Exception { 212 if (depth > 0) 213 // 214 // Self-invoke via reflection: 215 // 216 invokeRecurse(depth - 1); 217 } 218 }