/* * 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 mirror::ObjectArray* AllocObjectArray(Thread* self, size_t length) REQUIRES_SHARED(Locks::mutator_lock_) { ClassLinker* const class_linker = Runtime::Current()->GetClassLinker(); return mirror::ObjectArray::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(1))); EXPECT_FALSE(v->IsValidHeapObjectAddress(reinterpret_cast(4))); EXPECT_FALSE(v->IsValidHeapObjectAddress(nullptr)); VariableSizedHandleScope hs(soa.Self()); Handle 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(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(uint_klass + kObjectAlignment))); EXPECT_FALSE(v->IsValidHeapObjectAddress( reinterpret_cast(&uint_klass))); } TEST_F(VerificationTest, IsValidClass) { ScopedObjectAccess soa(Thread::Current()); VariableSizedHandleScope hs(soa.Self()); Handle string( hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "test"))); const Verification* const v = Runtime::Current()->GetHeap()->GetVerification(); EXPECT_FALSE(v->IsValidClass(reinterpret_cast(1))); EXPECT_FALSE(v->IsValidClass(reinterpret_cast(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(string->GetClass()); EXPECT_FALSE(v->IsValidClass(reinterpret_cast(uint_klass - kObjectAlignment))); EXPECT_FALSE(v->IsValidClass(reinterpret_cast(&uint_klass))); } TEST_F(VerificationTest, DumpObjectInfo) { ScopedLogSeverity sls(LogSeverity::INFO); ScopedObjectAccess soa(Thread::Current()); Runtime* const runtime = Runtime::Current(); VariableSizedHandleScope hs(soa.Self()); Handle string( hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "obj"))); Handle> arr( hs.NewHandle(AllocObjectArray(soa.Self(), 256))); const Verification* const v = runtime->GetHeap()->GetVerification(); LOG(INFO) << v->DumpObjectInfo(reinterpret_cast(1), "obj"); LOG(INFO) << v->DumpObjectInfo(reinterpret_cast(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(string->GetClass()); LOG(INFO) << v->DumpObjectInfo(reinterpret_cast(uint_klass - kObjectAlignment), "obj"); LOG(INFO) << v->DumpObjectInfo(reinterpret_cast(&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 string( hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "obj"))); using ObjArray = mirror::ObjectArray; Handle arr( hs.NewHandle(AllocObjectArray(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