1 /**
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "runtime/include/runtime.h"
17 #include "runtime/include/panda_vm.h"
18 #include "runtime/mem/gc/gc_root.h"
19 #include "runtime/mem/heap_verifier.h"
20
21 namespace panda::mem {
22
23 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
24 #define LOG_HEAP_VERIFIER LOG(ERROR, GC) << "HEAP_VERIFIER: "
25
26 // Should be called only with MutatorLock held
27 template <class LanguageConfig>
VerifyAllPaused() const28 size_t HeapVerifier<LanguageConfig>::VerifyAllPaused() const
29 {
30 Rendezvous *rendezvous = Thread::GetCurrent()->GetVM()->GetRendezvous();
31 rendezvous->SafepointBegin();
32 size_t fail_count = VerifyAll();
33 rendezvous->SafepointEnd();
34 return fail_count;
35 }
36
37 template <LangTypeT LangType>
operator ()(ObjectHeader * obj)38 void HeapObjectVerifier<LangType>::operator()(ObjectHeader *obj)
39 {
40 HeapReferenceVerifier<LangType> ref_verifier(HEAP, FAIL_COUNT);
41 ObjectHelpers<LangType>::TraverseAllObjects(obj, ref_verifier);
42 }
43
44 template <LangTypeT LangType>
operator ()(ObjectHeader * object_header,ObjectHeader * referent)45 void HeapReferenceVerifier<LangType>::operator()([[maybe_unused]] ObjectHeader *object_header, ObjectHeader *referent)
46 {
47 // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
48 if constexpr (LangType == LANG_TYPE_DYNAMIC) {
49 // Weak reference can be passed here, need to resolve the referent
50 coretypes::TaggedValue value(referent);
51 if (value.IsWeak()) {
52 referent = value.GetWeakReferent();
53 }
54 }
55 auto obj_allocator = HEAP->GetObjectAllocator().AsObjectAllocator();
56 if (!obj_allocator->IsLive(referent)) {
57 LOG_HEAP_VERIFIER << "Heap corruption found! Heap object " << std::hex << object_header
58 << " references a dead object at " << referent;
59 ++(*FAIL_COUNT);
60 } else if (referent->IsForwarded()) {
61 LOG_HEAP_VERIFIER << "Heap corruption found! Heap object " << std::hex << object_header
62 << " references a forwarded object at " << referent;
63 ++(*FAIL_COUNT);
64 }
65 }
66
67 template <LangTypeT LangType>
operator ()(const GCRoot & root)68 void HeapReferenceVerifier<LangType>::operator()(const GCRoot &root)
69 {
70 auto obj_allocator = HEAP->GetObjectAllocator().AsObjectAllocator();
71 auto referent = root.GetObjectHeader();
72 // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
73 if constexpr (LangType == LANG_TYPE_DYNAMIC) {
74 // Weak reference can be passed here, need to resolve the referent
75 coretypes::TaggedValue value(referent);
76 if (value.IsWeak()) {
77 referent = value.GetWeakReferent();
78 }
79 }
80 if (!obj_allocator->IsLive(referent)) {
81 LOG_HEAP_VERIFIER << "Heap corruption found! Root references a dead object at " << std::hex << referent;
82 ++(*FAIL_COUNT);
83 } else if (referent->IsForwarded()) {
84 LOG_HEAP_VERIFIER << "Heap corruption found! Root references a forwarded object at " << std::hex << referent;
85 ++(*FAIL_COUNT);
86 }
87 }
88
89 template <class LanguageConfig>
IsValidObjectAddress(void * addr) const90 bool HeapVerifier<LanguageConfig>::IsValidObjectAddress(void *addr) const
91 {
92 return IsAligned<DEFAULT_ALIGNMENT_IN_BYTES>(ToUintPtr(addr)) && IsHeapAddress(addr);
93 }
94
95 template <class LanguageConfig>
IsHeapAddress(void * addr) const96 bool HeapVerifier<LanguageConfig>::IsHeapAddress(void *addr) const
97 {
98 return heap_->GetObjectAllocator().AsObjectAllocator()->ContainObject(reinterpret_cast<ObjectHeader *>(addr));
99 }
100
101 template <class LanguageConfig>
VerifyHeap() const102 size_t HeapVerifier<LanguageConfig>::VerifyHeap() const
103 {
104 return heap_->VerifyHeapReferences();
105 }
106
107 template <class LanguageConfig>
VerifyRoot() const108 size_t HeapVerifier<LanguageConfig>::VerifyRoot() const
109 {
110 RootManager<LanguageConfig> root_manager;
111 size_t fail_count = 0;
112 root_manager.SetPandaVM(heap_->GetPandaVM());
113 root_manager.VisitNonHeapRoots([this, &fail_count](const GCRoot &root) {
114 if (root.GetType() == RootType::ROOT_FRAME || root.GetType() == RootType::ROOT_THREAD) {
115 auto *base_cls = root.GetObjectHeader()->ClassAddr<BaseClass>();
116 if (base_cls == nullptr) {
117 LOG_HEAP_VERIFIER << "Heap corruption found! Class address for root " << std::hex
118 << root.GetObjectHeader() << " is null";
119 ++fail_count;
120 } else if (!(!base_cls->IsDynamicClass() && static_cast<Class *>(base_cls)->IsClassClass())) {
121 HeapReferenceVerifier<LanguageConfig::LANG_TYPE>(heap_, &fail_count)(root);
122 }
123 }
124 });
125
126 return fail_count;
127 }
128
129 template <class LanguageConfig>
VerifyAll() const130 size_t FastHeapVerifier<LanguageConfig>::VerifyAll() const
131 {
132 PandaUnorderedSet<const ObjectHeader *> heap_objects;
133 PandaVector<ObjectCache> referent_objects;
134 size_t fails_count = 0;
135
136 auto lazy_verify = [&](const ObjectHeader *object_header, const ObjectHeader *referent) {
137 // Lazy verify during heap objects collection
138 if (heap_objects.find(referent) == heap_objects.end()) {
139 referent_objects.push_back(ObjectCache({object_header, referent}));
140 }
141 if (object_header->IsForwarded()) {
142 LOG_HEAP_VERIFIER << "Heap object " << std::hex << object_header << " is forwarded object";
143 ++fails_count;
144 }
145 auto *class_addr = object_header->ClassAddr<BaseClass>();
146 if (!IsInObjectsAddressSpace(class_addr)) {
147 LOG_HEAP_VERIFIER << "Heap object " << std::hex << object_header
148 << " has non-heap class address: " << class_addr;
149 ++fails_count;
150 }
151 };
152 const std::function<void(ObjectHeader *, ObjectHeader *)> lazy_verify_functor(lazy_verify);
153 auto collect_objects = [&](ObjectHeader *object) {
154 heap_objects.insert(object);
155 ObjectHelpers<LanguageConfig::LANG_TYPE>::TraverseAllObjects(object, lazy_verify_functor);
156 };
157
158 // Heap objects verifier
159
160 // Add strings from string table because these objects are like a phenix.
161 // A string object may exist but there are no live references to it (no bit set in the live bitmap).
162 // But later code may reuse it by calling StringTable::GetOrInternString so this string
163 // get alive. That is why we mark all strings as alive by visiting the string table.
164 Thread::GetCurrent()->GetVM()->GetStringTable()->VisitStrings(collect_objects);
165 heap_->GetObjectAllocator().AsObjectAllocator()->IterateOverObjects(collect_objects);
166 for (auto object_cache : referent_objects) {
167 if (heap_objects.find(object_cache.referent) == heap_objects.end()) {
168 LOG_HEAP_VERIFIER << "Heap object " << std::hex << object_cache.heap_object
169 << " references a dead object at " << object_cache.referent;
170 ++fails_count;
171 }
172 }
173 // Stack verifier
174 RootManager<LanguageConfig> root_manager;
175 root_manager.SetPandaVM(heap_->GetPandaVM());
176 auto root_verifier = [&](const GCRoot &root) {
177 const auto *root_obj_header = root.GetObjectHeader();
178 auto *base_cls = root_obj_header->ClassAddr<BaseClass>();
179 if (!IsAddressInObjectsHeap(ToUintPtr(base_cls))) {
180 LOG_HEAP_VERIFIER << "Class address for root " << std::hex << root_obj_header
181 << " is not in objects heap: " << base_cls;
182 ++fails_count;
183 } else if (base_cls->IsDynamicClass() || !static_cast<Class *>(base_cls)->IsClassClass()) {
184 if (heap_objects.find(root_obj_header) == heap_objects.end()) {
185 LOG_HEAP_VERIFIER << "Root references a dead object at " << std::hex << root_obj_header;
186 ++fails_count;
187 }
188 }
189 };
190 root_manager.VisitLocalRoots(root_verifier);
191
192 return fails_count;
193 }
194
ObjectVerificationInfo(ObjectHeader * referent)195 ObjectVerificationInfo::ObjectVerificationInfo(ObjectHeader *referent)
196 : class_address_(referent->ClassAddr<void *>()), old_address_(referent)
197 {
198 }
199
VerifyUpdatedRef(ObjectHeader * object_header,ObjectHeader * updated_ref,bool in_alive_space) const200 bool ObjectVerificationInfo::VerifyUpdatedRef(ObjectHeader *object_header, ObjectHeader *updated_ref,
201 bool in_alive_space) const
202 {
203 ObjectHeader *correct_address = old_address_;
204 if (!in_alive_space) {
205 if (!old_address_->IsForwarded()) {
206 LOG_HEAP_VERIFIER << "Object " << std::hex << object_header << " had reference " << old_address_
207 << ", which is not forwarded, new reference address: " << updated_ref;
208 return false;
209 }
210 correct_address = GetForwardAddress(old_address_);
211 }
212 if (correct_address != updated_ref) {
213 LOG_HEAP_VERIFIER << "Object " << std::hex << object_header << " has incorrect updated reference "
214 << updated_ref << ", correct address: " << correct_address;
215 return false;
216 }
217 void *new_class_addr = updated_ref->ClassAddr<void *>();
218 if (new_class_addr != class_address_) {
219 LOG_HEAP_VERIFIER << "Object " << std::hex << object_header << " has incorrect class address ("
220 << new_class_addr << ") in updated reference " << updated_ref
221 << ", class address before collection: " << class_address_;
222 return false;
223 }
224
225 return true;
226 }
227
228 template <class LanguageConfig>
InCollectableSpace(const ObjectHeader * object) const229 bool HeapVerifierIntoGC<LanguageConfig>::InCollectableSpace(const ObjectHeader *object) const
230 {
231 for (const auto &mem_range : this->collectable_mem_ranges_) {
232 if (mem_range.Contains(ToUintPtr(object))) {
233 return true;
234 }
235 }
236 return false;
237 }
238
239 template <class LanguageConfig>
InAliveSpace(const ObjectHeader * object) const240 bool HeapVerifierIntoGC<LanguageConfig>::InAliveSpace(const ObjectHeader *object) const
241 {
242 for (const auto &mem_range : this->alive_mem_ranges_) {
243 if (mem_range.Contains(ToUintPtr(object))) {
244 return true;
245 }
246 }
247 return false;
248 }
249
250 template <class LanguageConfig>
AddToVerificationInfo(RefsVerificationInfo & verification_info,size_t ref_number,ObjectHeader * object_header,ObjectHeader * referent)251 void HeapVerifierIntoGC<LanguageConfig>::AddToVerificationInfo(RefsVerificationInfo &verification_info,
252 size_t ref_number, ObjectHeader *object_header,
253 ObjectHeader *referent)
254 {
255 if (this->InCollectableSpace(referent)) {
256 ObjectVerificationInfo obj_info(referent);
257 auto it = verification_info.find(object_header);
258 if (it != verification_info.end()) {
259 it->second.insert({ref_number, obj_info});
260 } else {
261 verification_info.insert({object_header, VerifyingRefs({{ref_number, obj_info}})});
262 }
263 }
264 }
265
266 template <class LanguageConfig>
CollectVerificationInfo(PandaVector<MemRange> && collectable_mem_ranges)267 void HeapVerifierIntoGC<LanguageConfig>::CollectVerificationInfo(PandaVector<MemRange> &&collectable_mem_ranges)
268 {
269 auto *obj_allocator = heap_->GetObjectAllocator().AsObjectAllocator();
270 size_t ref_number = 0;
271 collectable_mem_ranges_ = std::move(collectable_mem_ranges);
272 const std::function<void(ObjectHeader *, ObjectHeader *)> refs_collector =
273 [this, &ref_number](ObjectHeader *object_header, ObjectHeader *referent) {
274 if (this->InCollectableSpace(object_header)) {
275 this->AddToVerificationInfo(this->collectable_verification_info_, ref_number, object_header, referent);
276 } else {
277 this->AddToVerificationInfo(this->permanent_verification_info_, ref_number, object_header, referent);
278 }
279 ++ref_number;
280 };
281
282 auto collect_functor = [&ref_number, &refs_collector](ObjectHeader *object) {
283 ref_number = 0;
284 ObjectHelpers<LanguageConfig::LANG_TYPE>::TraverseAllObjects(object, refs_collector);
285 };
286 obj_allocator->IterateOverObjects(collect_functor);
287 }
288
289 template <class LanguageConfig>
VerifyAll(PandaVector<MemRange> && alive_mem_ranges)290 size_t HeapVerifierIntoGC<LanguageConfig>::VerifyAll(PandaVector<MemRange> &&alive_mem_ranges)
291 {
292 size_t fails_count = 0U;
293 size_t ref_number = 0U;
294 auto *obj_allocator = heap_->GetObjectAllocator().AsObjectAllocator();
295 alive_mem_ranges_ = std::move(alive_mem_ranges);
296 auto it = permanent_verification_info_.begin();
297 for (auto &info : collectable_verification_info_) {
298 ObjectHeader *obj = info.first;
299 if (obj->IsForwarded()) {
300 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
301 permanent_verification_info_[GetForwardAddress(obj)] = std::move(info.second);
302 } else if (this->InAliveSpace(obj)) {
303 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
304 permanent_verification_info_[obj] = std::move(info.second);
305 }
306 }
307 collectable_verification_info_.clear();
308 const std::function<void(ObjectHeader *, ObjectHeader *)> non_young_checker =
309 [this, &fails_count](const ObjectHeader *object_header, const ObjectHeader *referent) {
310 if (this->InCollectableSpace(referent)) {
311 LOG_HEAP_VERIFIER << "Object " << std::hex << object_header << " references a dead object " << referent
312 << " after collection";
313 ++fails_count;
314 }
315 };
316 const std::function<void(ObjectHeader *, ObjectHeader *)> same_obj_checker =
317 [this, &non_young_checker, &ref_number, &fails_count, &it](ObjectHeader *object_header,
318 ObjectHeader *referent) {
319 auto ref_it = it->second.find(ref_number);
320 if (ref_it != it->second.end()) {
321 if (!ref_it->second.VerifyUpdatedRef(object_header, referent, this->InAliveSpace(referent))) {
322 ++fails_count;
323 }
324 } else {
325 non_young_checker(object_header, referent);
326 }
327 ++ref_number;
328 };
329 // Check references in alive objects
330 ObjectVisitor traverse_alive_obj = [&non_young_checker, &same_obj_checker, &ref_number, this,
331 &it](ObjectHeader *object) {
332 if (this->InCollectableSpace(object) && !this->InAliveSpace(object)) {
333 return;
334 }
335 it = this->permanent_verification_info_.find(object);
336 if (it == this->permanent_verification_info_.end()) {
337 ObjectHelpers<LanguageConfig::LANG_TYPE>::TraverseAllObjects(object, non_young_checker);
338 } else {
339 ref_number = 0U;
340 ObjectHelpers<LanguageConfig::LANG_TYPE>::TraverseAllObjects(object, same_obj_checker);
341 }
342 };
343 obj_allocator->IterateOverObjects(traverse_alive_obj);
344 return fails_count;
345 }
346
347 TEMPLATE_CLASS_LANGUAGE_CONFIG(HeapVerifier);
348 TEMPLATE_CLASS_LANGUAGE_CONFIG(FastHeapVerifier);
349 TEMPLATE_CLASS_LANGUAGE_CONFIG(HeapVerifierIntoGC);
350 } // namespace panda::mem
351