1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: sw=4 ts=4 et :
3 */
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7
8 #ifndef mozilla_mozalloc_h
9 #define mozilla_mozalloc_h
10
11 /*
12 * https://bugzilla.mozilla.org/show_bug.cgi?id=427099
13 */
14
15 #if defined(__cplusplus)
16 # include <new>
17 // Since libstdc++ 6, including the C headers (e.g. stdlib.h) instead of the
18 // corresponding C++ header (e.g. cstdlib) can cause confusion in C++ code
19 // using things defined there. Specifically, with stdlib.h, the use of abs()
20 // in gfx/graphite2/src/inc/UtfCodec.h somehow ends up picking the wrong abs()
21 # include <cstdlib>
22 # include <cstring>
23 #else
24 # include <stdlib.h>
25 # include <string.h>
26 #endif
27
28 #if defined(__cplusplus)
29 #include "mozilla/fallible.h"
30 #include "mozilla/mozalloc_abort.h"
31 #include "mozilla/TemplateLib.h"
32 #endif
33 #include "mozilla/Attributes.h"
34 #include "mozilla/Types.h"
35
36 #define MOZALLOC_HAVE_XMALLOC
37
38 #if defined(MOZ_ALWAYS_INLINE_EVEN_DEBUG)
39 # define MOZALLOC_INLINE MOZ_ALWAYS_INLINE_EVEN_DEBUG
40 #elif defined(HAVE_FORCEINLINE)
41 # define MOZALLOC_INLINE __forceinline
42 #else
43 # define MOZALLOC_INLINE inline
44 #endif
45
46 /* Workaround build problem with Sun Studio 12 */
47 #if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
48 # undef MOZ_MUST_USE
49 # define MOZ_MUST_USE
50 # undef MOZ_ALLOCATOR
51 # define MOZ_ALLOCATOR
52 #endif
53
54 #if defined(__cplusplus)
55 extern "C" {
56 #endif /* ifdef __cplusplus */
57
58 /*
59 * We need to use malloc_impl and free_impl in this file when they are
60 * defined, because of how mozglue.dll is linked on Windows, where using
61 * malloc/free would end up using the symbols from the MSVCRT instead of
62 * ours.
63 */
64 #ifndef free_impl
65 #define free_impl free
66 #define free_impl_
67 #endif
68 #ifndef malloc_impl
69 #define malloc_impl malloc
70 #define malloc_impl_
71 #endif
72
73 /*
74 * Each declaration below is analogous to a "standard" allocation
75 * function, except that the out-of-memory handling is made explicit.
76 * The |moz_x| versions will never return a NULL pointer; if memory
77 * is exhausted, they abort. The |moz_| versions may return NULL
78 * pointers if memory is exhausted: their return value must be checked.
79 *
80 * All these allocation functions are *guaranteed* to return a pointer
81 * to memory allocated in such a way that that memory can be freed by
82 * passing that pointer to |free()|.
83 */
84
85 MFBT_API void* moz_xmalloc(size_t size)
86 MOZ_ALLOCATOR;
87
88 MFBT_API void* moz_xcalloc(size_t nmemb, size_t size)
89 MOZ_ALLOCATOR;
90
91 MFBT_API void* moz_xrealloc(void* ptr, size_t size)
92 MOZ_ALLOCATOR;
93
94 MFBT_API char* moz_xstrdup(const char* str)
95 MOZ_ALLOCATOR;
96
97 MFBT_API size_t moz_malloc_usable_size(void *ptr);
98
99 MFBT_API size_t moz_malloc_size_of(const void *ptr);
100
101 #if defined(HAVE_STRNDUP)
102 MFBT_API char* moz_xstrndup(const char* str, size_t strsize)
103 MOZ_ALLOCATOR;
104 #endif /* if defined(HAVE_STRNDUP) */
105
106
107 #if defined(HAVE_POSIX_MEMALIGN)
108 MFBT_API MOZ_MUST_USE
109 int moz_xposix_memalign(void **ptr, size_t alignment, size_t size);
110
111 MFBT_API MOZ_MUST_USE
112 int moz_posix_memalign(void **ptr, size_t alignment, size_t size);
113 #endif /* if defined(HAVE_POSIX_MEMALIGN) */
114
115
116 #if defined(HAVE_MEMALIGN)
117 MFBT_API void* moz_xmemalign(size_t boundary, size_t size)
118 MOZ_ALLOCATOR;
119 #endif /* if defined(HAVE_MEMALIGN) */
120
121
122 #if defined(HAVE_VALLOC)
123 MFBT_API void* moz_xvalloc(size_t size)
124 MOZ_ALLOCATOR;
125 #endif /* if defined(HAVE_VALLOC) */
126
127
128 #ifdef __cplusplus
129 } /* extern "C" */
130 #endif /* ifdef __cplusplus */
131
132
133 #ifdef __cplusplus
134
135 /*
136 * We implement the default operators new/delete as part of
137 * libmozalloc, replacing their definitions in libstdc++. The
138 * operator new* definitions in libmozalloc will never return a NULL
139 * pointer.
140 *
141 * Each operator new immediately below returns a pointer to memory
142 * that can be delete'd by any of
143 *
144 * (1) the matching infallible operator delete immediately below
145 * (2) the matching "fallible" operator delete further below
146 * (3) the matching system |operator delete(void*, std::nothrow)|
147 * (4) the matching system |operator delete(void*) throw(std::bad_alloc)|
148 *
149 * NB: these are declared |throw(std::bad_alloc)|, though they will never
150 * throw that exception. This declaration is consistent with the rule
151 * that |::operator new() throw(std::bad_alloc)| will never return NULL.
152 */
153
154 /* NB: This is defined just to silence vacuous warnings about symbol
155 * visibility on OS X/gcc. These symbols are force-inline and not
156 * exported. */
157 #if defined(XP_MACOSX)
158 # define MOZALLOC_EXPORT_NEW MFBT_API
159 #else
160 # define MOZALLOC_EXPORT_NEW
161 #endif
162
163 #if defined(ANDROID)
164 /*
165 * It's important to always specify 'throw()' in GCC because it's used to tell
166 * GCC that 'new' may return null. That makes GCC null-check the result before
167 * potentially initializing the memory to zero.
168 * Also, the Android minimalistic headers don't include std::bad_alloc.
169 */
170 #define MOZALLOC_THROW_IF_HAS_EXCEPTIONS throw()
171 #define MOZALLOC_THROW_BAD_ALLOC_IF_HAS_EXCEPTIONS
172 #elif defined(_MSC_VER)
173 /*
174 * Suppress build warning spam (bug 578546).
175 */
176 #define MOZALLOC_THROW_IF_HAS_EXCEPTIONS
177 #define MOZALLOC_THROW_BAD_ALLOC_IF_HAS_EXCEPTIONS
178 #else
179 #define MOZALLOC_THROW_IF_HAS_EXCEPTIONS throw()
180 #define MOZALLOC_THROW_BAD_ALLOC_IF_HAS_EXCEPTIONS throw(std::bad_alloc)
181 #endif
182
183 #define MOZALLOC_THROW_BAD_ALLOC MOZALLOC_THROW_BAD_ALLOC_IF_HAS_EXCEPTIONS
184
185 MOZALLOC_EXPORT_NEW
186 #if defined(__GNUC__) && !defined(__clang__) && defined(__SANITIZE_ADDRESS__)
187 /* gcc's asan somehow doesn't like always_inline on this function. */
188 __attribute__((gnu_inline)) inline
189 #else
190 MOZALLOC_INLINE
191 #endif
new(size_t size)192 void* operator new(size_t size) MOZALLOC_THROW_BAD_ALLOC
193 {
194 return moz_xmalloc(size);
195 }
196
197 MOZALLOC_EXPORT_NEW MOZALLOC_INLINE
new(size_t size,const std::nothrow_t &)198 void* operator new(size_t size, const std::nothrow_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS
199 {
200 return malloc_impl(size);
201 }
202
203 MOZALLOC_EXPORT_NEW MOZALLOC_INLINE
204 void* operator new[](size_t size) MOZALLOC_THROW_BAD_ALLOC
205 {
206 return moz_xmalloc(size);
207 }
208
209 MOZALLOC_EXPORT_NEW MOZALLOC_INLINE
210 void* operator new[](size_t size, const std::nothrow_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS
211 {
212 return malloc_impl(size);
213 }
214
215 MOZALLOC_EXPORT_NEW MOZALLOC_INLINE
delete(void * ptr)216 void operator delete(void* ptr) MOZALLOC_THROW_IF_HAS_EXCEPTIONS
217 {
218 return free_impl(ptr);
219 }
220
221 MOZALLOC_EXPORT_NEW MOZALLOC_INLINE
delete(void * ptr,const std::nothrow_t &)222 void operator delete(void* ptr, const std::nothrow_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS
223 {
224 return free_impl(ptr);
225 }
226
227 MOZALLOC_EXPORT_NEW MOZALLOC_INLINE
228 void operator delete[](void* ptr) MOZALLOC_THROW_IF_HAS_EXCEPTIONS
229 {
230 return free_impl(ptr);
231 }
232
233 MOZALLOC_EXPORT_NEW MOZALLOC_INLINE
234 void operator delete[](void* ptr, const std::nothrow_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS
235 {
236 return free_impl(ptr);
237 }
238
239
240 /*
241 * We also add a new allocator variant: "fallible operator new."
242 * Unlike libmozalloc's implementations of the standard nofail
243 * allocators, this allocator is allowed to return NULL. It can be used
244 * as follows
245 *
246 * Foo* f = new (mozilla::fallible) Foo(...);
247 *
248 * operator delete(fallible) is defined for completeness only.
249 *
250 * Each operator new below returns a pointer to memory that can be
251 * delete'd by any of
252 *
253 * (1) the matching "fallible" operator delete below
254 * (2) the matching infallible operator delete above
255 * (3) the matching system |operator delete(void*, std::nothrow)|
256 * (4) the matching system |operator delete(void*) throw(std::bad_alloc)|
257 */
258
259 MOZALLOC_INLINE
new(size_t size,const mozilla::fallible_t &)260 void* operator new(size_t size, const mozilla::fallible_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS
261 {
262 return malloc_impl(size);
263 }
264
265 MOZALLOC_INLINE
266 void* operator new[](size_t size, const mozilla::fallible_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS
267 {
268 return malloc_impl(size);
269 }
270
271 MOZALLOC_INLINE
delete(void * ptr,const mozilla::fallible_t &)272 void operator delete(void* ptr, const mozilla::fallible_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS
273 {
274 free_impl(ptr);
275 }
276
277 MOZALLOC_INLINE
278 void operator delete[](void* ptr, const mozilla::fallible_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS
279 {
280 free_impl(ptr);
281 }
282
283
284 /*
285 * This policy is identical to MallocAllocPolicy, except it uses
286 * moz_xmalloc/moz_xcalloc/moz_xrealloc instead of
287 * malloc/calloc/realloc.
288 */
289 class InfallibleAllocPolicy
290 {
291 public:
292 template <typename T>
maybe_pod_malloc(size_t aNumElems)293 T* maybe_pod_malloc(size_t aNumElems)
294 {
295 return pod_malloc<T>(aNumElems);
296 }
297
298 template <typename T>
maybe_pod_calloc(size_t aNumElems)299 T* maybe_pod_calloc(size_t aNumElems)
300 {
301 return pod_calloc<T>(aNumElems);
302 }
303
304 template <typename T>
maybe_pod_realloc(T * aPtr,size_t aOldSize,size_t aNewSize)305 T* maybe_pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize)
306 {
307 return pod_realloc<T>(aPtr, aOldSize, aNewSize);
308 }
309
310 template <typename T>
pod_malloc(size_t aNumElems)311 T* pod_malloc(size_t aNumElems)
312 {
313 if (aNumElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value) {
314 reportAllocOverflow();
315 }
316 return static_cast<T*>(moz_xmalloc(aNumElems * sizeof(T)));
317 }
318
319 template <typename T>
pod_calloc(size_t aNumElems)320 T* pod_calloc(size_t aNumElems)
321 {
322 return static_cast<T*>(moz_xcalloc(aNumElems, sizeof(T)));
323 }
324
325 template <typename T>
pod_realloc(T * aPtr,size_t aOldSize,size_t aNewSize)326 T* pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize)
327 {
328 if (aNewSize & mozilla::tl::MulOverflowMask<sizeof(T)>::value) {
329 reportAllocOverflow();
330 }
331 return static_cast<T*>(moz_xrealloc(aPtr, aNewSize * sizeof(T)));
332 }
333
free_(void * aPtr)334 void free_(void* aPtr)
335 {
336 free_impl(aPtr);
337 }
338
reportAllocOverflow()339 void reportAllocOverflow() const
340 {
341 mozalloc_abort("alloc overflow");
342 }
343
checkSimulatedOOM()344 bool checkSimulatedOOM() const
345 {
346 return true;
347 }
348 };
349
350 #endif /* ifdef __cplusplus */
351
352 #ifdef malloc_impl_
353 #undef malloc_impl_
354 #undef malloc_impl
355 #endif
356 #ifdef free_impl_
357 #undef free_impl_
358 #undef free_impl
359 #endif
360
361 #endif /* ifndef mozilla_mozalloc_h */
362