Throw a custom exception type and attempt to catch it in the test program.
[zcpointer.git] / zcpointer.h
1 // Copyright 2016 Google Inc. All rights reserved.
2 //
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 #include <limits>
16 #include <memory>
17 #include <forward_list>
18 #include <stdexcept>
19
20 namespace zc {
21
22 class UseAfterFreeError : public std::logic_error {
23 public:
24 using std::logic_error::logic_error;
25 };
26
27 #if defined(ZCPOINTER_TRACK_REFS) && ZCPOINTER_TRACK_REFS
28
29 template <typename T> class ref;
30
31 namespace internal {
32
33 template <typename T>
34 class OwnedPtrDeleter {
35 public:
36 OwnedPtrDeleter() {}
37 ~OwnedPtrDeleter() {}
38
39 OwnedPtrDeleter(OwnedPtrDeleter&& other) : refs_(std::move(other.refs_)) {
40 }
41
42 void operator()(T* t) const {
43 for (auto& ref : refs_) {
44 ref->MarkDeleted();
45 }
46 delete t;
47 }
48
49 protected:
50 friend class ref<T>;
51
52 void AddRef(ref<T>* ref) {
53 refs_.push_front(ref);
54 }
55
56 void RemoveRef(ref<T>* ref) {
57 refs_.remove(ref);
58 }
59
60 private:
61 std::forward_list<ref<T>*> refs_;
62 };
63
64 void RaiseUseAfterFree(const char* error) __attribute__((noreturn));
65
66 } // namespace internal
67
68 template <typename T>
69 class owned : public std::unique_ptr<T, internal::OwnedPtrDeleter<T>> {
70 private:
71 using Deleter = internal::OwnedPtrDeleter<T>;
72
73 public:
74 using std::unique_ptr<T, Deleter>::unique_ptr;
75
76 ref<T> get() {
77 return ref<T>(*this);
78 }
79
80 private:
81 T* get() const {
82 return this->std::unique_ptr<T, Deleter>::get();
83 }
84 };
85
86 template <typename T>
87 class ref {
88 public:
89 ref() : ptr_(DeletedSentinel()) {}
90
91 explicit ref(owned<T>& o) : ptr_(&o) {
92 ptr_->get_deleter().AddRef(this);
93 }
94
95 ref(const ref<T>& o) {
96 *this = o;
97 }
98
99 ref<T>& operator=(const ref<T>& o) {
100 ptr_ = o.ptr_;
101 if (!IsDeleted()) {
102 ptr_->get_deleter().AddRef(this);
103 }
104 return *this;
105 }
106
107 ~ref() {
108 if (!IsDeleted()) {
109 ptr_->get_deleter().RemoveRef(this);
110 MarkDeleted();
111 }
112 }
113
114 T* operator->() const {
115 CheckDeleted();
116 return ptr_->operator->();
117 }
118
119 protected:
120 friend class internal::OwnedPtrDeleter<T>;
121
122 void MarkDeleted() {
123 ptr_ = DeletedSentinel();
124 }
125
126 private:
127 void CheckDeleted() const {
128 if (IsDeleted()) {
129 internal::RaiseUseAfterFree("attempt to access deleted pointer");
130 }
131 }
132
133 bool IsDeleted() const {
134 return ptr_ == DeletedSentinel();
135 }
136
137 inline static owned<T>* DeletedSentinel() {
138 return reinterpret_cast<owned<T>*>(std::numeric_limits<uintptr_t>::max());
139 }
140
141 owned<T>* ptr_;
142 };
143
144 #else
145
146 template <typename T>
147 using owned = std::unique_ptr<T>;
148
149 template <typename T>
150 using ref = T*;
151
152 #endif
153
154 } // namespace zc