verifier: Skip verification of methods when seeing experimental opcodes
Bug: 22638098
Change-Id: I9f172f3e0e7ad2aa8873e4036415702fee6bf2eb
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 764b6ba..8c950a0 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -329,14 +329,21 @@
} else {
// Bad method data.
CHECK_NE(verifier.failures_.size(), 0U);
- CHECK(verifier.have_pending_hard_failure_);
- verifier.DumpFailures(LOG(INFO) << "Verification error in "
- << PrettyMethod(method_idx, *dex_file) << "\n");
+
+ if (UNLIKELY(verifier.have_pending_experimental_failure_)) {
+ // Failed due to being forced into interpreter. This is ok because
+ // we just want to skip verification.
+ result = kSoftFailure;
+ } else {
+ CHECK(verifier.have_pending_hard_failure_);
+ verifier.DumpFailures(LOG(INFO) << "Verification error in "
+ << PrettyMethod(method_idx, *dex_file) << "\n");
+ result = kHardFailure;
+ }
if (gDebugVerify) {
std::cout << "\n" << verifier.info_messages_.str();
verifier.Dump(std::cout);
}
- result = kHardFailure;
}
if (kTimeVerifyMethod) {
uint64_t duration_ns = NanoTime() - start_ns;
@@ -402,6 +409,7 @@
monitor_enter_dex_pcs_(nullptr),
have_pending_hard_failure_(false),
have_pending_runtime_throw_failure_(false),
+ have_pending_experimental_failure_(false),
have_any_pending_runtime_throw_failure_(false),
new_instance_count_(0),
monitor_enter_count_(0),
@@ -813,6 +821,17 @@
}
bool MethodVerifier::VerifyInstruction(const Instruction* inst, uint32_t code_offset) {
+ if (UNLIKELY(inst->IsExperimental())) {
+ // Experimental instructions don't yet have verifier support implementation.
+ // While it is possible to use them by themselves, when we try to use stable instructions
+ // with a virtual register that was created by an experimental instruction,
+ // the data flow analysis will fail.
+ Fail(VERIFY_ERROR_FORCE_INTERPRETER)
+ << "experimental instruction is not supported by verifier; skipping verification";
+ have_pending_experimental_failure_ = true;
+ return false;
+ }
+
bool result = true;
switch (inst->GetVerifyTypeArgumentA()) {
case Instruction::kVerifyRegA:
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index d933448..a2835f5 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -736,6 +736,8 @@
// instructions that would hard fail the verification.
// Note: this flag is reset after processing each instruction.
bool have_pending_runtime_throw_failure_;
+ // Is there a pending experimental failure?
+ bool have_pending_experimental_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_;