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/d8/jack all 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 public static final class Impl { Impl()156 private Impl() {} throwCatchBaseTestExceptionTwiceImpl()157 public static void throwCatchBaseTestExceptionTwiceImpl() { 158 try { 159 try { 160 throw new TestException("throwCatchBaseTestExceptionTwice"); 161 } catch (BaseTestException t) { 162 System.out.println("Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\""); 163 if (PRINT_FULL_EXCEPTION) { 164 t.printStackTrace(System.out); 165 } 166 } 167 } catch (BaseTestException t) { 168 System.out.println("2nd Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\""); 169 if (PRINT_FULL_EXCEPTION) { 170 t.printStackTrace(System.out); 171 } 172 } 173 } 174 throwCatchTestExceptionTwiceImpl()175 public static void throwCatchTestExceptionTwiceImpl() { 176 try { 177 try { 178 throw new TestException("throwCatchTestExceptionTwice"); 179 } catch (TestException t) { 180 System.out.println("Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\""); 181 if (PRINT_FULL_EXCEPTION) { 182 t.printStackTrace(System.out); 183 } 184 } 185 } catch (TestException t) { 186 System.out.println("2nd Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\""); 187 if (PRINT_FULL_EXCEPTION) { 188 t.printStackTrace(System.out); 189 } 190 } 191 } 192 } 193 throwCatchBaseTestExceptionTwice()194 public static void throwCatchBaseTestExceptionTwice() { 195 // The implementation of this has to change depending upon the runtime slightly due to compiler 196 // optimizations present in DX/D8/Jack. 197 Impl.throwCatchBaseTestExceptionTwiceImpl(); 198 } 199 200 public static class DoThrowCatchBaseTestExceptionTwice implements Runnable { run()201 public void run() { throwCatchBaseTestExceptionTwice(); } 202 } 203 throwCatchTestException()204 public static void throwCatchTestException() { 205 try { 206 throw new TestException("throwCatchTestException"); 207 } catch (TestException t) { 208 System.out.println("Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\""); 209 if (PRINT_FULL_EXCEPTION) { 210 t.printStackTrace(System.out); 211 } 212 } 213 } 214 215 public static class DoThrowCatchTestException implements Runnable { run()216 public void run() { throwCatchTestException(); } 217 } 218 throwCatchTestExceptionTwice()219 public static void throwCatchTestExceptionTwice() { 220 // The implementation of this has to change depending upon the runtime slightly due to compiler 221 // optimizations present in DX/D8/Jack. 222 Impl.throwCatchTestExceptionTwiceImpl(); 223 } 224 225 public static class DoThrowCatchTestExceptionTwice implements Runnable { run()226 public void run() { throwCatchTestExceptionTwice(); } 227 } 228 throwCatchTestExceptionNoRethrow()229 public static void throwCatchTestExceptionNoRethrow() { 230 try { 231 throw new TestException("throwCatchTestExceptionNoRethrow"); 232 } catch (TestExceptionNoRethrow t) { 233 System.out.println("Caught " + t.getClass().getName() + ": \"" + t.getMessage() + "\""); 234 if (PRINT_FULL_EXCEPTION) { 235 t.printStackTrace(System.out); 236 } 237 } 238 } 239 240 public static class DoThrowCatchTestExceptionNoRethrow implements Runnable { run()241 public void run() { throwCatchTestExceptionNoRethrow(); } 242 } 243 run()244 public static void run() throws Exception { 245 // Set up breakpoints 246 Exceptions.setupExceptionTracing( 247 Test1929.class, 248 TestException.class, 249 null, 250 Test1929.class.getDeclaredMethod( 251 "ExceptionCatchEvent", 252 Thread.class, 253 Executable.class, 254 Long.TYPE, 255 Throwable.class)); 256 Exceptions.enableExceptionCatchEvent(Thread.currentThread()); 257 258 ExceptionHandler[] handlers = new ExceptionHandler[] { 259 new DoNothingHandler(), 260 new ThrowCatchBase(), 261 new ThrowBaseTestExceptionHandler(), 262 new ThrowTestExceptionNoRethrowHandler(), 263 }; 264 265 Runnable[] tests = new Runnable[] { 266 new DoThrowClass(), 267 new DoThrowCatchBaseTestException(), 268 new DoThrowCatchBaseTestExceptionTwice(), 269 new DoThrowCatchTestException(), 270 new DoThrowCatchTestExceptionTwice(), 271 new DoThrowCatchTestExceptionNoRethrow(), 272 }; 273 274 for (ExceptionHandler handler : handlers) { 275 for (Runnable test : tests) { 276 try { 277 HANDLER = handler; 278 System.out.printf("Test \"%s\": Running breakpoint with handler \"%s\"\n", 279 test.getClass().getName(), handler.getClass().getName()); 280 test.run(); 281 System.out.printf("Test \"%s\": No error caught with handler \"%s\"\n", 282 test.getClass().getName(), handler.getClass().getName()); 283 } catch (Throwable e) { 284 System.out.printf("Test \"%s\": Caught error %s:\"%s\" with handler \"%s\"\n", 285 test.getClass().getName(), 286 e.getClass().getName(), 287 e.getMessage(), 288 handler.getClass().getName()); 289 if (PRINT_FULL_EXCEPTION) { 290 e.printStackTrace(System.out); 291 } 292 } 293 System.out.printf("Test \"%s\": Finished running with handler \"%s\"\n", 294 test.getClass().getName(), handler.getClass().getName()); 295 HANDLER = null; 296 } 297 } 298 Exceptions.disableExceptionCatchEvent(Thread.currentThread()); 299 } 300 } 301