• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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