From 4d7b75f9cbcf99134c0a1c69b267b6bc8d94134e Mon Sep 17 00:00:00 2001 From: Igor Murashkin Date: Tue, 21 Jul 2015 17:03:36 -0700 Subject: [PATCH] verifier: Skip verification of methods when seeing experimental opcodes Bug: 22638098 Change-Id: I9f172f3e0e7ad2aa8873e4036415702fee6bf2eb --- runtime/verifier/method_verifier.cc | 27 +++++++++++++++++++++++---- runtime/verifier/method_verifier.h | 2 ++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index 764b6ba0a..8c950a061 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -329,14 +329,21 @@ MethodVerifier::FailureKind MethodVerifier::VerifyMethod(Thread* self, uint32_t } 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 @@ MethodVerifier::MethodVerifier(Thread* self, 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::VerifyInstructions() { } 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 d9334487f..a2835f56b 100644 --- a/runtime/verifier/method_verifier.h +++ b/runtime/verifier/method_verifier.h @@ -736,6 +736,8 @@ class MethodVerifier { // 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_; -- 2.11.0