1 // Copyright 2015 The Chromium 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 "CheckFieldsVisitor.h"
6
7 #include <cassert>
8
9 #include "RecordInfo.h"
10
CheckFieldsVisitor(const BlinkGCPluginOptions & options)11 CheckFieldsVisitor::CheckFieldsVisitor(const BlinkGCPluginOptions& options)
12 : options_(options), current_(0), stack_allocated_host_(false) {}
13
invalid_fields()14 CheckFieldsVisitor::Errors& CheckFieldsVisitor::invalid_fields() {
15 return invalid_fields_;
16 }
17
ContainsInvalidFields(RecordInfo * info)18 bool CheckFieldsVisitor::ContainsInvalidFields(RecordInfo* info) {
19 stack_allocated_host_ = info->IsStackAllocated();
20 managed_host_ = stack_allocated_host_ ||
21 info->IsGCAllocated() ||
22 info->IsNonNewable() ||
23 info->IsOnlyPlacementNewable();
24 for (RecordInfo::Fields::iterator it = info->GetFields().begin();
25 it != info->GetFields().end();
26 ++it) {
27 context().clear();
28 current_ = &it->second;
29 current_->edge()->Accept(this);
30 }
31 return !invalid_fields_.empty();
32 }
33
AtMember(Member *)34 void CheckFieldsVisitor::AtMember(Member*) {
35 if (managed_host_)
36 return;
37 // A member is allowed to appear in the context of a root.
38 for (Context::iterator it = context().begin();
39 it != context().end();
40 ++it) {
41 if ((*it)->Kind() == Edge::kRoot)
42 return;
43 }
44 invalid_fields_.push_back(std::make_pair(current_, kMemberInUnmanaged));
45 }
46
AtWeakMember(WeakMember *)47 void CheckFieldsVisitor::AtWeakMember(WeakMember*) {
48 // TODO(sof): remove this once crbug.com/724418's change
49 // has safely been rolled out.
50 if (options_.enable_weak_members_in_unmanaged_classes)
51 return;
52 AtMember(nullptr);
53 }
54
AtIterator(Iterator * edge)55 void CheckFieldsVisitor::AtIterator(Iterator* edge) {
56 if (!managed_host_)
57 return;
58
59 if (edge->IsUnsafe())
60 invalid_fields_.push_back(std::make_pair(current_, kIteratorToGCManaged));
61 }
62
AtValue(Value * edge)63 void CheckFieldsVisitor::AtValue(Value* edge) {
64 // TODO: what should we do to check unions?
65 if (edge->value()->record()->isUnion())
66 return;
67
68 if (!stack_allocated_host_ && edge->value()->IsStackAllocated()) {
69 invalid_fields_.push_back(std::make_pair(current_, kPtrFromHeapToStack));
70 return;
71 }
72
73 if (!Parent() &&
74 edge->value()->IsGCDerived() &&
75 !edge->value()->IsGCMixin()) {
76 invalid_fields_.push_back(std::make_pair(current_, kGCDerivedPartObject));
77 return;
78 }
79
80 // If in a stack allocated context, be fairly insistent that T in Member<T>
81 // is GC allocated, as stack allocated objects do not have a trace()
82 // that separately verifies the validity of Member<T>.
83 //
84 // Notice that an error is only reported if T's definition is in scope;
85 // we do not require that it must be brought into scope as that would
86 // prevent declarations of mutually dependent class types.
87 //
88 // (Note: Member<>'s constructor will at run-time verify that the
89 // pointer it wraps is indeed heap allocated.)
90 if (stack_allocated_host_ && Parent() && Parent()->IsMember() &&
91 edge->value()->HasDefinition() && !edge->value()->IsGCAllocated()) {
92 invalid_fields_.push_back(std::make_pair(current_,
93 kMemberToGCUnmanaged));
94 return;
95 }
96
97 if (!Parent() || !edge->value()->IsGCAllocated())
98 return;
99
100 // Disallow unique_ptr<T>, RefPtr<T> and T* to stack-allocated types.
101 if (Parent()->IsUniquePtr() ||
102 Parent()->IsRefPtr() ||
103 (stack_allocated_host_ && Parent()->IsRawPtr())) {
104 invalid_fields_.push_back(std::make_pair(
105 current_, InvalidSmartPtr(Parent())));
106 return;
107 }
108 if (Parent()->IsRawPtr()) {
109 RawPtr* rawPtr = static_cast<RawPtr*>(Parent());
110 Error error = rawPtr->HasReferenceType() ?
111 kReferencePtrToGCManaged : kRawPtrToGCManaged;
112 invalid_fields_.push_back(std::make_pair(current_, error));
113 }
114 }
115
AtCollection(Collection * edge)116 void CheckFieldsVisitor::AtCollection(Collection* edge) {
117 if (edge->on_heap() && Parent() && Parent()->IsUniquePtr())
118 invalid_fields_.push_back(std::make_pair(current_, kUniquePtrToGCManaged));
119 }
120
InvalidSmartPtr(Edge * ptr)121 CheckFieldsVisitor::Error CheckFieldsVisitor::InvalidSmartPtr(Edge* ptr) {
122 if (ptr->IsRawPtr()) {
123 if (static_cast<RawPtr*>(ptr)->HasReferenceType())
124 return kReferencePtrToGCManaged;
125 else
126 return kRawPtrToGCManaged;
127 }
128 if (ptr->IsRefPtr())
129 return kRefPtrToGCManaged;
130 if (ptr->IsUniquePtr())
131 return kUniquePtrToGCManaged;
132 assert(false && "Unknown smart pointer kind");
133 }
134