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 * @run main/othervm nsk.stress.stack.stack018 -eager 52 */ 53 54 package nsk.stress.stack; 55 56 57 import nsk.share.Harakiri; 58 59 import java.io.PrintStream; 60 import java.lang.reflect.InvocationTargetException; 61 import java.lang.reflect.Method; 62 63 public class stack018 extends Thread { 64 private final static int THREADS = 10; 65 private final static int CYCLES = 10; 66 private final static int STEP = 100; 67 private final static int RESERVE = 100; 68 69 public static void main(String[] args) { 70 int exitCode = run(args, System.out); 71 System.exit(exitCode + 95); 72 } 73 74 public static int run(String args[], PrintStream out) { 75 verbose = false; 76 boolean eager = false; 77 for (int i = 0; i < args.length; i++) 78 if (args[i].toLowerCase().equals("-verbose")) 79 verbose = true; 80 else if (args[i].toLowerCase().equals("-eager")) 81 eager = true; 82 if (!eager) 83 Harakiri.appoint(Harakiri.parseAppointment(args)); 84 stack018.out = out; 85 stack018 test = new stack018(); 86 return test.doRun(); 87 } 88 89 private static boolean verbose; 90 private static PrintStream out; 91 92 private void display(Object message) { 93 if (!verbose) 94 return; 95 synchronized (out) { 96 out.println(message.toString()); 97 } 98 } 99 100 private int doRun() { 101 // 102 // Measure maximal recursion depth until stack overflow: 103 // 104 int maxDepth = 0; 105 for (depthToTry = 0; ; depthToTry += STEP) 106 try { 107 invokeRecurse(depthToTry); 108 maxDepth = depthToTry; 109 } catch (Throwable exception) { 110 Throwable target = getTargetException(exception); 111 if ((target instanceof StackOverflowError) || 112 (target instanceof OutOfMemoryError)) 113 break; // OK. 114 target.printStackTrace(out); 115 if (target instanceof ThreadDeath) 116 throw (ThreadDeath) target; 117 return 2; 118 } 119 out.println("Maximal recursion depth: " + maxDepth); 120 121 // 122 // Run the tested threads: 123 // 124 stack018 threads[] = new stack018[THREADS]; 125 for (int i = 0; i < threads.length; i++) { 126 threads[i] = new stack018(); 127 threads[i].setName("Thread: " + (i + 1) + "/" + THREADS); 128 threads[i].depthToTry = RESERVE * maxDepth; 129 threads[i].start(); 130 } 131 for (int i = 0; i < threads.length; i++) 132 if (threads[i].isAlive()) 133 try { 134 threads[i].join(); 135 } catch (InterruptedException exception) { 136 exception.printStackTrace(out); 137 return 2; 138 } 139 140 // 141 // Check if unexpected exceptions were thrown: 142 // 143 int exitCode = 0; 144 for (int i = 0; i < threads.length; i++) 145 if (threads[i].thrown != null) { 146 out.println("# " + threads[i].getName() 147 + ": " + threads[i].thrown); 148 exitCode = 2; 149 } 150 151 if (exitCode != 0) 152 out.println("# TEST FAILED"); 153 return exitCode; 154 } 155 156 private int depthToTry = 0; 157 private Throwable thrown = null; 158 159 public void run() { 160 String threadName = Thread.currentThread().getName(); 161 for (int i = 1; i <= CYCLES; i++) 162 try { 163 display(threadName + ", iteration: " + i + "/" + CYCLES); 164 invokeRecurse(depthToTry); 165 throw new Error("TEST_RFE: try deeper invocations!"); 166 167 } catch (Throwable exception) { 168 Throwable target = getTargetException(exception); 169 if ((target instanceof StackOverflowError) || 170 (target instanceof OutOfMemoryError)) 171 continue; // OK. 172 if (target instanceof ThreadDeath) 173 throw (ThreadDeath) target; 174 thrown = target; 175 break; 176 } 177 } 178 179 private static Throwable getTargetException(Throwable exception) { 180 Throwable target; 181 // 182 // Unwrap deep chain of exceptions to find StackOverflowError: 183 // 184 for ( 185 target = exception; 186 target instanceof InvocationTargetException; 187 target = ((InvocationTargetException) target).getTargetException() 188 ) 189 ; 190 return target; 191 } 192 193 private Method method = null; 194 private Object params[] = null; 195 196 private void invokeRecurse(int depth) throws Exception { 197 if (method == null) { 198 // 199 // Optimization trick: allocate once, use everywhere. 200 // 201 method = stack018.class.getMethod("recurse"); 202 params = new Object[]{}; 203 } 204 this.depth = depth; // actual parameter 205 method.invoke(this, params); 206 } 207 208 private int depth = 0; // actual parameter for recurse() 209 210 public void recurse() throws Exception { 211 if (depth > 0) 212 // 213 // Self-invoke via reflection: 214 // 215 invokeRecurse(depth - 1); 216 } 217 }