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