[verifier]: flag instruction that will throw at runtime

We've accidentally changed the verifier behavior in:
https://android-review.googlesource.com/c/platform/art/+/1561956

We need to preserve the behavior of marking an instruction that will
throw at runtime, so that the code following it is not looked at. This
means that if there are verification failures in that "dead code", they
won't make the class not verified.

Test: 819-verification-runtime
Bug: 179227478
Bug: 179245053
Change-Id: I4526a98b9479f47102fb00bd65bb943fe6aa9c8e
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index c2ad314..f0f60e2 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -5543,6 +5543,10 @@
       case VERIFY_ERROR_ACCESS_METHOD:
       case VERIFY_ERROR_INSTANTIATION:
       case VERIFY_ERROR_CLASS_CHANGE:
+        if (!IsAotMode()) {
+          // If we fail again at runtime, mark that this instruction would throw.
+          flags_.have_pending_runtime_throw_failure_ = true;
+        }
         // How to handle runtime failures for instructions that are not flagged kThrow.
         //
         // The verifier may fail before we touch any instruction, for the signature of a method. So
@@ -5566,7 +5570,14 @@
         break;
 
       case VERIFY_ERROR_FORCE_INTERPRETER:
+        // This will be reported to the runtime as a soft failure.
+        break;
+
       case VERIFY_ERROR_LOCKING:
+        if (!IsAotMode()) {
+          // If we fail again at runtime, mark that this instruction would throw.
+          flags_.have_pending_runtime_throw_failure_ = true;
+        }
         // This will be reported to the runtime as a soft failure.
         break;
 
diff --git a/test/819-verification-runtime/expected-stderr.txt b/test/819-verification-runtime/expected-stderr.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/819-verification-runtime/expected-stderr.txt
diff --git a/test/819-verification-runtime/expected-stdout.txt b/test/819-verification-runtime/expected-stdout.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/819-verification-runtime/expected-stdout.txt
diff --git a/test/819-verification-runtime/info.txt b/test/819-verification-runtime/info.txt
new file mode 100644
index 0000000..bb641bb
--- /dev/null
+++ b/test/819-verification-runtime/info.txt
@@ -0,0 +1,2 @@
+Regression test for the verifier, where we need to keep the behavior of
+a known throwing instruction means the code following it is unreachable.
diff --git a/test/819-verification-runtime/smali/Main.smali b/test/819-verification-runtime/smali/Main.smali
new file mode 100644
index 0000000..623cfa3
--- /dev/null
+++ b/test/819-verification-runtime/smali/Main.smali
@@ -0,0 +1,40 @@
+# Copyright 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+.class public LMain;
+
+.super Ljava/lang/Object;
+
+.method public static main([Ljava/lang/String;)V
+  .registers 1
+  invoke-static {}, LMain;->softFail()I
+  return-void
+.end method
+
+.method public static softFail()I
+  .registers 1
+  sget v0, LMain;->test:I
+  if-eqz v0, :Lzero
+  # BecausenonExistentMethod does not exist, the verifier will
+  # consider this instructions as always throwing, and will not
+  # look at the return-void below.
+  invoke-static {}, LMain;->nonExistentMethod()V
+  # Normally, this should hard-fail the verification, but it is
+  # skipped due to the throwing instruction above.
+  return-void
+:Lzero
+  return v0
+.end method
+
+.field public static test:I
diff --git a/test/knownfailures.json b/test/knownfailures.json
index 5662327..20d4090 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -1011,6 +1011,7 @@
           "802-deoptimization",
           "804-class-extends-itself",
           "816-illegal-new-array",
+          "819-verification-runtime",
           "900-hello-plugin",
           "901-hello-ti-agent",
           "903-hello-tagging",