Harden failure signal handler in the face of memory corruptions
[folly.git] / folly / Memory.h
1 /*
2  * Copyright 2014 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #ifndef FOLLY_MEMORY_H_
18 #define FOLLY_MEMORY_H_
19
20 #include "folly/Traits.h"
21
22 #include <memory>
23 #include <limits>
24 #include <utility>
25 #include <exception>
26 #include <stdexcept>
27
28 #include <cstddef>
29
30 namespace folly {
31
32 /**
33  * For exception safety and consistency with make_shared. Erase me when
34  * we have std::make_unique().
35  *
36  * @author Louis Brandy (ldbrandy@fb.com)
37  * @author Xu Ning (xning@fb.com)
38  */
39
40 template<typename T, typename Dp = std::default_delete<T>, typename... Args>
41 std::unique_ptr<T, Dp> make_unique(Args&&... args) {
42   return std::unique_ptr<T, Dp>(new T(std::forward<Args>(args)...));
43 }
44
45 /*
46  * StlAllocator wraps a SimpleAllocator into a STL-compliant
47  * allocator, maintaining an instance pointer to the simple allocator
48  * object.  The underlying SimpleAllocator object must outlive all
49  * instances of StlAllocator using it.
50  *
51  * A SimpleAllocator must provide two methods:
52  *
53  *    void* allocate(size_t size);
54  *    void deallocate(void* ptr);
55  *
56  * which, respectively, allocate a block of size bytes (aligned to the
57  * maximum alignment required on your system), throwing std::bad_alloc
58  * if the allocation can't be satisfied, and free a previously
59  * allocated block.
60  *
61  * Note that the following allocator resembles the standard allocator
62  * quite well:
63  *
64  * class MallocAllocator {
65  *  public:
66  *   void* allocate(size_t size) {
67  *     void* p = malloc(size);
68  *     if (!p) throw std::bad_alloc();
69  *     return p;
70  *   }
71  *   void deallocate(void* p) {
72  *     free(p);
73  *   }
74  * };
75  *
76  * But note that if you pass StlAllocator<MallocAllocator,...> to a
77  * standard container it will be larger due to the contained state
78  * pointer.
79  *
80  * author: Tudor Bosman <tudorb@fb.com>
81  */
82
83 // This would be so much simpler with std::allocator_traits, but gcc 4.6.2
84 // doesn't support it.
85 template <class Alloc, class T> class StlAllocator;
86
87 template <class Alloc> class StlAllocator<Alloc, void> {
88  public:
89   typedef void value_type;
90   typedef void* pointer;
91   typedef const void* const_pointer;
92
93   StlAllocator() : alloc_(nullptr) { }
94   explicit StlAllocator(Alloc* a) : alloc_(a) { }
95
96   Alloc* alloc() const {
97     return alloc_;
98   }
99
100   template <class U> struct rebind {
101     typedef StlAllocator<Alloc, U> other;
102   };
103
104   bool operator!=(const StlAllocator<Alloc, void>& other) const {
105     return alloc_ != other.alloc_;
106   }
107
108   bool operator==(const StlAllocator<Alloc, void>& other) const {
109     return alloc_ == other.alloc_;
110   }
111
112  private:
113   Alloc* alloc_;
114 };
115
116 template <class Alloc, class T>
117 class StlAllocator {
118  public:
119   typedef T value_type;
120   typedef T* pointer;
121   typedef const T* const_pointer;
122   typedef T& reference;
123   typedef const T& const_reference;
124
125   typedef ptrdiff_t difference_type;
126   typedef size_t size_type;
127
128   StlAllocator() : alloc_(nullptr) { }
129   explicit StlAllocator(Alloc* a) : alloc_(a) { }
130
131   template <class U> StlAllocator(const StlAllocator<Alloc, U>& other)
132     : alloc_(other.alloc()) { }
133
134   T* allocate(size_t n, const void* hint = nullptr) {
135     return static_cast<T*>(alloc_->allocate(n * sizeof(T)));
136   }
137
138   void deallocate(T* p, size_t n) {
139     alloc_->deallocate(p);
140   }
141
142   size_t max_size() const {
143     return std::numeric_limits<size_t>::max();
144   }
145
146   T* address(T& x) const {
147     return std::addressof(x);
148   }
149
150   const T* address(const T& x) const {
151     return std::addressof(x);
152   }
153
154   template <class... Args>
155   void construct(T* p, Args&&... args) {
156     new (p) T(std::forward<Args>(args)...);
157   }
158
159   void destroy(T* p) {
160     p->~T();
161   }
162
163   Alloc* alloc() const {
164     return alloc_;
165   }
166
167   template <class U> struct rebind {
168     typedef StlAllocator<Alloc, U> other;
169   };
170
171   bool operator!=(const StlAllocator<Alloc, T>& other) const {
172     return alloc_ != other.alloc_;
173   }
174
175   bool operator==(const StlAllocator<Alloc, T>& other) const {
176     return alloc_ == other.alloc_;
177   }
178
179  private:
180   Alloc* alloc_;
181 };
182
183 /**
184  * Helper function to obtain rebound allocators
185  *
186  * @author: Marcelo Juchem <marcelo@fb.com>
187  */
188 template <typename T, typename Allocator>
189 typename Allocator::template rebind<T>::other rebind_allocator(
190   Allocator const& allocator
191 ) {
192   return typename Allocator::template rebind<T>::other(allocator);
193 }
194
195 /*
196  * Helper classes/functions for creating a unique_ptr using a custom
197  * allocator.
198  *
199  * @author: Marcelo Juchem <marcelo@fb.com>
200  */
201
202 // Derives from the allocator to take advantage of the empty base
203 // optimization when possible.
204 template <typename Allocator>
205 class allocator_delete
206   : private std::remove_reference<Allocator>::type
207 {
208   typedef typename std::remove_reference<Allocator>::type allocator_type;
209
210 public:
211   typedef typename Allocator::pointer pointer;
212
213   allocator_delete() = default;
214
215   explicit allocator_delete(const allocator_type& allocator)
216     : allocator_type(allocator)
217   {}
218
219   explicit allocator_delete(allocator_type&& allocator)
220     : allocator_type(std::move(allocator))
221   {}
222
223   template <typename U>
224   allocator_delete(const allocator_delete<U>& other)
225     : allocator_type(other.get_allocator())
226   {}
227
228   allocator_type& get_allocator() const {
229     return *const_cast<allocator_delete*>(this);
230   }
231
232   void operator()(pointer p) const {
233     if (!p) return;
234     const_cast<allocator_delete*>(this)->destroy(p);
235     const_cast<allocator_delete*>(this)->deallocate(p, 1);
236   }
237 };
238
239 template <typename T, typename Allocator>
240 class is_simple_allocator {
241   FOLLY_CREATE_HAS_MEMBER_FN_TRAITS(has_destroy, destroy);
242
243   typedef typename std::remove_const<
244     typename std::remove_reference<Allocator>::type
245   >::type allocator;
246   typedef typename std::remove_reference<T>::type value_type;
247   typedef value_type* pointer;
248
249 public:
250   constexpr static bool value = !has_destroy<allocator, void(pointer)>::value
251     && !has_destroy<allocator, void(void*)>::value;
252 };
253
254 template <typename T, typename Allocator>
255 struct as_stl_allocator {
256   typedef typename std::conditional<
257     is_simple_allocator<T, Allocator>::value,
258     folly::StlAllocator<
259       typename std::remove_reference<Allocator>::type,
260       typename std::remove_reference<T>::type
261     >,
262     typename std::remove_reference<Allocator>::type
263   >::type type;
264 };
265
266 template <typename T, typename Allocator>
267 typename std::enable_if<
268   is_simple_allocator<T, Allocator>::value,
269   folly::StlAllocator<
270     typename std::remove_reference<Allocator>::type,
271     typename std::remove_reference<T>::type
272   >
273 >::type make_stl_allocator(Allocator&& allocator) {
274   return folly::StlAllocator<
275     typename std::remove_reference<Allocator>::type,
276     typename std::remove_reference<T>::type
277   >(&allocator);
278 }
279
280 template <typename T, typename Allocator>
281 typename std::enable_if<
282   !is_simple_allocator<T, Allocator>::value,
283   typename std::remove_reference<Allocator>::type
284 >::type make_stl_allocator(Allocator&& allocator) {
285   return std::move(allocator);
286 }
287
288 /**
289  * AllocatorUniquePtr: a unique_ptr that supports both STL-style
290  * allocators and SimpleAllocator
291  *
292  * @author: Marcelo Juchem <marcelo@fb.com>
293  */
294
295 template <typename T, typename Allocator>
296 struct AllocatorUniquePtr {
297   typedef std::unique_ptr<T,
298     folly::allocator_delete<
299       typename std::conditional<
300         is_simple_allocator<T, Allocator>::value,
301         folly::StlAllocator<typename std::remove_reference<Allocator>::type, T>,
302         typename std::remove_reference<Allocator>::type
303       >::type
304     >
305   > type;
306 };
307
308 /**
309  * Functions to allocate a unique_ptr / shared_ptr, supporting both
310  * STL-style allocators and SimpleAllocator, analog to std::allocate_shared
311  *
312  * @author: Marcelo Juchem <marcelo@fb.com>
313  */
314
315 template <typename T, typename Allocator, typename ...Args>
316 typename AllocatorUniquePtr<T, Allocator>::type allocate_unique(
317   Allocator&& allocator, Args&&... args
318 ) {
319   auto stlAllocator = folly::make_stl_allocator<T>(
320     std::forward<Allocator>(allocator)
321   );
322   auto p = stlAllocator.allocate(1);
323
324   try {
325     stlAllocator.construct(p, std::forward<Args>(args)...);
326
327     return {p,
328       folly::allocator_delete<decltype(stlAllocator)>(std::move(stlAllocator))
329     };
330   } catch (...) {
331     stlAllocator.deallocate(p, 1);
332     throw;
333   }
334 }
335
336 template <typename T, typename Allocator, typename ...Args>
337 std::shared_ptr<T> allocate_shared(Allocator&& allocator, Args&&... args) {
338   return std::allocate_shared<T>(
339     folly::make_stl_allocator<T>(std::forward<Allocator>(allocator)),
340     std::forward<Args>(args)...
341   );
342 }
343
344 }  // namespace folly
345
346 #endif /* FOLLY_MEMORY_H_ */