• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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