diff options
author | Andreas Gampe <agampe@google.com> | 2014-10-27 20:08:46 -0700 |
---|---|---|
committer | Andreas Gampe <agampe@google.com> | 2014-10-30 10:06:52 -0700 |
commit | 7c0381049ea33e64514984432312290842946bc1 (patch) | |
tree | 24a8928610ebc84a166f1b766f3f70799cd66a9d /runtime/verifier | |
parent | 0ea536897c078761e0309437a3d25fbbf53c94a3 (diff) | |
download | art-7c0381049ea33e64514984432312290842946bc1.tar.gz art-7c0381049ea33e64514984432312290842946bc1.tar.bz2 art-7c0381049ea33e64514984432312290842946bc1.zip |
ART: Do not abort on most verifier failures
Changes hard aborts to hard verifier failures, which rejects a
class instead of killing the process.
Bug: 17625962
(cherry picked from commit 8fa841aa1c02ff8e3e7caaa73ed5fe25f027d5d3)
Change-Id: Iba8e15676e13ea6dcd6e1e5d0484031d9ab52ae9
Diffstat (limited to 'runtime/verifier')
-rw-r--r-- | runtime/verifier/method_verifier.cc | 71 |
1 files changed, 61 insertions, 10 deletions
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index 80124517d7..6e792d4fe5 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -88,6 +88,23 @@ PcToRegisterLineTable::~PcToRegisterLineTable() { } } +// Note: returns true on failure. +ALWAYS_INLINE static inline bool FailOrAbort(MethodVerifier* verifier, bool condition, + const char* error_msg, uint32_t work_insn_idx) { + if (kIsDebugBuild) { + // In a debug build, abort if the error condition is wrong. + DCHECK(condition) << error_msg << work_insn_idx; + } else { + // In a non-debug build, just fail the class. + if (!condition) { + verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << error_msg << work_insn_idx; + return true; + } + } + + return false; +} + MethodVerifier::FailureKind MethodVerifier::VerifyClass(Thread* self, mirror::Class* klass, bool allow_soft_failures, @@ -2014,7 +2031,11 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { while (0 != instance_of_idx && !insn_flags_[instance_of_idx].IsOpcode()) { instance_of_idx--; } - CHECK(insn_flags_[instance_of_idx].IsOpcode()); + if (FailOrAbort(this, insn_flags_[instance_of_idx].IsOpcode(), + "Unable to get previous instruction of if-eqz/if-nez for work index ", + work_insn_idx_)) { + break; + } } else { break; } @@ -2072,7 +2093,11 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { while (0 != move_idx && !insn_flags_[move_idx].IsOpcode()) { move_idx--; } - CHECK(insn_flags_[move_idx].IsOpcode()); + if (FailOrAbort(this, insn_flags_[move_idx].IsOpcode(), + "Unable to get previous instruction of if-eqz/if-nez for work index ", + work_insn_idx_)) { + break; + } const Instruction* move_inst = Instruction::At(code_item_->insns_ + move_idx); switch (move_inst->Opcode()) { case Instruction::MOVE_OBJECT: @@ -3035,7 +3060,12 @@ const RegType& MethodVerifier::GetCaughtExceptionType() { // odd case, but nothing to do } else { common_super = &common_super->Merge(exception, ®_types_); - CHECK(reg_types_.JavaLangThrowable(false).IsAssignableFrom(*common_super)); + if (FailOrAbort(this, + reg_types_.JavaLangThrowable(false).IsAssignableFrom(*common_super), + "java.lang.Throwable is not assignable-from common_super at ", + work_insn_idx_)) { + break; + } } } } @@ -3360,18 +3390,32 @@ mirror::ArtMethod* MethodVerifier::GetQuickInvokedMethod(const Instruction* inst if (klass->IsInterface()) { // Derive Object.class from Class.class.getSuperclass(). mirror::Class* object_klass = klass->GetClass()->GetSuperClass(); - CHECK(object_klass->IsObjectClass()); + if (FailOrAbort(this, object_klass->IsObjectClass(), + "Failed to find Object class in quickened invoke receiver", + work_insn_idx_)) { + return nullptr; + } dispatch_class = object_klass; } else { dispatch_class = klass; } - CHECK(dispatch_class->HasVTable()) << PrettyDescriptor(dispatch_class); + if (FailOrAbort(this, dispatch_class->HasVTable(), + "Receiver class has no vtable for quickened invoke at ", + work_insn_idx_)) { + return nullptr; + } uint16_t vtable_index = is_range ? inst->VRegB_3rc() : inst->VRegB_35c(); - CHECK_LT(static_cast<int32_t>(vtable_index), dispatch_class->GetVTableLength()) - << PrettyDescriptor(klass) << " in method " - << PrettyMethod(dex_method_idx_, *dex_file_, true); + if (FailOrAbort(this, static_cast<int32_t>(vtable_index) < dispatch_class->GetVTableLength(), + "Receiver class has not enough vtable slots for quickened invoke at ", + work_insn_idx_)) { + return nullptr; + } mirror::ArtMethod* res_method = dispatch_class->GetVTableEntry(vtable_index); - CHECK(!self_->IsExceptionPending()); + if (FailOrAbort(this, !Thread::Current()->IsExceptionPending(), + "Unexpected exception pending for quickened invoke at ", + work_insn_idx_)) { + return nullptr; + } return res_method; } @@ -3384,7 +3428,14 @@ mirror::ArtMethod* MethodVerifier::VerifyInvokeVirtualQuickArgs(const Instructio Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Cannot infer method from " << inst->Name(); return nullptr; } - CHECK(!res_method->IsDirect() && !res_method->IsStatic()); + if (FailOrAbort(this, !res_method->IsDirect(), "Quick-invoked method is direct at ", + work_insn_idx_)) { + return nullptr; + } + if (FailOrAbort(this, !res_method->IsStatic(), "Quick-invoked method is static at ", + work_insn_idx_)) { + return nullptr; + } // We use vAA as our expected arg count, rather than res_method->insSize, because we need to // match the call to the signature. Also, we might be calling through an abstract method |