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