1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package art; 18 19 import java.util.Arrays; 20 import java.util.Collection; 21 import java.util.Objects; 22 import java.lang.reflect.Executable; 23 import java.lang.reflect.Method; 24 25 public class Test1929 { 26 public static boolean PRINT_FULL_EXCEPTION = false; 27 public static ExceptionHandler HANDLER = null; 28 public static Collection<Executable> TEST_METHODS; 29 doNothing()30 public static void doNothing() {}; 31 static { 32 try { 33 TEST_METHODS = Arrays.asList( 34 Test1929.class.getDeclaredMethod("doThrow"), 35 Test1929.class.getDeclaredMethod("throwCatchBaseTestException"), 36 Test1929.class.getDeclaredMethod("throwCatchBaseTestExceptionTwice"), 37 Test1929.class.getDeclaredMethod("throwCatchTestException"), 38 Test1929.class.getDeclaredMethod("throwCatchTestExceptionTwice"), 39 Test1929.class.getDeclaredMethod("throwCatchTestExceptionNoRethrow")); 40 } catch (Exception e) { 41 throw new Error("Unable to list test methods!", e); 42 } 43 } 44 45 public static interface ExceptionHandler { exceptionOccurred( Executable m, long loc, Throwable exception)46 public void exceptionOccurred( 47 Executable m, long loc, Throwable exception); 48 } 49 PrintStack()50 private static void PrintStack() { 51 System.out.println("\tCurrent Stack:"); 52 for (StackTrace.StackFrameData e : StackTrace.GetStackTrace(Thread.currentThread())) { 53 if (Objects.equals(e.method.getDeclaringClass().getPackage(), Test1929.class.getPackage())) { 54 System.out.println("\t\t" + e.method + " @ line = " + 55 Breakpoint.locationToLine(e.method, e.current_location)); 56 } 57 } 58 } 59 ExceptionCatchEvent( Thread thr, Executable method, long location, Throwable exception)60 public static void ExceptionCatchEvent( 61 Thread thr, Executable method, long location, Throwable exception) { 62 System.out.println(thr.getName() + ": " + method + " @ line = " + 63 Breakpoint.locationToLine(method, location) + " caught " + 64 exception.getClass() + ": " + exception.getMessage()); 65 PrintStack(); 66 if (PRINT_FULL_EXCEPTION) { 67 System.out.print("exception is: "); 68 exception.printStackTrace(System.out); 69 } 70 if (HANDLER != null && TEST_METHODS.contains(method)) { 71 HANDLER.exceptionOccurred(method, location, exception); 72 } 73 } 74 75 public static class BaseTestException extends Error { BaseTestException(String e)76 public BaseTestException(String e) { super(e); } BaseTestException(String e, Throwable t)77 public BaseTestException(String e, Throwable t) { super(e, t); } 78 } 79 public static class TestException extends BaseTestException { TestException(String e)80 public TestException(String e) { super(e); } TestException(String e, Throwable t)81 public TestException(String e, Throwable t) { super(e, t); } 82 } 83 84 public static class TestExceptionNoRethrow extends TestException { TestExceptionNoRethrow(String e)85 public TestExceptionNoRethrow(String e) { super(e); } TestExceptionNoRethrow(String e, Throwable t)86 public TestExceptionNoRethrow(String e, Throwable t) { super(e, t); } 87 } 88 89 public static class DoNothingHandler implements ExceptionHandler { exceptionOccurred(Executable m, long loc, Throwable exception)90 public void exceptionOccurred(Executable m, long loc, Throwable exception) { 91 System.out.println("\tDoing nothing!"); 92 return; 93 } 94 } 95 96 public static class ThrowCatchBase implements ExceptionHandler { exceptionOccurred(Executable m, long loc, Throwable exception)97 public void exceptionOccurred(Executable m, long loc, Throwable exception) { 98 System.out.println("\tThrowing BaseTestException and catching it!"); 99 try { 100 throw new BaseTestException("ThrowBaseHandler during throw from " + m + " @ line = " + 101 Breakpoint.locationToLine(m, loc), exception); 102 } catch (BaseTestException t) { 103 System.out.println("Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\""); 104 if (PRINT_FULL_EXCEPTION) { 105 t.printStackTrace(System.out); 106 } 107 } 108 } 109 } 110 public static class ThrowBaseTestExceptionHandler implements ExceptionHandler { exceptionOccurred(Executable m, long loc, Throwable exception)111 public void exceptionOccurred(Executable m, long loc, Throwable exception) { 112 System.out.println("\tThrowing BaseTestException!"); 113 throw new BaseTestException("ThrowBaseHandler during throw from " + m + " @ line = " + 114 Breakpoint.locationToLine(m, loc), exception); 115 } 116 } 117 118 public static class ThrowTestExceptionNoRethrowHandler implements ExceptionHandler { exceptionOccurred(Executable m, long loc, Throwable exception)119 public void exceptionOccurred(Executable m, long loc, Throwable exception) { 120 if (exception instanceof TestExceptionNoRethrow) { 121 System.out.println("\tInstance of TestExceptionNoRethrow was thrown. Not throwing again."); 122 } else { 123 System.out.println("\tThrowing TestExceptionNoRethrow!"); 124 throw new TestExceptionNoRethrow("ThrowTestExceptionNoRethrowHandler during throw from " + 125 m + " @ line = " + Breakpoint.locationToLine(m, loc), exception); 126 } 127 } 128 } doThrow()129 public static void doThrow() { 130 throw new TestException("doThrow"); 131 } 132 133 public static class DoThrowClass implements Runnable { run()134 public void run() { doThrow(); } 135 } 136 throwCatchBaseTestException()137 public static void throwCatchBaseTestException() { 138 try { 139 throw new TestException("throwCatchBaseTestException"); 140 } catch (BaseTestException t) { 141 System.out.println("Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\""); 142 if (PRINT_FULL_EXCEPTION) { 143 t.printStackTrace(System.out); 144 } 145 } 146 } 147 148 public static class DoThrowCatchBaseTestException implements Runnable { run()149 public void run() { throwCatchBaseTestException(); } 150 } 151 152 // dx and d8 do an optimization around catch blocks that (while legal) breaks assumptions 153 // this test relies on so we have the actual implementation be corrected smali. This does work 154 // for RI however. 155 156 // For reference: 157 158 // public static final class Impl { 159 // private Impl() {} 160 // public static void throwCatchBaseTestExceptionTwiceImpl() { 161 // try { 162 // try { 163 // throw new TestException("throwCatchBaseTestExceptionTwice"); 164 // } catch (BaseTestException t) { 165 // System.out.println("Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\""); 166 // if (PRINT_FULL_EXCEPTION) { 167 // t.printStackTrace(System.out); 168 // } 169 // } 170 // } catch (BaseTestException t) { 171 // System.out.println("2nd Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\""); 172 // if (PRINT_FULL_EXCEPTION) { 173 // t.printStackTrace(System.out); 174 // } 175 // } 176 // } 177 178 // public static void throwCatchTestExceptionTwiceImpl() { 179 // try { 180 // try { 181 // throw new TestException("throwCatchTestExceptionTwice"); 182 // } catch (TestException t) { 183 // System.out.println("Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\""); 184 // if (PRINT_FULL_EXCEPTION) { 185 // t.printStackTrace(System.out); 186 // } 187 // } 188 // } catch (TestException t) { 189 // System.out.println("2nd Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\""); 190 // if (PRINT_FULL_EXCEPTION) { 191 // t.printStackTrace(System.out); 192 // } 193 // } 194 // } 195 // } 196 throwCatchBaseTestExceptionTwice()197 public static void throwCatchBaseTestExceptionTwice() { 198 // The implementation of this has to change depending upon the runtime slightly due to compiler 199 // optimizations present in DX/D8/Jack. 200 try { 201 Class<?> Impl = Class.forName("art.Test1929$Impl"); 202 Method m = Impl.getMethod("throwCatchBaseTestExceptionTwiceImpl"); 203 m.invoke(null); 204 } catch (Exception e) { 205 e.printStackTrace(System.out); 206 } 207 } 208 209 public static class DoThrowCatchBaseTestExceptionTwice implements Runnable { run()210 public void run() { throwCatchBaseTestExceptionTwice(); } 211 } 212 throwCatchTestException()213 public static void throwCatchTestException() { 214 try { 215 throw new TestException("throwCatchTestException"); 216 } catch (TestException t) { 217 System.out.println("Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\""); 218 if (PRINT_FULL_EXCEPTION) { 219 t.printStackTrace(System.out); 220 } 221 } 222 } 223 224 public static class DoThrowCatchTestException implements Runnable { run()225 public void run() { throwCatchTestException(); } 226 } 227 throwCatchTestExceptionTwice()228 public static void throwCatchTestExceptionTwice() { 229 // The implementation of this has to change depending upon the runtime slightly due to compiler 230 // optimizations present in DX/D8/Jack. 231 try { 232 Class<?> Impl = Class.forName("art.Test1929$Impl"); 233 Method m = Impl.getMethod("throwCatchTestExceptionTwiceImpl"); 234 m.invoke(null); 235 } catch (Exception e) { 236 e.printStackTrace(System.out); 237 } 238 } 239 240 public static class DoThrowCatchTestExceptionTwice implements Runnable { run()241 public void run() { throwCatchTestExceptionTwice(); } 242 } 243 throwCatchTestExceptionNoRethrow()244 public static void throwCatchTestExceptionNoRethrow() { 245 try { 246 throw new TestException("throwCatchTestExceptionNoRethrow"); 247 } catch (TestExceptionNoRethrow t) { 248 System.out.println("Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\""); 249 if (PRINT_FULL_EXCEPTION) { 250 t.printStackTrace(System.out); 251 } 252 } 253 } 254 255 public static class DoThrowCatchTestExceptionNoRethrow implements Runnable { run()256 public void run() { throwCatchTestExceptionNoRethrow(); } 257 } 258 run()259 public static void run() throws Exception { 260 // Set up breakpoints 261 Exceptions.setupExceptionTracing( 262 Test1929.class, 263 TestException.class, 264 null, 265 Test1929.class.getDeclaredMethod( 266 "ExceptionCatchEvent", 267 Thread.class, 268 Executable.class, 269 Long.TYPE, 270 Throwable.class)); 271 Exceptions.enableExceptionCatchEvent(Thread.currentThread()); 272 273 ExceptionHandler[] handlers = new ExceptionHandler[] { 274 new DoNothingHandler(), 275 new ThrowCatchBase(), 276 new ThrowBaseTestExceptionHandler(), 277 new ThrowTestExceptionNoRethrowHandler(), 278 }; 279 280 Runnable[] tests = new Runnable[] { 281 new DoThrowClass(), 282 new DoThrowCatchBaseTestException(), 283 new DoThrowCatchBaseTestExceptionTwice(), 284 new DoThrowCatchTestException(), 285 new DoThrowCatchTestExceptionTwice(), 286 new DoThrowCatchTestExceptionNoRethrow(), 287 }; 288 289 for (ExceptionHandler handler : handlers) { 290 for (Runnable test : tests) { 291 try { 292 HANDLER = handler; 293 System.out.printf("Test \"%s\": Running breakpoint with handler \"%s\"\n", 294 test.getClass().getName(), handler.getClass().getName()); 295 test.run(); 296 System.out.printf("Test \"%s\": No error caught with handler \"%s\"\n", 297 test.getClass().getName(), handler.getClass().getName()); 298 } catch (Throwable e) { 299 System.out.printf("Test \"%s\": Caught error %s:\"%s\" with handler \"%s\"\n", 300 test.getClass().getName(), 301 e.getClass().getName(), 302 e.getMessage(), 303 handler.getClass().getName()); 304 if (PRINT_FULL_EXCEPTION) { 305 e.printStackTrace(System.out); 306 } 307 } 308 System.out.printf("Test \"%s\": Finished running with handler \"%s\"\n", 309 test.getClass().getName(), handler.getClass().getName()); 310 HANDLER = null; 311 } 312 } 313 Exceptions.disableExceptionCatchEvent(Thread.currentThread()); 314 } 315 } 316