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 package test.java.lang.StackWalker; 25 26 import java.lang.reflect.InvocationTargetException; 27 import java.security.AccessController; 28 import java.security.PrivilegedAction; 29 import java.util.EnumSet; 30 import java.util.concurrent.atomic.AtomicLong; 31 import java.lang.StackWalker.StackFrame; 32 import java.lang.invoke.MethodHandle; 33 import java.lang.invoke.MethodHandles; 34 import java.lang.invoke.MethodType; 35 import java.util.Objects; 36 37 import org.testng.Assert; 38 import org.testng.annotations.Test; 39 40 import static java.lang.StackWalker.Option.*; 41 import static org.testng.Assert.assertEquals; 42 43 /** 44 * @test 45 * @bug 8140450 8197901 46 * @summary Verify stack trace information obtained with respect to StackWalker 47 * options, when the stack contains lambdas, method handle invoke 48 * virtual calls, and reflection. 49 * @run main/othervm VerifyStackTrace 50 * @run main/othervm/java.security.policy=stackwalk.policy VerifyStackTrace 51 * @author danielfuchs 52 */ 53 public class VerifyStackTrace { 54 55 static interface TestCase { walker()56 StackWalker walker(); description()57 String description(); expected()58 String expected(); 59 } 60 static final class TestCase1 implements TestCase { 61 private final StackWalker walker = StackWalker.getInstance(RETAIN_CLASS_REFERENCE); 62 63 private final String description = "StackWalker.getInstance(" + 64 "StackWalker.Option.RETAIN_CLASS_REFERENCE)"; 65 66 // Note: line numbers and lambda hashes will be erased when 67 // comparing stack traces. However, the stack may change 68 // if some methods are being renamed in the code base. 69 // If the JDKcode base changes and the test fails because of that, 70 // then after validating that the actual stack trace obtained 71 // is indeed correct (no frames are skipped that shouldn't) 72 // then you can cut & paste the <-- actual --> stack printed in the 73 // test output in here: 74 private final String expected = 75 // Android-changed: This test has a package name on Android. 76 /* 77 "1: VerifyStackTrace.lambda$test$1(VerifyStackTrace.java:209)\n" + 78 "2: VerifyStackTrace$Handle.execute(VerifyStackTrace.java:145)\n" + 79 "3: VerifyStackTrace$Handle.run(VerifyStackTrace.java:158)\n" + 80 "4: VerifyStackTrace.invoke(VerifyStackTrace.java:188)\n" + 81 "5: VerifyStackTrace$1.run(VerifyStackTrace.java:218)\n" + 82 "6: java.base/java.security.AccessController.doPrivileged(AccessController.java:310)\n" + 83 "7: VerifyStackTrace.test(VerifyStackTrace.java:227)\n" + 84 "8: VerifyStackTrace.main(VerifyStackTrace.java:182)\n"; 85 */ 86 "1: test.java.lang.StackWalker.VerifyStackTrace.lambda$test$1(VerifyStackTrace.java:209)\n" + 87 "2: test.java.lang.StackWalker.VerifyStackTrace$$ExternalSyntheticLambda1.run(Unknown Source:8)\n" + 88 "3: test.java.lang.StackWalker.VerifyStackTrace$Handle.execute(VerifyStackTrace.java:145)\n" + 89 "4: test.java.lang.StackWalker.VerifyStackTrace$Handle.run(VerifyStackTrace.java:158)\n" + 90 "5: test.java.lang.StackWalker.VerifyStackTrace.invoke(VerifyStackTrace.java:188)\n" + 91 "6: test.java.lang.StackWalker.VerifyStackTrace$1.run(VerifyStackTrace.java:218)\n" + 92 "7: java.security.AccessController.doPrivileged(AccessController.java:310)\n" + 93 "8: test.java.lang.StackWalker.VerifyStackTrace.test(VerifyStackTrace.java:227)\n" + 94 "9: test.java.lang.StackWalker.VerifyStackTrace.main(VerifyStackTrace.java:182)\n"; 95 walker()96 @Override public StackWalker walker() { return walker;} description()97 @Override public String description() { return description;} expected()98 @Override public String expected() { return expected;} 99 } 100 static final class TestCase2 implements TestCase { 101 private final StackWalker walker = StackWalker.getInstance( 102 EnumSet.of(RETAIN_CLASS_REFERENCE, SHOW_REFLECT_FRAMES)); 103 104 private final String description = "nStackWalker.getInstance(" + 105 "StackWalker.Option.RETAIN_CLASS_REFERENCE, " + 106 "StackWalker.Option.SHOW_REFLECT_FRAMES)"; 107 108 // Note: line numbers and lambda hashes will be erased when 109 // comparing stack traces. However, the stack may change 110 // if some methods are being renamed in the code base. 111 // If the JDK code base changes and the test fails because of that, 112 // then after validating that the actual stack trace obtained 113 // is indeed correct (no frames are skipped that shouldn't) 114 // then you can cut & paste the <-- actual --> stack printed in the 115 // test output in here (don't forget the final \n): 116 private final String expected = 117 // Android-changed: This test has a package name on Android, and implements 118 // lambda and OpenJDK classes with a different call chain. 119 /* 120 "1: VerifyStackTrace.lambda$test$1(VerifyStackTrace.java:211)\n" + 121 "2: VerifyStackTrace$Handle.execute(VerifyStackTrace.java:147)\n" + 122 "3: VerifyStackTrace$Handle.run(VerifyStackTrace.java:160)\n" + 123 "4: VerifyStackTrace.invoke(VerifyStackTrace.java:190)\n" + 124 "5: java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n" + 125 "6: java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\n" + 126 "7: java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n" + 127 "8: java.base/java.lang.reflect.Method.invoke(Method.java:520)\n" + 128 "9: VerifyStackTrace$1.run(VerifyStackTrace.java:220)\n" + 129 "10: java.base/java.security.AccessController.doPrivileged(AccessController.java:310)\n" + 130 "11: VerifyStackTrace.test(VerifyStackTrace.java:229)\n" + 131 "12: VerifyStackTrace.main(VerifyStackTrace.java:185)\n"; 132 */ 133 "1: test.java.lang.StackWalker.VerifyStackTrace.lambda$test$1(VerifyStackTrace.java:211)\n" + 134 "2: test.java.lang.StackWalker.VerifyStackTrace$$ExternalSyntheticLambda1.run(Unknown Source:8)\n" + 135 "3: test.java.lang.StackWalker.VerifyStackTrace$Handle.execute(VerifyStackTrace.java:147)\n" + 136 "4: test.java.lang.StackWalker.VerifyStackTrace$Handle.run(VerifyStackTrace.java:160)\n" + 137 "5: test.java.lang.StackWalker.VerifyStackTrace.invoke(VerifyStackTrace.java:190)\n" + 138 "6: java.lang.reflect.Method.invoke(Native Method)\n" + 139 "7: test.java.lang.StackWalker.VerifyStackTrace$1.run(VerifyStackTrace.java:220)\n" + 140 "8: java.security.AccessController.doPrivileged(AccessController.java:310)\n" + 141 "9: test.java.lang.StackWalker.VerifyStackTrace.test(VerifyStackTrace.java:229)\n" + 142 "10: test.java.lang.StackWalker.VerifyStackTrace.main(VerifyStackTrace.java:185)\n"; walker()143 @Override public StackWalker walker() { return walker;} description()144 @Override public String description() { return description;} expected()145 @Override public String expected() { return expected;} 146 } 147 static class TestCase3 implements TestCase { 148 private final StackWalker walker = StackWalker.getInstance( 149 EnumSet.of(RETAIN_CLASS_REFERENCE, SHOW_HIDDEN_FRAMES)); 150 151 private final String description = "StackWalker.getInstance(" + 152 "StackWalker.Option.RETAIN_CLASS_REFERENCE, " + 153 "StackWalker.Option.SHOW_HIDDEN_FRAMES)"; 154 155 // Note: line numbers and lambda hashes will be erased when 156 // comparing stack traces. However, the stack may change 157 // if some methods are being renamed in the code base. 158 // If the JDK code base changes and the test fails because of that, 159 // then after validating that the actual stack trace obtained 160 // is indeed correct (no frames are skipped that shouldn't) 161 // then you can cut & paste the <-- actual --> stack printed in the 162 // test output in here (don't forget the final \n): 163 private final String expected = 164 // Android-changed: This test has a package name on Android, and implements 165 // lambda and OpenJDK classes with a different call chain. 166 /* 167 "1: VerifyStackTrace.lambda$test$1(VerifyStackTrace.java:213)\n" + 168 "2: VerifyStackTrace$$Lambda$1/0x00000007c0089430.run(Unknown Source)\n" + 169 "3: VerifyStackTrace$Handle.execute(VerifyStackTrace.java:149)\n" + 170 "4: java.base/java.lang.invoke.LambdaForm$DMH/0x00000007c008a830.invokeVirtual_LL_V(LambdaForm$DMH)\n" + 171 "5: java.base/java.lang.invoke.LambdaForm$MH/0x00000007c008a830.invoke_MT(LambdaForm$MH)\n" + 172 "6: VerifyStackTrace$Handle.run(VerifyStackTrace.java:162)\n" + 173 "7: VerifyStackTrace.invoke(VerifyStackTrace.java:192)\n" + 174 "8: java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n" + 175 "9: java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\n" + 176 "10: java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n" + 177 "11: java.base/java.lang.reflect.Method.invoke(Method.java:520)\n" + 178 "12: VerifyStackTrace$1.run(VerifyStackTrace.java:222)\n" + 179 "13: java.base/java.security.AccessController.executePrivileged(AccessController.java:759)\n" + 180 "14: java.base/java.security.AccessController.doPrivileged(AccessController.java:310)\n" + 181 "15: VerifyStackTrace.test(VerifyStackTrace.java:231)\n" + 182 "16: VerifyStackTrace.main(VerifyStackTrace.java:188)\n"; 183 */ 184 "1: test.java.lang.StackWalker.VerifyStackTrace.lambda$test$1(VerifyStackTrace.java:213)\n" + 185 "2: test.java.lang.StackWalker.VerifyStackTrace$$ExternalSyntheticLambda1.run(Unknown Source:8)\n" + 186 "3: test.java.lang.StackWalker.VerifyStackTrace$Handle.execute(VerifyStackTrace.java:149)\n" + 187 "4: test.java.lang.StackWalker.VerifyStackTrace$Handle.run(VerifyStackTrace.java:162)\n" + 188 "5: test.java.lang.StackWalker.VerifyStackTrace.invoke(VerifyStackTrace.java:192)\n" + 189 "6: java.lang.reflect.Method.invoke(Native Method)\n" + 190 "7: test.java.lang.StackWalker.VerifyStackTrace$1.run(VerifyStackTrace.java:222)\n" + 191 "8: java.security.AccessController.doPrivileged(AccessController.java:310)\n" + 192 "9: test.java.lang.StackWalker.VerifyStackTrace.test(VerifyStackTrace.java:231)\n" + 193 "10: test.java.lang.StackWalker.VerifyStackTrace.main(VerifyStackTrace.java:188)\n"; walker()194 @Override public StackWalker walker() { return walker;} description()195 @Override public String description() { return description;} expected()196 @Override public String expected() { return expected;} 197 } 198 199 static final class TestCase4 extends TestCase3 { 200 private final StackWalker walker = StackWalker.getInstance( 201 EnumSet.allOf(StackWalker.Option.class)); 202 203 private final String description = "StackWalker.getInstance(" + 204 "StackWalker.Option.RETAIN_CLASS_REFERENCE, " + 205 "StackWalker.Option.SHOW_HIDDEN_FRAMES, " + 206 "StackWalker.Option.SHOW_REFLECT_FRAMES)"; 207 walker()208 @Override public StackWalker walker() {return walker;} description()209 @Override public String description() {return description;} 210 } 211 212 public static class Handle implements Runnable { 213 214 Runnable impl; Handle(Runnable run)215 public Handle(Runnable run) { 216 this.impl = run; 217 } 218 execute(Runnable run)219 public void execute(Runnable run) { 220 run.run(); 221 } 222 run()223 public void run() { 224 MethodHandles.Lookup lookup = MethodHandles.lookup(); 225 MethodHandle handle = null; 226 try { 227 handle = lookup.findVirtual(Handle.class, "execute", 228 MethodType.methodType(void.class, Runnable.class)); 229 } catch(NoSuchMethodException | IllegalAccessException x) { 230 throw new RuntimeException(x); 231 } 232 try { 233 handle.invoke(this, impl); 234 } catch(Error | RuntimeException x) { 235 throw x; 236 } catch(Throwable t) { 237 throw new RuntimeException(t); 238 } 239 } 240 } 241 prepare(String produced, boolean eraseSensitiveInfo)242 static String prepare(String produced, boolean eraseSensitiveInfo) { 243 if (eraseSensitiveInfo) { 244 // Erase sensitive information before comparing: 245 // comparing line numbers is too fragile, so we just erase them 246 // out before comparing. We also erase the hash-like names of 247 // synthetic frames introduced by lambdas & method handles 248 return produced.replaceAll(":[1-9][0-9]*\\)", ":00)") 249 .replaceAll("/0x[0-9a-f]+\\.run", "/xxxxxxxx.run") 250 .replaceAll("/0x[0-9a-f]+\\.invoke", "/xxxxxxxx.invoke") 251 // LFs may or may not be pre-generated, making frames differ 252 .replaceAll("DirectMethodHandle\\$Holder", "LambdaForm\\$DMH") 253 .replaceAll("Invokers\\$Holder", "LambdaForm\\$MH") 254 .replaceAll("MH\\.invoke", "MH/xxxxxxxx.invoke") 255 // invoke frames may or may not have basic method type 256 // information encoded for diagnostic purposes 257 .replaceAll("xx\\.invoke([A-Za-z]*)_[A-Z_]+", "xx.invoke$1") 258 .replaceAll("\\$[0-9]+", "\\$??"); 259 } else { 260 return produced; 261 } 262 } 263 264 // Android-changed: Add @Test annotation. 265 // public static void main(String[] args) { 266 @Test main()267 public static void main() { 268 test(new TestCase1()); 269 test(new TestCase2()); 270 test(new TestCase3()); 271 test(new TestCase4()); 272 } 273 invoke(Runnable run)274 public static void invoke(Runnable run) { 275 run.run(); 276 } 277 278 static final class Recorder { 279 boolean found; // stop recording after main recordSTE(long counter, StringBuilder s, StackFrame f)280 public void recordSTE(long counter, StringBuilder s, StackFrame f) { 281 if (found) return; 282 found = VerifyStackTrace.class.equals(f.getDeclaringClass()) && 283 "main".equals(f.getMethodName()); 284 String line = String.format("%d: %s", counter, f.toStackTraceElement()); 285 s.append(line).append('\n'); 286 System.out.println(line); 287 } 288 } 289 290 test(TestCase test)291 static void test(TestCase test) { 292 System.out.println("\nTesting: " + test.description()); 293 final AtomicLong counter = new AtomicLong(); 294 final StringBuilder builder = new StringBuilder(); 295 final Recorder recorder = new Recorder(); 296 final Runnable run = () -> test.walker().forEach( 297 f -> recorder.recordSTE(counter.incrementAndGet(), builder, f)); 298 final Handle handle = new Handle(run); 299 300 // We're not using lambda on purpose here. We want the anonymous 301 // class on the stack. 302 PrivilegedAction<Object> pa = new PrivilegedAction<Object>() { 303 @Override 304 public Object run() { 305 try { 306 return VerifyStackTrace.class 307 .getMethod("invoke", Runnable.class) 308 .invoke(null, handle); 309 } catch (NoSuchMethodException 310 | IllegalAccessException 311 | InvocationTargetException ex) { 312 System.out.flush(); 313 throw new RuntimeException(ex); 314 } 315 } 316 }; 317 AccessController.doPrivileged(pa); 318 System.out.println("Main found: " + recorder.found); 319 assertEquals(prepare(builder.toString(), true), prepare(test.expected(), true)); 320 // Android-changed: Replace System.out because the output is invisible to Tradefed. 321 /* 322 if (!Objects.equals(prepare(test.expected(), true), prepare(builder.toString(), true))) { 323 System.out.flush(); 324 try { 325 // sleep to make it less likely that System.out & System.err will 326 // interleave. 327 Thread.sleep(1000); 328 } catch (InterruptedException ex) { 329 } 330 System.err.println("\nUnexpected stack trace: " 331 + "\n<!-- expected -->\n" 332 + prepare(test.expected(), true) 333 + "\n<-- actual -->\n" 334 + prepare(builder.toString(), false)); 335 throw new RuntimeException("Unexpected stack trace for: " + test.description()); 336 } 337 */ 338 } 339 340 341 } 342