1 /* 2 * Copyright (c) 2015, 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 8143214 27 * @summary Verify outputs of Thread.dumpStack() and Throwable.printStackTrace(). 28 * This test should also been run against jdk9 successfully except of 29 * VM option MemberNameInStackFrame. 30 * @run main/othervm DumpStackTest 31 */ 32 33 package test.java.lang.StackWalker; 34 35 import dalvik.system.VMStack; 36 import java.lang.invoke.MethodHandle; 37 import java.lang.invoke.MethodHandles; 38 import java.lang.invoke.MethodType; 39 import java.lang.reflect.Method; 40 import java.util.Arrays; 41 import java.util.concurrent.atomic.AtomicReference; 42 import java.util.function.Consumer; 43 44 public class DumpStackTest { 45 main(String args[])46 public static void main(String args[]) { 47 test(); 48 testThread(); 49 testLambda(); 50 testMethodInvoke(); 51 testMethodHandle(); 52 } 53 54 static class CallFrame { 55 final String classname; 56 final String methodname; CallFrame(Class<?> c, String methodname)57 CallFrame(Class<?> c, String methodname) { 58 this(c.getName(), methodname); 59 } CallFrame(String classname, String methodname)60 CallFrame(String classname, String methodname) { 61 this.classname = classname; 62 this.methodname = methodname; 63 } 64 getClassName()65 String getClassName() { 66 return classname; 67 } getMethodName()68 String getMethodName() { 69 return methodname; 70 } getFileName()71 String getFileName() { 72 int i = classname.lastIndexOf('.'); 73 int j = classname.lastIndexOf('$'); 74 String name = classname.substring(i+1, j >= 0 ? j : classname.length()); 75 return name + ".java"; 76 } 77 @Override toString()78 public String toString() { 79 return classname + "." + methodname + "(" + getFileName() + ")"; 80 } 81 } 82 test()83 static void test() { 84 CallFrame[] callStack = new CallFrame[] { 85 new CallFrame(Thread.class, "getStackTrace"), 86 new CallFrame(DumpStackTest.class, "test"), 87 new CallFrame(DumpStackTest.class, "main"), 88 // if invoked from jtreg 89 // Android-removed: libcore doesn't have such hidden frames for reflection. 90 // new CallFrame("jdk.internal.reflect.NativeMethodAccessorImpl", "invoke0"), // non-public class 91 // new CallFrame("jdk.internal.reflect.NativeMethodAccessorImpl", "invoke"), 92 // new CallFrame("jdk.internal.reflect.DelegatingMethodAccessorImpl", "invoke"), 93 new CallFrame(Method.class, "invoke"), 94 new CallFrame(Thread.class, "run"), 95 }; 96 97 assertStackTrace(Thread.currentThread().getStackTrace(), callStack); 98 getStackTrace(callStack); 99 } 100 getStackTrace(CallFrame[] callStack)101 static void getStackTrace(CallFrame[] callStack) { 102 // this method is the top of the stack 103 callStack[0] = new CallFrame(DumpStackTest.class, "getStackTrace"); 104 105 try { 106 throw new RuntimeException(); 107 } catch(RuntimeException ex) { 108 assertStackTrace(ex.getStackTrace(), callStack); 109 } 110 } testThread()111 static void testThread() { 112 // Android-changed: Avoid test process crash when throwing in the new thread. 113 AtomicReference<Throwable> th = new AtomicReference<>(); 114 Thread t1 = new Thread() { 115 public void run() { 116 try { 117 c(); 118 } catch (Throwable e) { 119 th.set(e); 120 } 121 } 122 123 void c() { 124 CallFrame[] callStack = new CallFrame[] { 125 new CallFrame(Thread.class, "getStackTrace"), 126 new CallFrame(this.getClass(), "c"), 127 new CallFrame(this.getClass(), "run") 128 }; 129 assertStackTrace(Thread.currentThread().getStackTrace(), callStack); 130 DumpStackTest.getStackTrace(callStack); 131 } 132 }; 133 t1.start(); 134 try { 135 t1.join(); 136 } catch(InterruptedException e) {} 137 if (th.get() != null) { 138 throw new AssertionError("Pending throwable.", th.get()); 139 } 140 } 141 testLambda()142 static void testLambda() { 143 Consumer<Void> c = (x) -> consumeLambda(); 144 c.accept(null); 145 } 146 consumeLambda()147 static void consumeLambda() { 148 CallFrame[] callStack = new CallFrame[]{ 149 new CallFrame(Thread.class, "getStackTrace"), 150 new CallFrame(DumpStackTest.class, "consumeLambda"), 151 new CallFrame(DumpStackTest.class, "lambda$testLambda$0"), 152 new CallFrame(DumpStackTest.class, "testLambda"), 153 new CallFrame(DumpStackTest.class, "main"), 154 // if invoked from jtreg 155 // Android-removed: libcore doesn't have such hidden frames for reflection. 156 // new CallFrame("jdk.internal.reflect.NativeMethodAccessorImpl", "invoke0"), 157 // new CallFrame("jdk.internal.reflect.NativeMethodAccessorImpl", "invoke"), 158 // new CallFrame("jdk.internal.reflect.DelegatingMethodAccessorImpl", "invoke"), 159 new CallFrame(Method.class, "invoke"), 160 new CallFrame(Thread.class, "run") 161 }; 162 assertStackTrace(Thread.currentThread().getStackTrace(), callStack); 163 DumpStackTest.getStackTrace(callStack); 164 } 165 testMethodInvoke()166 static void testMethodInvoke() { 167 try { 168 Method m = DumpStackTest.class.getDeclaredMethod("methodInvoke"); 169 m.invoke(null); 170 } catch(Exception e) { 171 throw new RuntimeException(e); 172 } 173 } 174 methodInvoke()175 static void methodInvoke() { 176 CallFrame[] callStack = new CallFrame[] { 177 new CallFrame(Thread.class, "getStackTrace"), 178 new CallFrame(DumpStackTest.class, "methodInvoke"), 179 // Android-removed: libcore doesn't have such hidden frames for reflection. 180 // new CallFrame("jdk.internal.reflect.NativeMethodAccessorImpl", "invoke0"), 181 // new CallFrame("jdk.internal.reflect.NativeMethodAccessorImpl", "invoke"), 182 // new CallFrame("jdk.internal.reflect.DelegatingMethodAccessorImpl", "invoke"), 183 new CallFrame(Method.class, "invoke"), 184 new CallFrame(DumpStackTest.class, "testMethodInvoke"), 185 new CallFrame(DumpStackTest.class, "main"), 186 // if invoked from jtreg 187 // Android-removed: libcore doesn't have such hidden frames for reflection. 188 // new CallFrame("jdk.internal.reflect.NativeMethodAccessorImpl", "invoke0"), 189 // new CallFrame("jdk.internal.reflect.NativeMethodAccessorImpl", "invoke"), 190 // new CallFrame("jdk.internal.reflect.DelegatingMethodAccessorImpl", "invoke"), 191 new CallFrame(Method.class, "invoke"), 192 new CallFrame(Thread.class, "run") 193 }; 194 assertStackTrace(Thread.currentThread().getStackTrace(), callStack); 195 DumpStackTest.getStackTrace(callStack); 196 } 197 testMethodHandle()198 static void testMethodHandle() { 199 MethodHandles.Lookup lookup = MethodHandles.lookup(); 200 try { 201 MethodHandle handle = lookup.findStatic(DumpStackTest.class, "methodHandle", 202 MethodType.methodType(void.class)); 203 handle.invoke(); 204 } catch(Throwable t) { 205 throw new RuntimeException(t); 206 } 207 } 208 methodHandle()209 static void methodHandle() { 210 CallFrame[] callStack = new CallFrame[]{ 211 new CallFrame(Thread.class, "getStackTrace"), 212 new CallFrame(DumpStackTest.class, "methodHandle"), 213 new CallFrame(DumpStackTest.class, "testMethodHandle"), 214 new CallFrame(DumpStackTest.class, "main"), 215 // if invoked from jtreg 216 // Android-removed: libcore doesn't have such hidden frames for reflection. 217 // new CallFrame("jdk.internal.reflect.NativeMethodAccessorImpl", "invoke0"), 218 // new CallFrame("jdk.internal.reflect.NativeMethodAccessorImpl", "invoke"), 219 // new CallFrame("jdk.internal.reflect.DelegatingMethodAccessorImpl", "invoke"), 220 new CallFrame(Method.class, "invoke"), 221 new CallFrame(Thread.class, "run") 222 }; 223 assertStackTrace(Thread.currentThread().getStackTrace(), callStack); 224 DumpStackTest.getStackTrace(callStack); 225 } 226 assertStackTrace(StackTraceElement[] actual, CallFrame[] expected)227 static void assertStackTrace(StackTraceElement[] actual, CallFrame[] expected) { 228 System.out.println("--- Actual ---"); 229 Arrays.stream(actual).forEach(e -> System.out.println(e)); 230 System.out.println("--- Expected ---"); 231 Arrays.stream(expected).forEach(e -> System.out.println(e)); 232 for (int i = 0, j = 0; i < actual.length; i++) { 233 // filter test framework classes 234 // Android-changed: Android uses different test infras. 235 // if (actual[i].getClassName().startsWith("com.sun.javatest.regtest")) 236 if (isAndroidTestInfra(actual[i].getClassName())) 237 continue; 238 // Android-added: dexer on Android generates extra class for lambda 239 if (actual[i].getClassName().contains("$$ExternalSyntheticLambda")) { 240 continue; 241 } 242 // Android-added: Due to http://b/240140214, we skip this call frame. 243 // TODO(http://b/240140214): Remove this patch when it's fixed. 244 if (VMStack.class.getName().equals(actual[i].getClassName()) && 245 "getThreadStackTrace".equals(actual[i].getMethodName())) { 246 continue; 247 } 248 assertEquals(actual[i], expected[j++], i); 249 } 250 } assertEquals(StackTraceElement actual, CallFrame expected, int idx)251 static void assertEquals(StackTraceElement actual, CallFrame expected, int idx) { 252 if (!actual.getClassName().equals(expected.getClassName()) || 253 !actual.getFileName().equals(expected.getFileName()) || 254 !actual.getMethodName().equals(expected.getMethodName())) { 255 throw new RuntimeException("StackTraceElements mismatch at index " + idx + 256 ". Expected [" + expected + "], but get [" + actual + "]"); 257 } 258 } 259 260 // Android-added: Extra function to filter Android test infra in stack frames. 261 private static final String[] ANDROID_INFRA_PACKAGES = new String[] { 262 "android.app.Instrumentation", 263 "androidx.test", 264 "com.android.cts", 265 "org.junit", 266 "org.testng", 267 "vogar.target", 268 }; isAndroidTestInfra(String classname)269 private static final boolean isAndroidTestInfra(String classname) { 270 for (String pkg : ANDROID_INFRA_PACKAGES) { 271 if (classname.startsWith(pkg)) { 272 return true; 273 } 274 } 275 return false; 276 } 277 } 278