• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/heap/cppgc/marking-verifier.h"
6 
7 #include "include/cppgc/internal/caged-heap-local-data.h"
8 #include "src/base/logging.h"
9 #include "src/heap/cppgc/gc-info-table.h"
10 #include "src/heap/cppgc/heap-object-header.h"
11 #include "src/heap/cppgc/heap.h"
12 #include "src/heap/cppgc/marking-visitor.h"
13 #include "src/heap/cppgc/object-view.h"
14 
15 namespace cppgc {
16 namespace internal {
17 
VerifyMarked(const void * base_object_payload) const18 void VerificationState::VerifyMarked(const void* base_object_payload) const {
19   const HeapObjectHeader& child_header =
20       HeapObjectHeader::FromObject(base_object_payload);
21 
22   if (!child_header.IsMarked()) {
23     FATAL(
24         "MarkingVerifier: Encountered unmarked object.\n"
25         "#\n"
26         "# Hint:\n"
27         "#   %s (%p)\n"
28         "#     \\-> %s (%p)",
29         parent_ ? parent_->GetName().value : "Stack",
30         parent_ ? parent_->ObjectStart() : nullptr,
31         child_header.GetName().value, child_header.ObjectStart());
32   }
33 }
34 
MarkingVerifierBase(HeapBase & heap,Heap::Config::CollectionType collection_type,VerificationState & verification_state,std::unique_ptr<cppgc::Visitor> visitor)35 MarkingVerifierBase::MarkingVerifierBase(
36     HeapBase& heap, Heap::Config::CollectionType collection_type,
37     VerificationState& verification_state,
38     std::unique_ptr<cppgc::Visitor> visitor)
39     : ConservativeTracingVisitor(heap, *heap.page_backend(), *visitor.get()),
40       verification_state_(verification_state),
41       visitor_(std::move(visitor)),
42       collection_type_(collection_type) {}
43 
Run(Heap::Config::StackState stack_state,uintptr_t stack_end,v8::base::Optional<size_t> expected_marked_bytes)44 void MarkingVerifierBase::Run(
45     Heap::Config::StackState stack_state, uintptr_t stack_end,
46     v8::base::Optional<size_t> expected_marked_bytes) {
47   Traverse(heap_.raw_heap());
48 // Avoid verifying the stack when running with TSAN as the TSAN runtime changes
49 // stack contents when e.g. working with locks. Specifically, the marker uses
50 // locks in slow path operations which results in stack changes throughout
51 // marking. This means that the conservative iteration below may find more
52 // objects then the regular marker. The difference is benign as the delta of
53 // objects is not reachable from user code but it prevents verification.
54 #if !defined(THREAD_SANITIZER)
55   if (stack_state == Heap::Config::StackState::kMayContainHeapPointers) {
56     in_construction_objects_ = &in_construction_objects_stack_;
57     heap_.stack()->IteratePointersUnsafe(this, stack_end);
58     // The objects found through the unsafe iteration are only a subset of the
59     // regular iteration as they miss objects held alive only from callee-saved
60     // registers that are never pushed on the stack and SafeStack.
61     CHECK_LE(in_construction_objects_stack_.size(),
62              in_construction_objects_heap_.size());
63     for (auto* header : in_construction_objects_stack_) {
64       CHECK_NE(in_construction_objects_heap_.end(),
65                in_construction_objects_heap_.find(header));
66     }
67   }
68 #endif  // !defined(THREAD_SANITIZER)
69   if (expected_marked_bytes && verifier_found_marked_bytes_are_exact_) {
70     CHECK_EQ(expected_marked_bytes.value(), verifier_found_marked_bytes_);
71   }
72 }
73 
VisitInConstructionConservatively(HeapObjectHeader & header,TraceConservativelyCallback callback)74 void MarkingVerifierBase::VisitInConstructionConservatively(
75     HeapObjectHeader& header, TraceConservativelyCallback callback) {
76   if (in_construction_objects_->find(&header) !=
77       in_construction_objects_->end())
78     return;
79   in_construction_objects_->insert(&header);
80 
81   // Stack case: Parent is stack and this is merely ensuring that the object
82   // itself is marked. If the object is marked, then it is being processed by
83   // the on-heap phase.
84   if (verification_state_.IsParentOnStack()) {
85     verification_state_.VerifyMarked(header.ObjectStart());
86     return;
87   }
88 
89   // Heap case: Dispatching parent object that must be marked (pre-condition).
90   CHECK(header.IsMarked());
91   callback(this, header);
92 }
93 
VisitPointer(const void * address)94 void MarkingVerifierBase::VisitPointer(const void* address) {
95   // Entry point for stack walk. The conservative visitor dispatches as follows:
96   // - Fully constructed objects: Visit()
97   // - Objects in construction: VisitInConstructionConservatively()
98   TraceConservativelyIfNeeded(address);
99 }
100 
VisitHeapObjectHeader(HeapObjectHeader & header)101 bool MarkingVerifierBase::VisitHeapObjectHeader(HeapObjectHeader& header) {
102   // Verify only non-free marked objects.
103   if (!header.IsMarked()) return true;
104 
105   DCHECK(!header.IsFree());
106 
107 #if defined(CPPGC_YOUNG_GENERATION)
108   if (collection_type_ == Heap::Config::CollectionType::kMinor) {
109     const auto age = heap_.caged_heap().local_data().age_table.GetAge(
110         heap_.caged_heap().OffsetFromAddress(header.ObjectStart()));
111     if (age == AgeTable::Age::kOld) {
112       // Do not verify old objects.
113       return true;
114     } else if (age == AgeTable::Age::kMixed) {
115       // If the age is not known, the marked bytes may not be exact as possibly
116       // old objects are verified as well.
117       verifier_found_marked_bytes_are_exact_ = false;
118     }
119     // Verify young and unknown objects.
120   }
121 #endif  // defined(CPPGC_YOUNG_GENERATION)
122 
123   verification_state_.SetCurrentParent(&header);
124 
125   if (!header.IsInConstruction()) {
126     header.Trace(visitor_.get());
127   } else {
128     // Dispatches to conservative tracing implementation.
129     TraceConservativelyIfNeeded(header);
130   }
131 
132   verifier_found_marked_bytes_ +=
133       ObjectView<>(header).Size() + sizeof(HeapObjectHeader);
134 
135   verification_state_.SetCurrentParent(nullptr);
136 
137   return true;
138 }
139 
140 namespace {
141 
142 class VerificationVisitor final : public cppgc::Visitor {
143  public:
VerificationVisitor(VerificationState & state)144   explicit VerificationVisitor(VerificationState& state)
145       : cppgc::Visitor(VisitorFactory::CreateKey()), state_(state) {}
146 
Visit(const void *,TraceDescriptor desc)147   void Visit(const void*, TraceDescriptor desc) final {
148     state_.VerifyMarked(desc.base_object_payload);
149   }
150 
VisitWeak(const void *,TraceDescriptor desc,WeakCallback,const void *)151   void VisitWeak(const void*, TraceDescriptor desc, WeakCallback,
152                  const void*) final {
153     // Weak objects should have been cleared at this point. As a consequence,
154     // all objects found through weak references have to point to live objects
155     // at this point.
156     state_.VerifyMarked(desc.base_object_payload);
157   }
158 
VisitWeakContainer(const void * object,TraceDescriptor,TraceDescriptor weak_desc,WeakCallback,const void *)159   void VisitWeakContainer(const void* object, TraceDescriptor,
160                           TraceDescriptor weak_desc, WeakCallback,
161                           const void*) final {
162     if (!object) return;
163 
164     // Contents of weak containers are found themselves through page iteration
165     // and are treated strongly, similar to how they are treated strongly when
166     // found through stack scanning. The verification here only makes sure that
167     // the container itself is properly marked.
168     state_.VerifyMarked(weak_desc.base_object_payload);
169   }
170 
171  private:
172   VerificationState& state_;
173 };
174 
175 }  // namespace
176 
MarkingVerifier(HeapBase & heap_base,Heap::Config::CollectionType collection_type)177 MarkingVerifier::MarkingVerifier(HeapBase& heap_base,
178                                  Heap::Config::CollectionType collection_type)
179     : MarkingVerifierBase(heap_base, collection_type, state_,
180                           std::make_unique<VerificationVisitor>(state_)) {}
181 
182 }  // namespace internal
183 }  // namespace cppgc
184