// Copyright 2016 Google Inc. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef ZCPOINTER_ZCPOINTER_H_ #define ZCPOINTER_ZCPOINTER_H_ #include #include #include #include #include namespace zc { class UseAfterFreeError : public std::logic_error { public: using std::logic_error::logic_error; }; #if defined(ZCPOINTER_TRACK_REFS) && ZCPOINTER_TRACK_REFS template class ref; namespace internal { enum class OwnershipBehavior { DELETE_POINTER, BORROW_POINTER, }; template class OwnedPtrDeleter { public: OwnedPtrDeleter() : refs_(), behavior_(OwnershipBehavior::DELETE_POINTER) {} ~OwnedPtrDeleter() {} explicit OwnedPtrDeleter(OwnershipBehavior behavior) : refs_(), behavior_(behavior) { } OwnedPtrDeleter(OwnedPtrDeleter&& other) : refs_(std::move(other.refs_)), behavior_(other.behavior_) { } void operator=(const OwnedPtrDeleter& o) { refs_ = o.refs_; behavior_ = o.behavior_; } void operator()(T* t) const { for (auto& ref : refs_) { ref->MarkDeleted(); } if (behavior_ == OwnershipBehavior::DELETE_POINTER) { delete t; } } protected: friend class ref; void AddRef(ref* ref) { refs_.push_front(ref); } void RemoveRef(ref* ref) { refs_.remove(ref); } private: std::forward_list*> refs_; OwnershipBehavior behavior_; }; void RaiseUseAfterFree() __attribute__((noreturn)); } // namespace internal template class owned : public std::unique_ptr> { private: using Deleter = internal::OwnedPtrDeleter; public: using std::unique_ptr::unique_ptr; ref get() { return ref(*this); } private: T* get() const { return this->std::unique_ptr::get(); } }; template class ref { public: ref() : ptr_(nullptr) {} ref(std::nullptr_t) : ref() {} explicit ref(owned& o) : ptr_(nullptr) { if (o != nullptr) { ptr_ = &o; ptr_->get_deleter().AddRef(this); } } ref(const ref& r) { *this = r; } ref& operator=(const ref& o) { ptr_ = o.ptr_; if (ptr_ != nullptr && !IsDeleted()) { ptr_->get_deleter().AddRef(this); } return *this; } ~ref() { if (ptr_ != nullptr && !IsDeleted()) { ptr_->get_deleter().RemoveRef(this); } MarkDeleted(); } T* operator->() const { CheckDeleted(); return ptr_->operator->(); } bool operator==(const ref& r) const { if (ptr_ == nullptr) { return r.ptr_ == nullptr; } else { return ptr_ == r.ptr_ && *ptr_ == *r.ptr_; } } bool operator==(std::nullptr_t) const { return ptr_ == nullptr; } bool operator!=(const ref& r) const { return !(*this == r); } protected: friend class internal::OwnedPtrDeleter; void MarkDeleted() { ptr_ = DeletedSentinel(); } private: void CheckDeleted() const { if (IsDeleted()) { internal::RaiseUseAfterFree(); } } bool IsDeleted() const { return ptr_ == DeletedSentinel(); } inline static owned* DeletedSentinel() { return reinterpret_cast*>(std::numeric_limits::max()); } owned* ptr_; }; template class member : public T { public: using T::T; ref operator&() { return ptr_.get(); } private: owned ptr_ = owned(this, internal::OwnedPtrDeleter( internal::OwnershipBehavior::BORROW_POINTER)); }; #else template using owned = std::unique_ptr; template using ref = T*; template using member = T; #endif } // namespace zc #endif // ZCPOINTER_ZCPOINTER_H_