diff options
Diffstat (limited to 'runtime/gc/heap_verification_test.cc')
-rw-r--r-- | runtime/gc/heap_verification_test.cc | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/runtime/gc/heap_verification_test.cc b/runtime/gc/heap_verification_test.cc new file mode 100644 index 0000000000..480ba2abb1 --- /dev/null +++ b/runtime/gc/heap_verification_test.cc @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "common_runtime_test.h" +#include "verification.h" +#include "mirror/string.h" +#include "scoped_thread_state_change-inl.h" + +namespace art { +namespace gc { + +class VerificationTest : public CommonRuntimeTest { + protected: + VerificationTest() {} + + template <class T> + mirror::ObjectArray<T>* AllocObjectArray(Thread* self, size_t length) + REQUIRES_SHARED(Locks::mutator_lock_) { + ClassLinker* const class_linker = Runtime::Current()->GetClassLinker(); + return mirror::ObjectArray<T>::Alloc( + self, + class_linker->GetClassRoot(ClassLinker::ClassRoot::kObjectArrayClass), + length); + } +}; + +TEST_F(VerificationTest, IsValidHeapObjectAddress) { + ScopedObjectAccess soa(Thread::Current()); + const Verification* const v = Runtime::Current()->GetHeap()->GetVerification(); + EXPECT_FALSE(v->IsValidHeapObjectAddress(reinterpret_cast<const void*>(1))); + EXPECT_FALSE(v->IsValidHeapObjectAddress(reinterpret_cast<const void*>(4))); + EXPECT_FALSE(v->IsValidHeapObjectAddress(nullptr)); + VariableSizedHandleScope hs(soa.Self()); + Handle<mirror::String> string( + hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "test"))); + EXPECT_TRUE(v->IsValidHeapObjectAddress(string.Get())); + EXPECT_TRUE(v->IsValidHeapObjectAddress(string->GetClass())); + const uintptr_t uint_klass = reinterpret_cast<uintptr_t>(string->GetClass()); + // Not actually a valid object but the verification can't know that. Guaranteed to be inside a + // heap space. + EXPECT_TRUE(v->IsValidHeapObjectAddress( + reinterpret_cast<const void*>(uint_klass + kObjectAlignment))); + EXPECT_FALSE(v->IsValidHeapObjectAddress( + reinterpret_cast<const void*>(&uint_klass))); +} + +TEST_F(VerificationTest, IsValidClass) { + ScopedObjectAccess soa(Thread::Current()); + VariableSizedHandleScope hs(soa.Self()); + Handle<mirror::String> string( + hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "test"))); + const Verification* const v = Runtime::Current()->GetHeap()->GetVerification(); + EXPECT_FALSE(v->IsValidClass(reinterpret_cast<const void*>(1))); + EXPECT_FALSE(v->IsValidClass(reinterpret_cast<const void*>(4))); + EXPECT_FALSE(v->IsValidClass(nullptr)); + EXPECT_FALSE(v->IsValidClass(string.Get())); + EXPECT_TRUE(v->IsValidClass(string->GetClass())); + const uintptr_t uint_klass = reinterpret_cast<uintptr_t>(string->GetClass()); + EXPECT_FALSE(v->IsValidClass(reinterpret_cast<const void*>(uint_klass - kObjectAlignment))); + EXPECT_FALSE(v->IsValidClass(reinterpret_cast<const void*>(&uint_klass))); +} + +TEST_F(VerificationTest, DumpObjectInfo) { + ScopedLogSeverity sls(LogSeverity::INFO); + ScopedObjectAccess soa(Thread::Current()); + Runtime* const runtime = Runtime::Current(); + VariableSizedHandleScope hs(soa.Self()); + Handle<mirror::String> string( + hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "obj"))); + Handle<mirror::ObjectArray<mirror::Object>> arr( + hs.NewHandle(AllocObjectArray<mirror::Object>(soa.Self(), 256))); + const Verification* const v = runtime->GetHeap()->GetVerification(); + LOG(INFO) << v->DumpObjectInfo(reinterpret_cast<const void*>(1), "obj"); + LOG(INFO) << v->DumpObjectInfo(reinterpret_cast<const void*>(4), "obj"); + LOG(INFO) << v->DumpObjectInfo(nullptr, "obj"); + LOG(INFO) << v->DumpObjectInfo(string.Get(), "test"); + LOG(INFO) << v->DumpObjectInfo(string->GetClass(), "obj"); + const uintptr_t uint_klass = reinterpret_cast<uintptr_t>(string->GetClass()); + LOG(INFO) << v->DumpObjectInfo(reinterpret_cast<const void*>(uint_klass - kObjectAlignment), + "obj"); + LOG(INFO) << v->DumpObjectInfo(reinterpret_cast<const void*>(&uint_klass), "obj"); + LOG(INFO) << v->DumpObjectInfo(arr.Get(), "arr"); +} + +TEST_F(VerificationTest, LogHeapCorruption) { + ScopedLogSeverity sls(LogSeverity::INFO); + ScopedObjectAccess soa(Thread::Current()); + Runtime* const runtime = Runtime::Current(); + VariableSizedHandleScope hs(soa.Self()); + Handle<mirror::String> string( + hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "obj"))); + using ObjArray = mirror::ObjectArray<mirror::Object>; + Handle<ObjArray> arr( + hs.NewHandle(AllocObjectArray<mirror::Object>(soa.Self(), 256))); + const Verification* const v = runtime->GetHeap()->GetVerification(); + arr->Set(0, string.Get()); + // Test normal cases. + v->LogHeapCorruption(arr.Get(), ObjArray::DataOffset(kHeapReferenceSize), string.Get(), false); + v->LogHeapCorruption(string.Get(), mirror::Object::ClassOffset(), string->GetClass(), false); + // Test null holder cases. + v->LogHeapCorruption(nullptr, MemberOffset(0), string.Get(), false); + v->LogHeapCorruption(nullptr, MemberOffset(0), arr.Get(), false); +} + +} // namespace gc +} // namespace art |