Remove remaining poisoning code.
[WebKit-https.git] / Source / WTF / wtf / Ref.h
1 /*
2  * Copyright (C) 2013-2018 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #pragma once
27
28 #include <wtf/Assertions.h>
29 #include <wtf/DumbPtrTraits.h>
30 #include <wtf/Forward.h>
31 #include <wtf/GetPtr.h>
32 #include <wtf/StdLibExtras.h>
33 #include <wtf/TypeCasts.h>
34
35 #if ASAN_ENABLED
36 extern "C" void __asan_poison_memory_region(void const volatile *addr, size_t size);
37 extern "C" void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
38 extern "C" int __asan_address_is_poisoned(void const volatile *addr);
39 #endif
40
41 namespace WTF {
42
43 inline void adopted(const void*) { }
44
45 template<typename T, typename PtrTraits> class Ref;
46 template<typename T, typename PtrTraits = DumbPtrTraits<T>> Ref<T, PtrTraits> adoptRef(T&);
47
48 template<typename T, typename PtrTraits>
49 class Ref {
50 public:
51     static constexpr bool isRef = true;
52
53     ~Ref()
54     {
55 #if ASAN_ENABLED
56         if (__asan_address_is_poisoned(this))
57             __asan_unpoison_memory_region(this, sizeof(*this));
58 #endif
59         if (m_ptr)
60             PtrTraits::unwrap(m_ptr)->deref();
61     }
62
63     Ref(T& object)
64         : m_ptr(&object)
65     {
66         object.ref();
67     }
68
69     // Use copyRef() instead.
70     Ref(const Ref& other) = delete;
71     template<typename X, typename Y> Ref(const Ref<X, Y>& other) = delete;
72
73     Ref(Ref&& other)
74         : m_ptr(&other.leakRef())
75     {
76         ASSERT(m_ptr);
77     }
78
79     template<typename X, typename Y>
80     Ref(Ref<X, Y>&& other)
81         : m_ptr(&other.leakRef())
82     {
83         ASSERT(m_ptr);
84     }
85
86     Ref& operator=(T&);
87     Ref& operator=(Ref&&);
88     template<typename X, typename Y> Ref& operator=(Ref<X, Y>&&);
89
90     // Use copyRef() and the move assignment operators instead.
91     Ref& operator=(const Ref&) = delete;
92     template<typename X, typename Y> Ref& operator=(const Ref<X, Y>&) = delete;
93
94     template<typename X, typename Y> void swap(Ref<X, Y>&);
95
96     // Hash table deleted values, which are only constructed and never copied or destroyed.
97     Ref(HashTableDeletedValueType) : m_ptr(hashTableDeletedValue()) { }
98     bool isHashTableDeletedValue() const { return m_ptr == hashTableDeletedValue(); }
99     static T* hashTableDeletedValue() { return reinterpret_cast<T*>(-1); }
100
101     Ref(HashTableEmptyValueType) : m_ptr(hashTableEmptyValue()) { }
102     bool isHashTableEmptyValue() const { return m_ptr == hashTableEmptyValue(); }
103     static T* hashTableEmptyValue() { return nullptr; }
104
105     const T* ptrAllowingHashTableEmptyValue() const { ASSERT(m_ptr || isHashTableEmptyValue()); return PtrTraits::unwrap(m_ptr); }
106     T* ptrAllowingHashTableEmptyValue() { ASSERT(m_ptr || isHashTableEmptyValue()); return PtrTraits::unwrap(m_ptr); }
107
108     void assignToHashTableEmptyValue(Ref&& reference)
109     {
110 #if ASAN_ENABLED
111         if (__asan_address_is_poisoned(this))
112             __asan_unpoison_memory_region(this, sizeof(*this));
113 #endif
114         ASSERT(m_ptr == hashTableEmptyValue());
115         m_ptr = &reference.leakRef();
116         ASSERT(m_ptr);
117     }
118
119     T* operator->() const { ASSERT(m_ptr); return PtrTraits::unwrap(m_ptr); }
120     T* ptr() const RETURNS_NONNULL { ASSERT(m_ptr); return PtrTraits::unwrap(m_ptr); }
121     T& get() const { ASSERT(m_ptr); return *PtrTraits::unwrap(m_ptr); }
122     operator T&() const { ASSERT(m_ptr); return *PtrTraits::unwrap(m_ptr); }
123     bool operator!() const { ASSERT(m_ptr); return !*m_ptr; }
124
125     template<typename X, typename Y> Ref<T, PtrTraits> replace(Ref<X, Y>&&) WARN_UNUSED_RETURN;
126
127     Ref copyRef() && = delete;
128     Ref copyRef() const & WARN_UNUSED_RETURN { return Ref(*m_ptr); }
129
130     T& leakRef() WARN_UNUSED_RETURN
131     {
132         ASSERT(m_ptr);
133
134         T& result = *PtrTraits::exchange(m_ptr, nullptr);
135 #if ASAN_ENABLED
136         __asan_poison_memory_region(this, sizeof(*this));
137 #endif
138         return result;
139     }
140
141 private:
142     friend Ref adoptRef<T>(T&);
143     template<typename X, typename Y> friend class Ref;
144
145     enum AdoptTag { Adopt };
146     Ref(T& object, AdoptTag)
147         : m_ptr(&object)
148     {
149     }
150
151     typename PtrTraits::StorageType m_ptr;
152 };
153
154 template<typename T, typename U> Ref<T, U> adoptRef(T&);
155 template<typename T> Ref<T> makeRef(T&);
156
157 template<typename T, typename U>
158 inline Ref<T, U>& Ref<T, U>::operator=(T& reference)
159 {
160     Ref copiedReference = reference;
161     swap(copiedReference);
162     return *this;
163 }
164
165 template<typename T, typename U>
166 inline Ref<T, U>& Ref<T, U>::operator=(Ref&& reference)
167 {
168 #if ASAN_ENABLED
169     if (__asan_address_is_poisoned(this))
170         __asan_unpoison_memory_region(this, sizeof(*this));
171 #endif
172     Ref movedReference = WTFMove(reference);
173     swap(movedReference);
174     return *this;
175 }
176
177 template<typename T, typename U>
178 template<typename X, typename Y>
179 inline Ref<T, U>& Ref<T, U>::operator=(Ref<X, Y>&& reference)
180 {
181 #if ASAN_ENABLED
182     if (__asan_address_is_poisoned(this))
183         __asan_unpoison_memory_region(this, sizeof(*this));
184 #endif
185     Ref movedReference = WTFMove(reference);
186     swap(movedReference);
187     return *this;
188 }
189
190 template<typename T, typename U>
191 template<typename X, typename Y>
192 inline void Ref<T, U>::swap(Ref<X, Y>& other)
193 {
194     U::swap(m_ptr, other.m_ptr);
195 }
196
197 template<typename T, typename U, typename X, typename Y, typename = std::enable_if_t<!std::is_same<U, DumbPtrTraits<T>>::value || !std::is_same<Y, DumbPtrTraits<X>>::value>>
198 inline void swap(Ref<T, U>& a, Ref<X, Y>& b)
199 {
200     a.swap(b);
201 }
202
203 template<typename T, typename U>
204 template<typename X, typename Y>
205 inline Ref<T, U> Ref<T, U>::replace(Ref<X, Y>&& reference)
206 {
207 #if ASAN_ENABLED
208     if (__asan_address_is_poisoned(this))
209         __asan_unpoison_memory_region(this, sizeof(*this));
210 #endif
211     auto oldReference = adoptRef(*m_ptr);
212     m_ptr = &reference.leakRef();
213     return oldReference;
214 }
215
216 template<typename T, typename U = DumbPtrTraits<T>, typename X, typename Y>
217 inline Ref<T, U> static_reference_cast(Ref<X, Y>& reference)
218 {
219     return Ref<T, U>(static_cast<T&>(reference.get()));
220 }
221
222 template<typename T, typename U = DumbPtrTraits<T>, typename X, typename Y>
223 inline Ref<T, U> static_reference_cast(Ref<X, Y>&& reference)
224 {
225     return adoptRef(static_cast<T&>(reference.leakRef()));
226 }
227
228 template<typename T, typename U = DumbPtrTraits<T>, typename X, typename Y>
229 inline Ref<T, U> static_reference_cast(const Ref<X, Y>& reference)
230 {
231     return Ref<T, U>(static_cast<T&>(reference.copyRef().get()));
232 }
233
234 template <typename T, typename U>
235 struct GetPtrHelper<Ref<T, U>> {
236     typedef T* PtrType;
237     static T* getPtr(const Ref<T, U>& p) { return const_cast<T*>(p.ptr()); }
238 };
239
240 template <typename T, typename U>
241 struct IsSmartPtr<Ref<T, U>> {
242     static const bool value = true;
243 };
244
245 template<typename T, typename U>
246 inline Ref<T, U> adoptRef(T& reference)
247 {
248     adopted(&reference);
249     return Ref<T, U>(reference, Ref<T, U>::Adopt);
250 }
251
252 template<typename T>
253 inline Ref<T> makeRef(T& reference)
254 {
255     return Ref<T>(reference);
256 }
257
258 template<typename ExpectedType, typename ArgType, typename PtrTraits>
259 inline bool is(Ref<ArgType, PtrTraits>& source)
260 {
261     return is<ExpectedType>(source.get());
262 }
263
264 template<typename ExpectedType, typename ArgType, typename PtrTraits>
265 inline bool is(const Ref<ArgType, PtrTraits>& source)
266 {
267     return is<ExpectedType>(source.get());
268 }
269
270 } // namespace WTF
271
272 using WTF::Ref;
273 using WTF::adoptRef;
274 using WTF::makeRef;
275 using WTF::static_reference_cast;