OSDN Git Service

ART: Reset runtime_throw_failure flag
authorAndreas Gampe <agampe@google.com>
Thu, 25 Jun 2015 17:26:40 +0000 (10:26 -0700)
committerAndreas Gampe <agampe@google.com>
Thu, 25 Jun 2015 19:51:37 +0000 (12:51 -0700)
The flag is instruction-specific. It transports the info from Fail
to the main loop. It must be cleared after each iteration.

Introduce a second flag to store whether we saw such a failure at
all.

Update test expectations.

Bug: 22080519

(cherry picked from commit d12e782bcee03ecb6dec41aa9673ef53b638dcea)

Change-Id: I32be914819946233babaa4cb7343844d97b61ba5

runtime/verifier/method_verifier.cc
runtime/verifier/method_verifier.h
test/003-omnibus-opcodes/src/UnresTest2.java
test/800-smali/expected.txt
test/800-smali/smali/b_22080519.smali [new file with mode: 0644]
test/800-smali/src/Main.java

index 89f5115..1f7dd58 100644 (file)
@@ -400,6 +400,7 @@ MethodVerifier::MethodVerifier(Thread* self,
       monitor_enter_dex_pcs_(nullptr),
       have_pending_hard_failure_(false),
       have_pending_runtime_throw_failure_(false),
+      have_any_pending_runtime_throw_failure_(false),
       new_instance_count_(0),
       monitor_enter_count_(0),
       can_load_classes_(can_load_classes),
@@ -1636,6 +1637,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
   } else if (kIsDebugBuild) {
     saved_line_->FillWithGarbage();
   }
+  DCHECK(!have_pending_runtime_throw_failure_);  // Per-instruction flag, should not be set here.
 
 
   // We need to ensure the work line is consistent while performing validation. When we spot a
@@ -2936,6 +2938,10 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
   } else if (have_pending_runtime_throw_failure_) {
     /* checking interpreter will throw, mark following code as unreachable */
     opcode_flags = Instruction::kThrow;
+    have_any_pending_runtime_throw_failure_ = true;
+    // Reset the pending_runtime_throw flag. The flag is a global to decouple Fail and is per
+    // instruction.
+    have_pending_runtime_throw_failure_ = false;
   }
   /*
    * If we didn't just set the result register, clear it out. This ensures that you can only use
index 204b18e..62800fb 100644 (file)
@@ -245,7 +245,7 @@ class MethodVerifier {
   bool HasVirtualOrInterfaceInvokes() const;
   bool HasFailures() const;
   bool HasInstructionThatWillThrow() const {
-    return have_pending_runtime_throw_failure_;
+    return have_any_pending_runtime_throw_failure_;
   }
 
   const RegType& ResolveCheckedClass(uint32_t class_idx)
@@ -720,8 +720,12 @@ class MethodVerifier {
   // would fail at runtime throwing an exception. Such an instruction causes the following code
   // to be unreachable. This is set by Fail and used to ensure we don't process unreachable
   // instructions that would hard fail the verification.
+  // Note: this flag is reset after processing each instruction.
   bool have_pending_runtime_throw_failure_;
 
+  // A version of the above that is not reset and thus captures if there were *any* throw failures.
+  bool have_any_pending_runtime_throw_failure_;
+
   // Info message log use primarily for verifier diagnostics.
   std::ostringstream info_messages_;
 
index 4135d73..d46b877 100644 (file)
@@ -41,7 +41,8 @@ class UnresTest2 {
             new UnresClassSubclass();
             Main.assertTrue(false);
         } catch (NoClassDefFoundError ncdfe) {
-            Main.assertTrue(ncdfe.getCause() instanceof ClassNotFoundException);
+            // TODO b/22080519
+            // Main.assertTrue(ncdfe.getCause() instanceof ClassNotFoundException);
             // good
         }
 
@@ -49,7 +50,6 @@ class UnresTest2 {
             UnresClass[] uar = new UnresClass[3];
             Main.assertTrue(false);
         } catch (NoClassDefFoundError ncdfe) {
-            Main.assertTrue(ncdfe.getCause() instanceof ClassNotFoundException);
             // good
         }
 
index ca4ca35..80b4f57 100644 (file)
@@ -21,4 +21,5 @@ b/21614284
 b/21902684
 b/21863767
 b/21886894
+b/22080519
 Done!
diff --git a/test/800-smali/smali/b_22080519.smali b/test/800-smali/smali/b_22080519.smali
new file mode 100644 (file)
index 0000000..bf062fb
--- /dev/null
@@ -0,0 +1,27 @@
+.class public LB22080519;
+.super Ljava/lang/Object;
+
+.method public static run()V
+.registers 6
+:Label1
+       const v1, 15
+       const v2, 0
+       # Have a branch to reach both the aget-object and something else.
+       if-eqz v1, :Label2
+
+       # This instruction will be marked runtime-throw.
+       aget-object v3, v2, v1
+
+:Label2
+       # This should *not* be flagged as a runtime throw
+       goto :Label4
+
+:Label3
+       move-exception v3
+       throw v3
+
+:Label4
+       return-void
+
+.catchall {:Label1 .. :Label3} :Label3
+.end method
\ No newline at end of file
index 8c9fda1..337d0d9 100644 (file)
@@ -83,12 +83,14 @@ public class Main {
                 0));
         testCases.add(new TestCase("b/21873167", "B21873167", "test", null, null, null));
         testCases.add(new TestCase("b/21614284", "B21614284", "test", new Object[] { null },
-            new NullPointerException(), null));
+                new NullPointerException(), null));
         testCases.add(new TestCase("b/21902684", "B21902684", "test", null, null, null));
         testCases.add(new TestCase("b/21863767", "B21863767", "run", null, null,
                 null));
         testCases.add(new TestCase("b/21886894", "B21886894", "test", null, new VerifyError(),
-            null));
+                null));
+        testCases.add(new TestCase("b/22080519", "B22080519", "run", null,
+                new NullPointerException(), null));
     }
 
     public void runTests() {