// Copyright 2015 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "CheckFieldsVisitor.h" #include #include "RecordInfo.h" #include "llvm/Support/ErrorHandling.h" CheckFieldsVisitor::CheckFieldsVisitor(const BlinkGCPluginOptions& options) : options_(options), current_(0), stack_allocated_host_(false) {} CheckFieldsVisitor::Errors& CheckFieldsVisitor::invalid_fields() { return invalid_fields_; } bool CheckFieldsVisitor::ContainsInvalidFields(RecordInfo* info) { stack_allocated_host_ = info->IsStackAllocated(); managed_host_ = stack_allocated_host_ || info->IsGCAllocated() || info->IsNonNewable() || info->IsOnlyPlacementNewable(); for (RecordInfo::Fields::iterator it = info->GetFields().begin(); it != info->GetFields().end(); ++it) { context().clear(); current_ = &it->second; current_->edge()->Accept(this); } return !invalid_fields_.empty(); } void CheckFieldsVisitor::AtMember(Member*) { if (managed_host_) return; // A member is allowed to appear in the context of a root. for (Context::iterator it = context().begin(); it != context().end(); ++it) { if ((*it)->Kind() == Edge::kRoot) return; } invalid_fields_.push_back(std::make_pair(current_, kMemberInUnmanaged)); } void CheckFieldsVisitor::AtWeakMember(WeakMember*) { // TODO(sof): remove this once crbug.com/724418's change // has safely been rolled out. if (options_.enable_weak_members_in_unmanaged_classes) return; AtMember(nullptr); } void CheckFieldsVisitor::AtIterator(Iterator* edge) { if (!managed_host_) return; if (edge->IsUnsafe()) invalid_fields_.push_back(std::make_pair(current_, kIteratorToGCManaged)); } void CheckFieldsVisitor::AtValue(Value* edge) { // TODO: what should we do to check unions? if (edge->value()->record()->isUnion()) return; if (!stack_allocated_host_ && edge->value()->IsStackAllocated()) { invalid_fields_.push_back(std::make_pair(current_, kPtrFromHeapToStack)); return; } if (!Parent() && edge->value()->IsGCDerived() && !edge->value()->IsGCMixin()) { invalid_fields_.push_back(std::make_pair(current_, kGCDerivedPartObject)); return; } if (options_.no_members_in_stack_allocated) { // Members/WeakMembers are prohibited if the host is stack allocated, but // heap collections with Members are okay. if (stack_allocated_host_ && Parent() && (Parent()->IsMember() || Parent()->IsWeakMember())) { if (!GrandParent() || !GrandParent()->IsCollection()) { invalid_fields_.push_back( std::make_pair(current_, kMemberInStackAllocated)); return; } } } // If in a stack allocated context, be fairly insistent that T in Member // is GC allocated, as stack allocated objects do not have a trace() // that separately verifies the validity of Member. // // Notice that an error is only reported if T's definition is in scope; // we do not require that it must be brought into scope as that would // prevent declarations of mutually dependent class types. // // (Note: Member<>'s constructor will at run-time verify that the // pointer it wraps is indeed heap allocated.) if (stack_allocated_host_ && Parent() && (Parent()->IsMember() || Parent()->IsWeakMember()) && edge->value()->HasDefinition() && !edge->value()->IsGCAllocated()) { invalid_fields_.push_back(std::make_pair(current_, kMemberToGCUnmanaged)); return; } if (!Parent() || !edge->value()->IsGCAllocated()) return; // Disallow unique_ptr, RefPtr. if (Parent()->IsUniquePtr() || Parent()->IsRefPtr()) { invalid_fields_.push_back(std::make_pair( current_, InvalidSmartPtr(Parent()))); return; } if (Parent()->IsRawPtr() && !(stack_allocated_host_ && options_.no_members_in_stack_allocated)) { RawPtr* rawPtr = static_cast(Parent()); Error error = rawPtr->HasReferenceType() ? kReferencePtrToGCManaged : kRawPtrToGCManaged; invalid_fields_.push_back(std::make_pair(current_, error)); } } void CheckFieldsVisitor::AtCollection(Collection* edge) { if (edge->on_heap() && Parent() && Parent()->IsUniquePtr()) invalid_fields_.push_back(std::make_pair(current_, kUniquePtrToGCManaged)); } CheckFieldsVisitor::Error CheckFieldsVisitor::InvalidSmartPtr(Edge* ptr) { if (ptr->IsRefPtr()) return kRefPtrToGCManaged; if (ptr->IsUniquePtr()) return kUniquePtrToGCManaged; llvm_unreachable("Unknown smart pointer kind"); }