Mathieu Chartier | 1ca6890 | 2017-04-18 11:26:22 -0700 | [diff] [blame^] | 1 | /* |
| 2 | * Copyright (C) 2017 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #include "verification.h" |
| 18 | |
| 19 | #include <iomanip> |
| 20 | #include <sstream> |
| 21 | |
| 22 | #include "mirror/class-inl.h" |
| 23 | |
| 24 | namespace art { |
| 25 | namespace gc { |
| 26 | |
| 27 | std::string Verification::DumpObjectInfo(const void* addr, const char* tag) const { |
| 28 | std::ostringstream oss; |
| 29 | oss << tag << "=" << addr; |
| 30 | if (IsValidHeapObjectAddress(addr)) { |
| 31 | mirror::Object* obj = reinterpret_cast<mirror::Object*>(const_cast<void*>(addr)); |
| 32 | mirror::Class* klass = obj->GetClass<kVerifyNone, kWithoutReadBarrier>(); |
| 33 | oss << " klass=" << klass; |
| 34 | if (IsValidClass(klass)) { |
| 35 | oss << "(" << klass->PrettyClass() << ")"; |
| 36 | if (klass->IsArrayClass<kVerifyNone, kWithoutReadBarrier>()) { |
| 37 | oss << " length=" << obj->AsArray<kVerifyNone, kWithoutReadBarrier>()->GetLength(); |
| 38 | } |
| 39 | } else { |
| 40 | oss << " <invalid address>"; |
| 41 | } |
| 42 | space::Space* const space = heap_->FindSpaceFromAddress(addr); |
| 43 | if (space != nullptr) { |
| 44 | oss << " space=" << *space; |
| 45 | } |
| 46 | accounting::CardTable* card_table = heap_->GetCardTable(); |
| 47 | if (card_table->AddrIsInCardTable(addr)) { |
| 48 | oss << " card=" << static_cast<size_t>( |
| 49 | card_table->GetCard(reinterpret_cast<const mirror::Object*>(addr))); |
| 50 | } |
| 51 | // Dump adjacent RAM. |
| 52 | const uintptr_t uint_addr = reinterpret_cast<uintptr_t>(addr); |
| 53 | static constexpr size_t kBytesBeforeAfter = 2 * kObjectAlignment; |
| 54 | const uintptr_t dump_start = uint_addr - kBytesBeforeAfter; |
| 55 | const uintptr_t dump_end = uint_addr + kBytesBeforeAfter; |
| 56 | if (dump_start < dump_end && |
| 57 | IsValidHeapObjectAddress(reinterpret_cast<const void*>(dump_start)) && |
| 58 | IsValidHeapObjectAddress(reinterpret_cast<const void*>(dump_end - kObjectAlignment))) { |
| 59 | oss << " adjacent_ram="; |
| 60 | for (uintptr_t p = dump_start; p < dump_end; ++p) { |
| 61 | if (p == uint_addr) { |
| 62 | // Marker of where the object is. |
| 63 | oss << "|"; |
| 64 | } |
| 65 | uint8_t* ptr = reinterpret_cast<uint8_t*>(p); |
| 66 | oss << std::hex << std::setfill('0') << std::setw(2) << static_cast<uintptr_t>(*ptr); |
| 67 | } |
| 68 | } |
| 69 | } else { |
| 70 | oss << " <invalid address>"; |
| 71 | } |
| 72 | return oss.str(); |
| 73 | } |
| 74 | |
| 75 | void Verification::LogHeapCorruption(ObjPtr<mirror::Object> holder, |
| 76 | MemberOffset offset, |
| 77 | mirror::Object* ref, |
| 78 | bool fatal) const { |
| 79 | // Lowest priority logging first: |
| 80 | PrintFileToLog("/proc/self/maps", LogSeverity::FATAL_WITHOUT_ABORT); |
| 81 | MemMap::DumpMaps(LOG_STREAM(FATAL_WITHOUT_ABORT), true); |
| 82 | // Buffer the output in the string stream since it is more important than the stack traces |
| 83 | // and we want it to have log priority. The stack traces are printed from Runtime::Abort |
| 84 | // which is called from LOG(FATAL) but before the abort message. |
| 85 | std::ostringstream oss; |
| 86 | oss << "GC tried to mark invalid reference " << ref << std::endl; |
| 87 | oss << DumpObjectInfo(ref, "ref") << "\n"; |
| 88 | if (holder != nullptr) { |
| 89 | oss << DumpObjectInfo(holder.Ptr(), "holder"); |
| 90 | mirror::Class* holder_klass = holder->GetClass<kVerifyNone, kWithoutReadBarrier>(); |
| 91 | if (IsValidClass(holder_klass)) { |
| 92 | oss << "field_offset=" << offset.Uint32Value(); |
| 93 | ArtField* field = holder->FindFieldByOffset(offset); |
| 94 | if (field != nullptr) { |
| 95 | oss << " name=" << field->GetName(); |
| 96 | } |
| 97 | } |
| 98 | } |
| 99 | |
| 100 | if (fatal) { |
| 101 | LOG(FATAL) << oss.str(); |
| 102 | } else { |
| 103 | LOG(FATAL_WITHOUT_ABORT) << oss.str(); |
| 104 | } |
| 105 | } |
| 106 | |
| 107 | bool Verification::IsValidHeapObjectAddress(const void* addr, space::Space** out_space) const { |
| 108 | if (!IsAligned<kObjectAlignment>(addr)) { |
| 109 | return false; |
| 110 | } |
| 111 | space::Space* const space = heap_->FindSpaceFromAddress(addr); |
| 112 | if (space != nullptr) { |
| 113 | if (out_space != nullptr) { |
| 114 | *out_space = space; |
| 115 | } |
| 116 | return true; |
| 117 | } |
| 118 | return false; |
| 119 | } |
| 120 | |
| 121 | bool Verification::IsValidClass(const void* addr) const { |
| 122 | if (!IsValidHeapObjectAddress(addr)) { |
| 123 | return false; |
| 124 | } |
| 125 | mirror::Class* klass = reinterpret_cast<mirror::Class*>(const_cast<void*>(addr)); |
| 126 | mirror::Class* k1 = klass->GetClass<kVerifyNone, kWithoutReadBarrier>(); |
| 127 | if (!IsValidHeapObjectAddress(k1)) { |
| 128 | return false; |
| 129 | } |
| 130 | // k should be class class, take the class again to verify. |
| 131 | // Note that this check may not be valid for the no image space since the class class might move |
| 132 | // around from moving GC. |
| 133 | mirror::Class* k2 = k1->GetClass<kVerifyNone, kWithoutReadBarrier>(); |
| 134 | if (!IsValidHeapObjectAddress(k2)) { |
| 135 | return false; |
| 136 | } |
| 137 | return k1 == k2; |
| 138 | } |
| 139 | |
| 140 | } // namespace gc |
| 141 | } // namespace art |