From 59fe711f88191cd8ca1a386c4fa0d2f9e484af50 Mon Sep 17 00:00:00 2001 From: Mathieu Chartier Date: Mon, 14 Jul 2014 10:16:05 -0700 Subject: [PATCH] Fix infinite loop when calling SetStatus after OOM. There was a problem where we would call SetStatus when we had an OOM error. This results in attempting to find the ExceptionInInitializer class which if not loaded does more allocations resulting in an infinite loop. Also some cleanup addressing other comments. Bug: 16082350 (cherry picked from commit fd22d5bada15d95b5ea8ab5a4dda39077e1a54ee) Change-Id: Ie291eb0f52ba9c63f24591fae691dd9f393e6ccb --- runtime/gc/accounting/card_table.cc | 2 -- runtime/gc/heap-inl.h | 10 ++++++---- runtime/mirror/class.cc | 28 ++++++++++++++++------------ 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/runtime/gc/accounting/card_table.cc b/runtime/gc/accounting/card_table.cc index a95c0038a..ceb42e593 100644 --- a/runtime/gc/accounting/card_table.cc +++ b/runtime/gc/accounting/card_table.cc @@ -83,8 +83,6 @@ CardTable* CardTable::Create(const byte* heap_begin, size_t heap_capacity) { CardTable::CardTable(MemMap* mem_map, byte* biased_begin, size_t offset) : mem_map_(mem_map), biased_begin_(biased_begin), offset_(offset) { - byte* __attribute__((unused)) begin = mem_map_->Begin() + offset_; - byte* __attribute__((unused)) end = mem_map_->End(); } void CardTable::ClearSpaceCards(space::ContinuousSpace* space) { diff --git a/runtime/gc/heap-inl.h b/runtime/gc/heap-inl.h index 419af30e6..7d3fd2d23 100644 --- a/runtime/gc/heap-inl.h +++ b/runtime/gc/heap-inl.h @@ -63,6 +63,7 @@ inline mirror::Object* Heap::AllocObjectWithAllocator(Thread* self, mirror::Clas // If we have a thread local allocation we don't need to update bytes allocated. if (allocator == kAllocatorTypeTLAB && byte_count <= self->TlabSize()) { obj = self->AllocTlab(byte_count); + DCHECK(obj != nullptr) << "AllocTlab can't fail"; obj->SetClass(klass); if (kUseBakerOrBrooksReadBarrier) { if (kUseBrooksReadBarrier) { @@ -71,7 +72,8 @@ inline mirror::Object* Heap::AllocObjectWithAllocator(Thread* self, mirror::Clas obj->AssertReadBarrierPointer(); } bytes_allocated = byte_count; - pre_fence_visitor(obj, bytes_allocated); + usable_size = bytes_allocated; + pre_fence_visitor(obj, usable_size); QuasiAtomic::ThreadFenceForConstructor(); } else { obj = TryToAllocate(self, allocator, byte_count, &bytes_allocated, @@ -111,13 +113,13 @@ inline mirror::Object* Heap::AllocObjectWithAllocator(Thread* self, mirror::Clas WriteBarrierField(obj, mirror::Object::ClassOffset(), klass); } pre_fence_visitor(obj, usable_size); - if (kIsDebugBuild && Runtime::Current()->IsStarted()) { - CHECK_LE(obj->SizeOf(), usable_size); - } new_num_bytes_allocated = static_cast(num_bytes_allocated_.FetchAndAddSequentiallyConsistent(bytes_allocated)) + bytes_allocated; } + if (kIsDebugBuild && Runtime::Current()->IsStarted()) { + CHECK_LE(obj->SizeOf(), usable_size); + } // TODO: Deprecate. if (kInstrumented) { if (Runtime::Current()->HasStatsEnabled()) { diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc index 371e984b0..be05fb8a9 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -88,18 +88,22 @@ void Class::SetStatus(Status new_status, Thread* self) { Handle old_throw_method(hs.NewHandle(old_throw_location.GetMethod())); uint32_t old_throw_dex_pc = old_throw_location.GetDexPc(); bool is_exception_reported = self->IsExceptionReportedToInstrumentation(); - // clear exception to call FindSystemClass - self->ClearException(); - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - Class* eiie_class = class_linker->FindSystemClass(self, - "Ljava/lang/ExceptionInInitializerError;"); - CHECK(!self->IsExceptionPending()); - - // Only verification errors, not initialization problems, should set a verify error. - // This is to ensure that ThrowEarlierClassFailure will throw NoClassDefFoundError in that case. - Class* exception_class = old_exception->GetClass(); - if (!eiie_class->IsAssignableFrom(exception_class)) { - SetVerifyErrorClass(exception_class); + Class* eiie_class; + // Do't attempt to use FindClass if we have an OOM error since this can try to do more + // allocations and may cause infinite loops. + if (old_exception.Get() == nullptr || + old_exception->GetClass()->GetDescriptor() != "Ljava/lang/OutOfMemoryError;") { + // Clear exception to call FindSystemClass. + self->ClearException(); + eiie_class = Runtime::Current()->GetClassLinker()->FindSystemClass( + self, "Ljava/lang/ExceptionInInitializerError;"); + CHECK(!self->IsExceptionPending()); + // Only verification errors, not initialization problems, should set a verify error. + // This is to ensure that ThrowEarlierClassFailure will throw NoClassDefFoundError in that case. + Class* exception_class = old_exception->GetClass(); + if (!eiie_class->IsAssignableFrom(exception_class)) { + SetVerifyErrorClass(exception_class); + } } // Restore exception. -- 2.11.0