diff options
author | Andreas Gampe <agampe@google.com> | 2016-09-27 18:45:02 -0700 |
---|---|---|
committer | Andreas Gampe <agampe@google.com> | 2016-09-28 09:56:41 -0700 |
commit | a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08b (patch) | |
tree | e01c088615fe1b8354099033e25cf68e5801234d | |
parent | 1b6cf7fbca0fd90ae58938e4a16a77b79a83408e (diff) | |
download | android_art-a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08b.tar.gz android_art-a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08b.tar.bz2 android_art-a3bbf8bf436fd7567097b8ca0d7bd24fdf5ae08b.zip |
ART: Dump referenced type in IRT overflows
When the runtime dumps a reference table, e.g., when aborting for
an overflow, dump the type of stored referents for reference types
to aid in debugging leaks.
Bug: 31600693
Test: m test-art-host-gtest-reference_table_test
Change-Id: Ia892dc84ca8827dd93a8b75d6f571c392f94859c
(cherry picked from commit 280f32b095f55f24dc557f9a9067d223901214ce)
-rw-r--r-- | runtime/reference_table.cc | 7 | ||||
-rw-r--r-- | runtime/reference_table_test.cc | 60 |
2 files changed, 67 insertions, 0 deletions
diff --git a/runtime/reference_table.cc b/runtime/reference_table.cc index f04d41dc80..0be79efb76 100644 --- a/runtime/reference_table.cc +++ b/runtime/reference_table.cc @@ -192,6 +192,13 @@ void ReferenceTable::Dump(std::ostream& os, Table& entries) { } else { StringAppendF(&extras, " \"%.16s... (%d chars)", utf8.c_str(), s->GetLength()); } + } else if (ref->IsReferenceInstance()) { + mirror::Object* referent = ref->AsReference()->GetReferent(); + if (referent == nullptr) { + extras = " (referent is null)"; + } else { + extras = StringPrintf(" (referent is a %s)", PrettyTypeOf(referent).c_str()); + } } os << StringPrintf(" %5d: ", idx) << ref << " " << className << extras << "\n"; } diff --git a/runtime/reference_table_test.cc b/runtime/reference_table_test.cc index fae8e722c3..819e17a619 100644 --- a/runtime/reference_table_test.cc +++ b/runtime/reference_table_test.cc @@ -16,11 +16,15 @@ #include "reference_table.h" +#include "class_linker.h" #include "common_runtime_test.h" +#include "handle_scope-inl.h" #include "mirror/array-inl.h" #include "mirror/class-inl.h" +#include "mirror/class_loader.h" #include "mirror/string.h" #include "primitive.h" +#include "runtime.h" #include "scoped_thread_state_change.h" #include "thread-inl.h" @@ -28,6 +32,39 @@ namespace art { class ReferenceTableTest : public CommonRuntimeTest {}; +static mirror::Object* CreateWeakReference(mirror::Object* referent) + REQUIRES_SHARED(Locks::mutator_lock_) { + Thread* self = Thread::Current(); + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + + StackHandleScope<3> scope(self); + Handle<mirror::Object> h_referent(scope.NewHandle<mirror::Object>(referent)); + + Handle<mirror::Class> h_ref_class(scope.NewHandle<mirror::Class>( + class_linker->FindClass(self, + "Ljava/lang/ref/WeakReference;", + ScopedNullHandle<mirror::ClassLoader>()))); + CHECK(h_ref_class.Get() != nullptr); + CHECK(class_linker->EnsureInitialized(self, h_ref_class, true, true)); + + Handle<mirror::Object> h_ref_instance(scope.NewHandle<mirror::Object>( + h_ref_class->AllocObject(self))); + CHECK(h_ref_instance.Get() != nullptr); + + ArtMethod* constructor = h_ref_class->FindDeclaredDirectMethod( + "<init>", "(Ljava/lang/Object;)V", class_linker->GetImagePointerSize()); + CHECK(constructor != nullptr); + + uint32_t args[2]; + args[0] = PointerToLowMemUInt32(h_ref_instance.Get()); + args[1] = PointerToLowMemUInt32(h_referent.Get()); + JValue result; + constructor->Invoke(self, args, sizeof(uint32_t), &result, constructor->GetShorty()); + CHECK(!self->IsExceptionPending()); + + return h_ref_instance.Get(); +} + TEST_F(ReferenceTableTest, Basics) { ScopedObjectAccess soa(Thread::Current()); mirror::Object* o1 = mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello"); @@ -104,6 +141,29 @@ TEST_F(ReferenceTableTest, Basics) { std::string::npos) << oss.str(); } } + + // Add a reference and check that the type of the referent is dumped. + { + mirror::Object* empty_reference = CreateWeakReference(nullptr); + ASSERT_TRUE(empty_reference->IsReferenceInstance()); + rt.Add(empty_reference); + std::ostringstream oss; + rt.Dump(oss); + EXPECT_NE(oss.str().find("java.lang.ref.WeakReference (referent is null)"), std::string::npos) + << oss.str(); + } + + { + mirror::Object* string_referent = mirror::String::AllocFromModifiedUtf8(Thread::Current(), "A"); + mirror::Object* non_empty_reference = CreateWeakReference(string_referent); + ASSERT_TRUE(non_empty_reference->IsReferenceInstance()); + rt.Add(non_empty_reference); + std::ostringstream oss; + rt.Dump(oss); + EXPECT_NE(oss.str().find("java.lang.ref.WeakReference (referent is a java.lang.String)"), + std::string::npos) + << oss.str(); + } } } // namespace art |