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 | |
Andreas Gampe | 5e36c2f | 2017-04-21 19:11:15 -0700 | [diff] [blame] | 22 | #include "art_field-inl.h" |
David Sehr | 891a50e | 2017-10-27 17:01:07 -0700 | [diff] [blame] | 23 | #include "base/file_utils.h" |
Andreas Gampe | 85f1c57 | 2018-11-21 13:52:48 -0800 | [diff] [blame] | 24 | #include "base/logging.h" |
Mathieu Chartier | 1ca6890 | 2017-04-18 11:26:22 -0700 | [diff] [blame] | 25 | #include "mirror/class-inl.h" |
Mathieu Chartier | 4f5e3cb | 2017-06-12 13:10:01 -0700 | [diff] [blame] | 26 | #include "mirror/object-refvisitor-inl.h" |
Mathieu Chartier | 1ca6890 | 2017-04-18 11:26:22 -0700 | [diff] [blame] | 27 | |
| 28 | namespace art { |
| 29 | namespace gc { |
| 30 | |
Mathieu Chartier | b814ef5 | 2017-06-27 12:56:00 -0700 | [diff] [blame] | 31 | std::string Verification::DumpRAMAroundAddress(uintptr_t addr, uintptr_t bytes) const { |
| 32 | const uintptr_t dump_start = addr - bytes; |
| 33 | const uintptr_t dump_end = addr + bytes; |
| 34 | std::ostringstream oss; |
| 35 | if (dump_start < dump_end && |
| 36 | IsAddressInHeapSpace(reinterpret_cast<const void*>(dump_start)) && |
| 37 | IsAddressInHeapSpace(reinterpret_cast<const void*>(dump_end - 1))) { |
| 38 | oss << " adjacent_ram="; |
| 39 | for (uintptr_t p = dump_start; p < dump_end; ++p) { |
| 40 | if (p == addr) { |
| 41 | // Marker of where the address is. |
| 42 | oss << "|"; |
| 43 | } |
| 44 | uint8_t* ptr = reinterpret_cast<uint8_t*>(p); |
| 45 | oss << std::hex << std::setfill('0') << std::setw(2) << static_cast<uintptr_t>(*ptr); |
| 46 | } |
| 47 | } else { |
| 48 | oss << " <invalid address>"; |
| 49 | } |
| 50 | return oss.str(); |
| 51 | } |
| 52 | |
Mathieu Chartier | 1ca6890 | 2017-04-18 11:26:22 -0700 | [diff] [blame] | 53 | std::string Verification::DumpObjectInfo(const void* addr, const char* tag) const { |
| 54 | std::ostringstream oss; |
| 55 | oss << tag << "=" << addr; |
| 56 | if (IsValidHeapObjectAddress(addr)) { |
| 57 | mirror::Object* obj = reinterpret_cast<mirror::Object*>(const_cast<void*>(addr)); |
| 58 | mirror::Class* klass = obj->GetClass<kVerifyNone, kWithoutReadBarrier>(); |
| 59 | oss << " klass=" << klass; |
| 60 | if (IsValidClass(klass)) { |
| 61 | oss << "(" << klass->PrettyClass() << ")"; |
Vladimir Marko | 98db89c | 2018-09-07 11:45:46 +0100 | [diff] [blame] | 62 | if (klass->IsArrayClass<kVerifyNone>()) { |
| 63 | oss << " length=" << obj->AsArray<kVerifyNone>()->GetLength(); |
Mathieu Chartier | 1ca6890 | 2017-04-18 11:26:22 -0700 | [diff] [blame] | 64 | } |
| 65 | } else { |
| 66 | oss << " <invalid address>"; |
| 67 | } |
| 68 | space::Space* const space = heap_->FindSpaceFromAddress(addr); |
| 69 | if (space != nullptr) { |
| 70 | oss << " space=" << *space; |
| 71 | } |
| 72 | accounting::CardTable* card_table = heap_->GetCardTable(); |
| 73 | if (card_table->AddrIsInCardTable(addr)) { |
| 74 | oss << " card=" << static_cast<size_t>( |
| 75 | card_table->GetCard(reinterpret_cast<const mirror::Object*>(addr))); |
| 76 | } |
| 77 | // Dump adjacent RAM. |
Mathieu Chartier | b814ef5 | 2017-06-27 12:56:00 -0700 | [diff] [blame] | 78 | oss << DumpRAMAroundAddress(reinterpret_cast<uintptr_t>(addr), 4 * kObjectAlignment); |
Mathieu Chartier | 1ca6890 | 2017-04-18 11:26:22 -0700 | [diff] [blame] | 79 | } else { |
| 80 | oss << " <invalid address>"; |
| 81 | } |
| 82 | return oss.str(); |
| 83 | } |
| 84 | |
| 85 | void Verification::LogHeapCorruption(ObjPtr<mirror::Object> holder, |
| 86 | MemberOffset offset, |
| 87 | mirror::Object* ref, |
| 88 | bool fatal) const { |
Mathieu Chartier | 30ac398 | 2020-04-21 12:48:53 -0700 | [diff] [blame] | 89 | // Highest priority logging first. |
Mathieu Chartier | 1ca6890 | 2017-04-18 11:26:22 -0700 | [diff] [blame] | 90 | // Buffer the output in the string stream since it is more important than the stack traces |
| 91 | // and we want it to have log priority. The stack traces are printed from Runtime::Abort |
| 92 | // which is called from LOG(FATAL) but before the abort message. |
| 93 | std::ostringstream oss; |
| 94 | oss << "GC tried to mark invalid reference " << ref << std::endl; |
| 95 | oss << DumpObjectInfo(ref, "ref") << "\n"; |
Mathieu Chartier | 4ce0c76 | 2017-05-18 10:01:07 -0700 | [diff] [blame] | 96 | oss << DumpObjectInfo(holder.Ptr(), "holder"); |
Mathieu Chartier | 1ca6890 | 2017-04-18 11:26:22 -0700 | [diff] [blame] | 97 | if (holder != nullptr) { |
Mathieu Chartier | 1ca6890 | 2017-04-18 11:26:22 -0700 | [diff] [blame] | 98 | mirror::Class* holder_klass = holder->GetClass<kVerifyNone, kWithoutReadBarrier>(); |
| 99 | if (IsValidClass(holder_klass)) { |
Mathieu Chartier | b814ef5 | 2017-06-27 12:56:00 -0700 | [diff] [blame] | 100 | oss << " field_offset=" << offset.Uint32Value(); |
Mathieu Chartier | 1ca6890 | 2017-04-18 11:26:22 -0700 | [diff] [blame] | 101 | ArtField* field = holder->FindFieldByOffset(offset); |
| 102 | if (field != nullptr) { |
| 103 | oss << " name=" << field->GetName(); |
| 104 | } |
| 105 | } |
Mathieu Chartier | b814ef5 | 2017-06-27 12:56:00 -0700 | [diff] [blame] | 106 | mirror::HeapReference<mirror::Object>* addr = holder->GetFieldObjectReferenceAddr(offset); |
| 107 | oss << " reference addr" |
| 108 | << DumpRAMAroundAddress(reinterpret_cast<uintptr_t>(addr), 4 * kObjectAlignment); |
Mathieu Chartier | 1ca6890 | 2017-04-18 11:26:22 -0700 | [diff] [blame] | 109 | } |
Mathieu Chartier | 30ac398 | 2020-04-21 12:48:53 -0700 | [diff] [blame] | 110 | Runtime::Current()->GetHeap()->DumpSpaces(oss); |
| 111 | MemMap::DumpMaps(oss, /* terse= */ true); |
Mathieu Chartier | 1ca6890 | 2017-04-18 11:26:22 -0700 | [diff] [blame] | 112 | |
| 113 | if (fatal) { |
| 114 | LOG(FATAL) << oss.str(); |
| 115 | } else { |
| 116 | LOG(FATAL_WITHOUT_ABORT) << oss.str(); |
| 117 | } |
| 118 | } |
| 119 | |
Mathieu Chartier | b814ef5 | 2017-06-27 12:56:00 -0700 | [diff] [blame] | 120 | bool Verification::IsAddressInHeapSpace(const void* addr, space::Space** out_space) const { |
Mathieu Chartier | 1ca6890 | 2017-04-18 11:26:22 -0700 | [diff] [blame] | 121 | space::Space* const space = heap_->FindSpaceFromAddress(addr); |
| 122 | if (space != nullptr) { |
| 123 | if (out_space != nullptr) { |
| 124 | *out_space = space; |
| 125 | } |
| 126 | return true; |
| 127 | } |
| 128 | return false; |
| 129 | } |
| 130 | |
Mathieu Chartier | b814ef5 | 2017-06-27 12:56:00 -0700 | [diff] [blame] | 131 | bool Verification::IsValidHeapObjectAddress(const void* addr, space::Space** out_space) const { |
| 132 | return IsAligned<kObjectAlignment>(addr) && IsAddressInHeapSpace(addr, out_space); |
| 133 | } |
| 134 | |
Mathieu Chartier | 1ca6890 | 2017-04-18 11:26:22 -0700 | [diff] [blame] | 135 | bool Verification::IsValidClass(const void* addr) const { |
| 136 | if (!IsValidHeapObjectAddress(addr)) { |
| 137 | return false; |
| 138 | } |
| 139 | mirror::Class* klass = reinterpret_cast<mirror::Class*>(const_cast<void*>(addr)); |
| 140 | mirror::Class* k1 = klass->GetClass<kVerifyNone, kWithoutReadBarrier>(); |
| 141 | if (!IsValidHeapObjectAddress(k1)) { |
| 142 | return false; |
| 143 | } |
Roland Levillain | 001eff9 | 2018-01-24 14:24:33 +0000 | [diff] [blame] | 144 | // `k1` should be class class, take the class again to verify. |
Mathieu Chartier | 1ca6890 | 2017-04-18 11:26:22 -0700 | [diff] [blame] | 145 | // Note that this check may not be valid for the no image space since the class class might move |
| 146 | // around from moving GC. |
| 147 | mirror::Class* k2 = k1->GetClass<kVerifyNone, kWithoutReadBarrier>(); |
| 148 | if (!IsValidHeapObjectAddress(k2)) { |
| 149 | return false; |
| 150 | } |
| 151 | return k1 == k2; |
| 152 | } |
| 153 | |
Mathieu Chartier | 4f5e3cb | 2017-06-12 13:10:01 -0700 | [diff] [blame] | 154 | using ObjectSet = std::set<mirror::Object*>; |
| 155 | using WorkQueue = std::deque<std::pair<mirror::Object*, std::string>>; |
| 156 | |
| 157 | // Use for visiting the GcRoots held live by ArtFields, ArtMethods, and ClassLoaders. |
| 158 | class Verification::BFSFindReachable { |
| 159 | public: |
| 160 | explicit BFSFindReachable(ObjectSet* visited) : visited_(visited) {} |
| 161 | |
| 162 | void operator()(mirror::Object* obj, MemberOffset offset, bool is_static ATTRIBUTE_UNUSED) const |
| 163 | REQUIRES_SHARED(Locks::mutator_lock_) { |
| 164 | ArtField* field = obj->FindFieldByOffset(offset); |
| 165 | Visit(obj->GetFieldObject<mirror::Object>(offset), |
| 166 | field != nullptr ? field->GetName() : ""); |
| 167 | } |
| 168 | |
| 169 | void VisitRootIfNonNull(mirror::CompressedReference<mirror::Object>* root) const |
| 170 | REQUIRES_SHARED(Locks::mutator_lock_) { |
| 171 | if (!root->IsNull()) { |
| 172 | VisitRoot(root); |
| 173 | } |
| 174 | } |
| 175 | |
| 176 | void VisitRoot(mirror::CompressedReference<mirror::Object>* root) const |
| 177 | REQUIRES_SHARED(Locks::mutator_lock_) { |
| 178 | Visit(root->AsMirrorPtr(), "!nativeRoot"); |
| 179 | } |
| 180 | |
| 181 | void Visit(mirror::Object* ref, const std::string& field_name) const |
| 182 | REQUIRES_SHARED(Locks::mutator_lock_) { |
| 183 | if (ref != nullptr && visited_->insert(ref).second) { |
| 184 | new_visited_.emplace_back(ref, field_name); |
| 185 | } |
| 186 | } |
| 187 | |
| 188 | const WorkQueue& NewlyVisited() const { |
| 189 | return new_visited_; |
| 190 | } |
| 191 | |
| 192 | private: |
| 193 | ObjectSet* visited_; |
| 194 | mutable WorkQueue new_visited_; |
| 195 | }; |
| 196 | |
| 197 | class Verification::CollectRootVisitor : public SingleRootVisitor { |
| 198 | public: |
| 199 | CollectRootVisitor(ObjectSet* visited, WorkQueue* work) : visited_(visited), work_(work) {} |
| 200 | |
| 201 | void VisitRoot(mirror::Object* obj, const RootInfo& info) |
Roland Levillain | bbc6e7e | 2018-08-24 16:58:47 +0100 | [diff] [blame] | 202 | override REQUIRES_SHARED(Locks::mutator_lock_) { |
Mathieu Chartier | 4f5e3cb | 2017-06-12 13:10:01 -0700 | [diff] [blame] | 203 | if (obj != nullptr && visited_->insert(obj).second) { |
| 204 | std::ostringstream oss; |
| 205 | oss << info.ToString() << " = " << obj << "(" << obj->PrettyTypeOf() << ")"; |
| 206 | work_->emplace_back(obj, oss.str()); |
| 207 | } |
| 208 | } |
| 209 | |
| 210 | private: |
| 211 | ObjectSet* const visited_; |
| 212 | WorkQueue* const work_; |
| 213 | }; |
| 214 | |
| 215 | std::string Verification::FirstPathFromRootSet(ObjPtr<mirror::Object> target) const { |
| 216 | Runtime* const runtime = Runtime::Current(); |
| 217 | std::set<mirror::Object*> visited; |
| 218 | std::deque<std::pair<mirror::Object*, std::string>> work; |
| 219 | { |
| 220 | CollectRootVisitor root_visitor(&visited, &work); |
| 221 | runtime->VisitRoots(&root_visitor, kVisitRootFlagAllRoots); |
| 222 | } |
| 223 | while (!work.empty()) { |
| 224 | auto pair = work.front(); |
| 225 | work.pop_front(); |
| 226 | if (pair.first == target) { |
| 227 | return pair.second; |
| 228 | } |
| 229 | BFSFindReachable visitor(&visited); |
| 230 | pair.first->VisitReferences(visitor, VoidFunctor()); |
| 231 | for (auto&& pair2 : visitor.NewlyVisited()) { |
| 232 | std::ostringstream oss; |
| 233 | mirror::Object* obj = pair2.first; |
| 234 | oss << pair.second << " -> " << obj << "(" << obj->PrettyTypeOf() << ")." << pair2.second; |
| 235 | work.emplace_back(obj, oss.str()); |
| 236 | } |
| 237 | } |
| 238 | return "<no path found>"; |
| 239 | } |
| 240 | |
Mathieu Chartier | 1ca6890 | 2017-04-18 11:26:22 -0700 | [diff] [blame] | 241 | } // namespace gc |
| 242 | } // namespace art |