1 /* 2 * Copyright (c) 2015, 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. 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 8087315 27 * @summary Get old method's stack trace elements after GC 28 * @library /test/lib 29 * @modules java.base/jdk.internal.misc 30 * @modules java.compiler 31 * java.instrument 32 * jdk.jartool/sun.tools.jar 33 * @run main RedefineClassHelper 34 * @run main/othervm -javaagent:redefineagent.jar RedefineRunningMethodsWithBacktrace 35 */ 36 37 import static jdk.test.lib.Asserts.*; 38 39 public class RedefineRunningMethodsWithBacktrace { 40 41 public static String newB = 42 "class RedefineRunningMethodsWithBacktrace$B {" + 43 " static int count1 = 0;" + 44 " static int count2 = 0;" + 45 " public static volatile boolean stop = false;" + 46 " static void localSleep() { " + 47 " try{ " + 48 " Thread.currentThread().sleep(10);" + 49 " } catch(InterruptedException ie) { " + 50 " } " + 51 " } " + 52 " public static void infinite() { " + 53 " System.out.println(\"infinite called\");" + 54 " }" + 55 " public static void throwable() { " + 56 " throw new RuntimeException(\"throwable called\");" + 57 " }" + 58 "}"; 59 60 public static String evenNewerB = 61 "class RedefineRunningMethodsWithBacktrace$B {" + 62 " static int count1 = 0;" + 63 " static int count2 = 0;" + 64 " public static volatile boolean stop = false;" + 65 " static void localSleep() { " + 66 " try{ " + 67 " Thread.currentThread().sleep(1);" + 68 " } catch(InterruptedException ie) { " + 69 " } " + 70 " } " + 71 " public static void infinite() { }" + 72 " public static void throwable() { " + 73 " throw new RuntimeException(\"throwable called\");" + 74 " }" + 75 "}"; 76 77 static class B { 78 static int count1 = 0; 79 static int count2 = 0; 80 public static volatile boolean stop = false; 81 static void localSleep() { 82 try { 83 Thread.currentThread().sleep(10);//sleep for 10 ms 84 } catch(InterruptedException ie) { 85 } 86 } 87 88 public static void infinite() { 89 while (!stop) { count1++; localSleep(); } 90 } 91 public static void throwable() { 92 // add some stuff to the original constant pool 93 String s1 = new String ("string1"); 94 String s2 = new String ("string2"); 95 String s3 = new String ("string3"); 96 String s4 = new String ("string4"); 97 String s5 = new String ("string5"); 98 String s6 = new String ("string6"); 99 String s7 = new String ("string7"); 100 String s8 = new String ("string8"); 101 String s9 = new String ("string9"); 102 String s10 = new String ("string10"); 103 String s11 = new String ("string11"); 104 String s12 = new String ("string12"); 105 String s13 = new String ("string13"); 106 String s14 = new String ("string14"); 107 String s15 = new String ("string15"); 108 String s16 = new String ("string16"); 109 String s17 = new String ("string17"); 110 String s18 = new String ("string18"); 111 String s19 = new String ("string19"); 112 throw new RuntimeException("throwable called"); 113 } 114 } 115 116 private static void touchRedefinedMethodInBacktrace(Throwable throwable) { 117 System.out.println("touchRedefinedMethodInBacktrace: "); 118 throwable.printStackTrace(); // this actually crashes with the bug in 119 // java_lang_StackTraceElement::create() 120 121 // Make sure that we can convert the backtrace, which is referring to 122 // the redefined method, to a StrackTraceElement[] without crashing. 123 StackTraceElement[] stackTrace = throwable.getStackTrace(); 124 for (int i = 0; i < stackTrace.length; i++) { 125 StackTraceElement frame = stackTrace[i]; 126 assertNotNull(frame.getClassName(), 127 "\nTest failed: trace[" + i + "].getClassName() returned null"); 128 assertNotNull(frame.getMethodName(), 129 "\nTest failed: trace[" + i + "].getMethodName() returned null"); 130 } 131 } 132 133 private static Throwable getThrowableInB() { 134 Throwable t = null; 135 try { 136 B.throwable(); 137 } catch (Exception e) { 138 t = e; 139 // Don't print here because Throwable will cache the constructed stacktrace 140 // e.printStackTrace(); 141 } 142 return t; 143 } 144 145 146 public static void main(String[] args) throws Exception { 147 148 new Thread() { 149 public void run() { 150 B.infinite(); 151 } 152 }.start(); 153 154 Throwable t1 = getThrowableInB(); 155 156 RedefineClassHelper.redefineClass(B.class, newB); 157 158 System.gc(); 159 160 Throwable t2 = getThrowableInB(); 161 162 B.infinite(); 163 164 for (int i = 0; i < 20 ; i++) { 165 String s = new String("some garbage"); 166 System.gc(); 167 } 168 169 RedefineClassHelper.redefineClass(B.class, evenNewerB); 170 System.gc(); 171 172 Throwable t3 = getThrowableInB(); 173 174 for (int i = 0; i < 20 ; i++) { 175 B.infinite(); 176 String s = new String("some garbage"); 177 System.gc(); 178 } 179 180 touchRedefinedMethodInBacktrace(t1); 181 touchRedefinedMethodInBacktrace(t2); 182 touchRedefinedMethodInBacktrace(t3); 183 184 // purge should clean everything up. 185 B.stop = true; 186 187 for (int i = 0; i < 20 ; i++) { 188 B.infinite(); 189 String s = new String("some garbage"); 190 System.gc(); 191 } 192 } 193 }