ART: Fix wrong hard-failure handling in verifier

Correctly return null for the method when a hard failure is
encountered. Also improve logging for order failures. Add a
regression test.

Bug: 20224106

(cherry picked from commit 3b74e275838729c5023cd80116f1b3b81306ee19)

Change-Id: I6e08202617147378b204af169308b67fc69f92c6
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index f25e4ee..9faaa4a 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -2860,7 +2860,16 @@
   if (have_pending_hard_failure_) {
     if (Runtime::Current()->IsAotCompiler()) {
       /* When AOT compiling, check that the last failure is a hard failure */
-      CHECK_EQ(failures_[failures_.size() - 1], VERIFY_ERROR_BAD_CLASS_HARD);
+      if (failures_[failures_.size() - 1] != VERIFY_ERROR_BAD_CLASS_HARD) {
+        LOG(ERROR) << "Pending failures:";
+        for (auto& error : failures_) {
+          LOG(ERROR) << error;
+        }
+        for (auto& error_msg : failure_messages_) {
+          LOG(ERROR) << error_msg->str();
+        }
+        LOG(FATAL) << "Pending hard failure, but last failure not hard.";
+      }
     }
     /* immediate failure, reject class */
     info_messages_ << "Rejecting opcode " << inst->DumpString(dex_file_);
@@ -3358,13 +3367,13 @@
       if (!src_type.IsIntegralTypes()) {
         Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "register v" << get_reg << " has type " << src_type
             << " but expected " << reg_type;
-        return res_method;
+        return nullptr;
       }
     } else if (!work_line_->VerifyRegisterType(this, get_reg, reg_type)) {
       // Continue on soft failures. We need to find possible hard failures to avoid problems in the
       // compiler.
       if (have_pending_hard_failure_) {
-        return res_method;
+        return nullptr;
       }
     }
     sig_registers += reg_type.IsLongOrDoubleTypes() ?  2 : 1;
diff --git a/test/800-smali/expected.txt b/test/800-smali/expected.txt
index 5922257..a6b216b 100644
--- a/test/800-smali/expected.txt
+++ b/test/800-smali/expected.txt
@@ -15,4 +15,5 @@
 MoveExc
 MoveExceptionOnEntry
 EmptySparseSwitch
+b/20224106
 Done!
diff --git a/test/800-smali/smali/b_20224106.smali b/test/800-smali/smali/b_20224106.smali
new file mode 100644
index 0000000..78009db
--- /dev/null
+++ b/test/800-smali/smali/b_20224106.smali
@@ -0,0 +1,16 @@
+.class public LB20224106;
+
+# Test that a hard + soft verifier failure in invoke-interface does not lead to
+# an order abort (the last failure must be hard).
+
+.super Ljava/lang/Object;
+
+.method public static run(LB20224106;Ljava/lang/Object;)V
+    .registers 4
+    # Two failure points here:
+    # 1) There is a parameter type mismatch. The formal type is integral (int), but the actual
+    #    type is reference.
+    # 2) The receiver is not an interface or Object
+    invoke-interface {v2, v3}, Ljava/net/DatagramSocket;->checkPort(I)V
+    return-void
+.end method
diff --git a/test/800-smali/src/Main.java b/test/800-smali/src/Main.java
index 3e0b1f9..3e88364 100644
--- a/test/800-smali/src/Main.java
+++ b/test/800-smali/src/Main.java
@@ -79,6 +79,8 @@
             "moveExceptionOnEntry", new Object[]{0}, new VerifyError(), null));
         testCases.add(new TestCase("EmptySparseSwitch", "EmptySparseSwitch", "run", null, null,
                 null));
+        testCases.add(new TestCase("b/20224106", "B20224106", "run", null, new VerifyError(),
+                0));
     }
 
     public void runTests() {