OSDN Git Service

ART: Also accept java.lang.Throwable as a catch-all handler.
authorAndreas Gampe <agampe@google.com>
Fri, 18 Jul 2014 22:41:00 +0000 (15:41 -0700)
committerAndreas Gampe <agampe@google.com>
Fri, 18 Jul 2014 23:52:23 +0000 (16:52 -0700)
Accept catch handlers with catch type of java.lang.Throwable as
catch-all handlers.

(cherry picked from commit f91baf17ad11a86c84c9fc34ff70feee65a43233)

Bug: 16308310
Change-Id: Ie9b9582ee71c94c82b7695dc6f9c2c6df3d869d8

runtime/verifier/method_verifier.cc

index 8464b13..c0e4ae7 100644 (file)
@@ -2772,12 +2772,30 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
    * "try" block when they throw, control transfers out of the method.)
    */
   if ((opcode_flags & Instruction::kThrow) != 0 && insn_flags_[work_insn_idx_].IsInTry()) {
-    bool within_catch_all = false;
+    bool has_catch_all_handler = false;
     CatchHandlerIterator iterator(*code_item_, work_insn_idx_);
 
+    // Need the linker to try and resolve the handled class to check if it's Throwable.
+    ClassLinker* linker = Runtime::Current()->GetClassLinker();
+
     for (; iterator.HasNext(); iterator.Next()) {
-      if (iterator.GetHandlerTypeIndex() == DexFile::kDexNoIndex16) {
-        within_catch_all = true;
+      uint16_t handler_type_idx = iterator.GetHandlerTypeIndex();
+      if (handler_type_idx == DexFile::kDexNoIndex16) {
+        has_catch_all_handler = true;
+      } else {
+        // It is also a catch-all if it is java.lang.Throwable.
+        mirror::Class* klass = linker->ResolveType(*dex_file_, handler_type_idx, *dex_cache_,
+                                                   *class_loader_);
+        if (klass != nullptr) {
+          if (klass == mirror::Throwable::GetJavaLangThrowable()) {
+            has_catch_all_handler = true;
+          }
+        } else {
+          // Clear exception.
+          Thread* self = Thread::Current();
+          DCHECK(self->IsExceptionPending());
+          self->ClearException();
+        }
       }
       /*
        * Merge registers into the "catch" block. We want to use the "savedRegs" rather than
@@ -2793,7 +2811,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
      * If the monitor stack depth is nonzero, there must be a "catch all" handler for this
      * instruction. This does apply to monitor-exit because of async exception handling.
      */
-    if (work_line_->MonitorStackDepth() > 0 && !within_catch_all) {
+    if (work_line_->MonitorStackDepth() > 0 && !has_catch_all_handler) {
       /*
        * The state in work_line reflects the post-execution state. If the current instruction is a
        * monitor-enter and the monitor stack was empty, we don't need a catch-all (if it throws,