Line data Source code
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
192 : void* operator new(size_t size) MOZALLOC_THROW_BAD_ALLOC
193 : {
194 177095 : return moz_xmalloc(size);
195 : }
196 :
197 : MOZALLOC_EXPORT_NEW MOZALLOC_INLINE
198 : void* operator new(size_t size, const std::nothrow_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS
199 : {
200 168 : 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 8109 : 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 0 : return malloc_impl(size);
213 : }
214 :
215 : MOZALLOC_EXPORT_NEW MOZALLOC_INLINE
216 : void operator delete(void* ptr) MOZALLOC_THROW_IF_HAS_EXCEPTIONS
217 : {
218 50846 : return free_impl(ptr);
219 : }
220 :
221 : MOZALLOC_EXPORT_NEW MOZALLOC_INLINE
222 : void operator delete(void* ptr, const std::nothrow_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS
223 : {
224 1243 : 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 5280 : 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
260 : void* operator new(size_t size, const mozilla::fallible_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS
261 : {
262 4 : 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 1550 : return malloc_impl(size);
269 : }
270 :
271 : MOZALLOC_INLINE
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 644 : class InfallibleAllocPolicy
290 : {
291 : public:
292 : template <typename T>
293 : T* maybe_pod_malloc(size_t aNumElems)
294 : {
295 : return pod_malloc<T>(aNumElems);
296 : }
297 :
298 : template <typename T>
299 92 : T* maybe_pod_calloc(size_t aNumElems)
300 : {
301 92 : return pod_calloc<T>(aNumElems);
302 : }
303 :
304 : template <typename T>
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>
311 2461 : T* pod_malloc(size_t aNumElems)
312 : {
313 387 : if (aNumElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value) {
314 0 : reportAllocOverflow();
315 : }
316 2461 : return static_cast<T*>(moz_xmalloc(aNumElems * sizeof(T)));
317 : }
318 :
319 : template <typename T>
320 397 : T* pod_calloc(size_t aNumElems)
321 : {
322 397 : return static_cast<T*>(moz_xcalloc(aNumElems, sizeof(T)));
323 : }
324 :
325 : template <typename T>
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 :
334 2425 : void free_(void* aPtr)
335 : {
336 2425 : free_impl(aPtr);
337 2425 : }
338 :
339 0 : void reportAllocOverflow() const
340 : {
341 0 : mozalloc_abort("alloc overflow");
342 : }
343 :
344 1609 : bool checkSimulatedOOM() const
345 : {
346 1609 : 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 */
|