From f00baf56ef647684888a407dbb6adadd704a2039 Mon Sep 17 00:00:00 2001 From: Mathieu Chartier Date: Fri, 8 May 2015 14:19:26 -0700 Subject: [PATCH] Check IsReferenceVReg during deopt Required since the quick GC maps may not agree with the verifier ones. Without this check we may copy stale object references into the shadow frame. Bug: 20736048 Change-Id: I7783c8a8ee45cf601b08b4c38f1dec7f7d11380c --- runtime/quick_exception_handler.cc | 5 ++++- runtime/stack.cc | 28 ++++++++++++++++++++++++++++ runtime/stack.h | 3 +++ runtime/thread.cc | 4 ---- runtime/utils.h | 5 +++++ 5 files changed, 40 insertions(+), 5 deletions(-) diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc index 243260345..4b65b11ad 100644 --- a/runtime/quick_exception_handler.cc +++ b/runtime/quick_exception_handler.cc @@ -222,7 +222,10 @@ class DeoptimizeStackVisitor FINAL : public StackVisitor { break; case kReferenceVReg: { uint32_t value = 0; - if (GetVReg(h_method.Get(), reg, kind, &value)) { + // Check IsReferenceVReg in case the compiled GC map doesn't agree with the verifier. + // We don't want to copy a stale reference into the shadow frame as a reference. + // b/20736048 + if (GetVReg(h_method.Get(), reg, kind, &value) && IsReferenceVReg(h_method.Get(), reg)) { new_frame->SetVRegReference(reg, reinterpret_cast(value)); } else { new_frame->SetVReg(reg, kDeadValue); diff --git a/runtime/stack.cc b/runtime/stack.cc index e49bc1d78..a566886d7 100644 --- a/runtime/stack.cc +++ b/runtime/stack.cc @@ -19,6 +19,7 @@ #include "arch/context.h" #include "base/hex_dump.h" #include "entrypoints/runtime_asm_entrypoints.h" +#include "gc_map.h" #include "mirror/art_method-inl.h" #include "mirror/class-inl.h" #include "mirror/object.h" @@ -151,6 +152,33 @@ size_t StackVisitor::GetNativePcOffset() const { return GetMethod()->NativeQuickPcOffset(cur_quick_frame_pc_); } +bool StackVisitor::IsReferenceVReg(mirror::ArtMethod* m, uint16_t vreg) { + // Process register map (which native and runtime methods don't have) + if (m->IsNative() || m->IsRuntimeMethod() || m->IsProxyMethod()) { + return false; + } + if (m->IsOptimized(sizeof(void*))) { + return true; // TODO: Implement. + } + const uint8_t* native_gc_map = m->GetNativeGcMap(sizeof(void*)); + CHECK(native_gc_map != nullptr) << PrettyMethod(m); + const DexFile::CodeItem* code_item = m->GetCodeItem(); + // Can't be null or how would we compile its instructions? + DCHECK(code_item != nullptr) << PrettyMethod(m); + NativePcOffsetToReferenceMap map(native_gc_map); + size_t num_regs = std::min(map.RegWidth() * 8, static_cast(code_item->registers_size_)); + const uint8_t* reg_bitmap = nullptr; + if (num_regs > 0) { + Runtime* runtime = Runtime::Current(); + const void* entry_point = runtime->GetInstrumentation()->GetQuickCodeFor(m, sizeof(void*)); + uintptr_t native_pc_offset = m->NativeQuickPcOffset(GetCurrentQuickFramePc(), entry_point); + reg_bitmap = map.FindBitMap(native_pc_offset); + DCHECK(reg_bitmap != nullptr); + } + // Does this register hold a reference? + return vreg < num_regs && TestBitmap(vreg, reg_bitmap); +} + bool StackVisitor::GetVReg(mirror::ArtMethod* m, uint16_t vreg, VRegKind kind, uint32_t* val) const { if (cur_quick_frame_ != nullptr) { diff --git a/runtime/stack.h b/runtime/stack.h index e2af5eefd..71a5dec41 100644 --- a/runtime/stack.h +++ b/runtime/stack.h @@ -472,6 +472,9 @@ class StackVisitor { bool GetNextMethodAndDexPc(mirror::ArtMethod** next_method, uint32_t* next_dex_pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + bool IsReferenceVReg(mirror::ArtMethod* m, uint16_t vreg) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + bool GetVReg(mirror::ArtMethod* m, uint16_t vreg, VRegKind kind, uint32_t* val) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); diff --git a/runtime/thread.cc b/runtime/thread.cc index c8aad1b78..605a1b541 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -2311,10 +2311,6 @@ class ReferenceMapVisitor : public StackVisitor { } } - static bool TestBitmap(size_t reg, const uint8_t* reg_vector) { - return ((reg_vector[reg / kBitsPerByte] >> (reg % kBitsPerByte)) & 0x01) != 0; - } - // Visitor for when we visit a root. RootVisitor& visitor_; }; diff --git a/runtime/utils.h b/runtime/utils.h index eaafcf0a6..71ccf8527 100644 --- a/runtime/utils.h +++ b/runtime/utils.h @@ -604,6 +604,11 @@ std::unique_ptr MakeUnique(Args&& ... args) { return std::unique_ptr(new T(std::forward(args)...)); } +inline bool TestBitmap(size_t idx, const uint8_t* bitmap) { + return ((bitmap[idx / kBitsPerByte] >> (idx % kBitsPerByte)) & 0x01) != 0; +} + + } // namespace art #endif // ART_RUNTIME_UTILS_H_ -- 2.11.0