summaryrefslogtreecommitdiffstats
path: root/memory/mozalloc
diff options
context:
space:
mode:
Diffstat (limited to 'memory/mozalloc')
-rw-r--r--memory/mozalloc/moz.build57
-rw-r--r--memory/mozalloc/mozalloc.cpp221
-rw-r--r--memory/mozalloc/mozalloc.h361
-rw-r--r--memory/mozalloc/mozalloc_abort.cpp89
-rw-r--r--memory/mozalloc/mozalloc_abort.h28
-rw-r--r--memory/mozalloc/mozalloc_oom.cpp53
-rw-r--r--memory/mozalloc/mozalloc_oom.h31
-rw-r--r--memory/mozalloc/msvc_raise_wrappers.cpp63
-rw-r--r--memory/mozalloc/msvc_raise_wrappers.h41
-rw-r--r--memory/mozalloc/staticruntime/moz.build35
-rw-r--r--memory/mozalloc/throw_gcc.h145
-rw-r--r--memory/mozalloc/throw_msvc.h17
-rw-r--r--memory/mozalloc/winheap.cpp74
13 files changed, 1215 insertions, 0 deletions
diff --git a/memory/mozalloc/moz.build b/memory/mozalloc/moz.build
new file mode 100644
index 000000000..56d4b8d80
--- /dev/null
+++ b/memory/mozalloc/moz.build
@@ -0,0 +1,57 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+NO_VISIBILITY_FLAGS = True
+
+EXPORTS.mozilla += [
+ 'mozalloc.h',
+ 'mozalloc_abort.h',
+ 'mozalloc_oom.h',
+]
+
+if CONFIG['WRAP_STL_INCLUDES']:
+ if CONFIG['GNU_CXX']:
+ EXPORTS.mozilla += ['throw_gcc.h']
+ elif CONFIG['_MSC_VER']:
+ DEFINES['_HAS_EXCEPTIONS'] = 0
+ if CONFIG['MOZ_MSVC_STL_WRAP_RAISE']:
+ EXPORTS.mozilla += [
+ 'msvc_raise_wrappers.h',
+ 'throw_msvc.h',
+ ]
+ SOURCES += [
+ 'msvc_raise_wrappers.cpp',
+ ]
+
+if CONFIG['OS_TARGET'] == 'WINNT':
+ # Keep this file separate to avoid #include'ing windows.h everywhere.
+ SOURCES += [
+ 'winheap.cpp',
+ ]
+
+UNIFIED_SOURCES += [
+ 'mozalloc.cpp',
+ 'mozalloc_abort.cpp',
+ 'mozalloc_oom.cpp',
+]
+
+FINAL_LIBRARY = 'mozglue'
+
+# The strndup declaration in string.h is in an ifdef __USE_GNU section
+DEFINES['_GNU_SOURCE'] = True
+
+DISABLE_STL_WRAPPING = True
+
+DEFINES['IMPL_MFBT'] = True
+
+if CONFIG['_MSC_VER']:
+ DIRS += ['staticruntime']
+
+LOCAL_INCLUDES += [
+ '!/xpcom',
+ '/memory/build',
+]
+
+DIST_INSTALL = True
diff --git a/memory/mozalloc/mozalloc.cpp b/memory/mozalloc/mozalloc.cpp
new file mode 100644
index 000000000..55d36d80b
--- /dev/null
+++ b/memory/mozalloc/mozalloc.cpp
@@ -0,0 +1,221 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: sw=4 ts=4 et :
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <stddef.h> // for size_t
+
+// Building with USE_STATIC_LIBS = True sets -MT instead of -MD. -MT sets _MT,
+// while -MD sets _MT and _DLL.
+#if defined(_MT) && !defined(_DLL)
+#define MOZ_STATIC_RUNTIME
+#endif
+
+#if defined(MOZ_MEMORY) && !defined(MOZ_STATIC_RUNTIME)
+// mozalloc.cpp is part of the same library as mozmemory, thus MOZ_MEMORY_IMPL
+// is needed.
+#define MOZ_MEMORY_IMPL
+#include "mozmemory_wrap.h"
+
+#if defined(XP_DARWIN)
+#include <malloc/malloc.h> // for malloc_size
+#endif
+
+// See mozmemory_wrap.h for more details. This file is part of libmozglue, so
+// it needs to use _impl suffixes. However, with libmozglue growing, this is
+// becoming cumbersome, so we will likely use a malloc.h wrapper of some sort
+// and allow the use of the functions without a _impl suffix.
+#define MALLOC_DECL(name, return_type, ...) \
+ extern "C" MOZ_MEMORY_API return_type name ## _impl(__VA_ARGS__);
+#define MALLOC_FUNCS MALLOC_FUNCS_MALLOC
+#include "malloc_decls.h"
+
+extern "C" MOZ_MEMORY_API char *strdup_impl(const char *);
+extern "C" MOZ_MEMORY_API char *strndup_impl(const char *, size_t);
+
+#else
+// When jemalloc is disabled, or when building the static runtime variant,
+// we need not to use the suffixes.
+
+#if defined(MALLOC_H)
+# include MALLOC_H // for memalign, valloc, malloc_size, malloc_us
+#endif // if defined(MALLOC_H)
+#include <stdlib.h> // for malloc, free
+#if defined(XP_UNIX)
+# include <unistd.h> // for valloc on *BSD
+#endif //if defined(XP_UNIX)
+
+#define malloc_impl malloc
+#define posix_memalign_impl posix_memalign
+#define calloc_impl calloc
+#define realloc_impl realloc
+#define free_impl free
+#define memalign_impl memalign
+#define valloc_impl valloc
+#define malloc_usable_size_impl malloc_usable_size
+#define strdup_impl strdup
+#define strndup_impl strndup
+
+#endif
+
+#include <errno.h>
+#include <new> // for std::bad_alloc
+#include <string.h>
+
+#include <sys/types.h>
+
+#include "mozilla/mozalloc.h"
+#include "mozilla/mozalloc_oom.h" // for mozalloc_handle_oom
+
+#ifdef __GNUC__
+#define LIKELY(x) (__builtin_expect(!!(x), 1))
+#define UNLIKELY(x) (__builtin_expect(!!(x), 0))
+#else
+#define LIKELY(x) (x)
+#define UNLIKELY(x) (x)
+#endif
+
+void*
+moz_xmalloc(size_t size)
+{
+ void* ptr = malloc_impl(size);
+ if (UNLIKELY(!ptr && size)) {
+ mozalloc_handle_oom(size);
+ return moz_xmalloc(size);
+ }
+ return ptr;
+}
+
+void*
+moz_xcalloc(size_t nmemb, size_t size)
+{
+ void* ptr = calloc_impl(nmemb, size);
+ if (UNLIKELY(!ptr && nmemb && size)) {
+ mozalloc_handle_oom(size);
+ return moz_xcalloc(nmemb, size);
+ }
+ return ptr;
+}
+
+void*
+moz_xrealloc(void* ptr, size_t size)
+{
+ void* newptr = realloc_impl(ptr, size);
+ if (UNLIKELY(!newptr && size)) {
+ mozalloc_handle_oom(size);
+ return moz_xrealloc(ptr, size);
+ }
+ return newptr;
+}
+
+char*
+moz_xstrdup(const char* str)
+{
+ char* dup = strdup_impl(str);
+ if (UNLIKELY(!dup)) {
+ mozalloc_handle_oom(0);
+ return moz_xstrdup(str);
+ }
+ return dup;
+}
+
+#if defined(HAVE_STRNDUP)
+char*
+moz_xstrndup(const char* str, size_t strsize)
+{
+ char* dup = strndup_impl(str, strsize);
+ if (UNLIKELY(!dup)) {
+ mozalloc_handle_oom(strsize);
+ return moz_xstrndup(str, strsize);
+ }
+ return dup;
+}
+#endif // if defined(HAVE_STRNDUP)
+
+#if defined(HAVE_POSIX_MEMALIGN)
+int
+moz_xposix_memalign(void **ptr, size_t alignment, size_t size)
+{
+ int err = posix_memalign_impl(ptr, alignment, size);
+ if (UNLIKELY(err && ENOMEM == err)) {
+ mozalloc_handle_oom(size);
+ return moz_xposix_memalign(ptr, alignment, size);
+ }
+ // else: (0 == err) or (EINVAL == err)
+ return err;
+}
+int
+moz_posix_memalign(void **ptr, size_t alignment, size_t size)
+{
+ int code = posix_memalign_impl(ptr, alignment, size);
+ if (code)
+ return code;
+
+#if defined(XP_DARWIN)
+ // Workaround faulty OSX posix_memalign, which provides memory with the
+ // incorrect alignment sometimes, but returns 0 as if nothing was wrong.
+ size_t mask = alignment - 1;
+ if (((size_t)(*ptr) & mask) != 0) {
+ void* old = *ptr;
+ code = moz_posix_memalign(ptr, alignment, size);
+ free(old);
+ }
+#endif
+
+ return code;
+
+}
+#endif // if defined(HAVE_POSIX_MEMALIGN)
+
+#if defined(HAVE_MEMALIGN)
+void*
+moz_xmemalign(size_t boundary, size_t size)
+{
+ void* ptr = memalign_impl(boundary, size);
+ if (UNLIKELY(!ptr && EINVAL != errno)) {
+ mozalloc_handle_oom(size);
+ return moz_xmemalign(boundary, size);
+ }
+ // non-NULL ptr or errno == EINVAL
+ return ptr;
+}
+#endif // if defined(HAVE_MEMALIGN)
+
+#if defined(HAVE_VALLOC)
+void*
+moz_xvalloc(size_t size)
+{
+ void* ptr = valloc_impl(size);
+ if (UNLIKELY(!ptr)) {
+ mozalloc_handle_oom(size);
+ return moz_xvalloc(size);
+ }
+ return ptr;
+}
+#endif // if defined(HAVE_VALLOC)
+
+#ifndef MOZ_STATIC_RUNTIME
+size_t
+moz_malloc_usable_size(void *ptr)
+{
+ if (!ptr)
+ return 0;
+
+#if defined(XP_DARWIN)
+ return malloc_size(ptr);
+#elif defined(HAVE_MALLOC_USABLE_SIZE) || defined(MOZ_MEMORY)
+ return malloc_usable_size_impl(ptr);
+#elif defined(XP_WIN)
+ return _msize(ptr);
+#else
+ return 0;
+#endif
+}
+
+size_t moz_malloc_size_of(const void *ptr)
+{
+ return moz_malloc_usable_size((void *)ptr);
+}
+#endif
diff --git a/memory/mozalloc/mozalloc.h b/memory/mozalloc/mozalloc.h
new file mode 100644
index 000000000..f7ddb7e6d
--- /dev/null
+++ b/memory/mozalloc/mozalloc.h
@@ -0,0 +1,361 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: sw=4 ts=4 et :
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_mozalloc_h
+#define mozilla_mozalloc_h
+
+/*
+ * https://bugzilla.mozilla.org/show_bug.cgi?id=427099
+ */
+
+#if defined(__cplusplus)
+# include <new>
+// Since libstdc++ 6, including the C headers (e.g. stdlib.h) instead of the
+// corresponding C++ header (e.g. cstdlib) can cause confusion in C++ code
+// using things defined there. Specifically, with stdlib.h, the use of abs()
+// in gfx/graphite2/src/inc/UtfCodec.h somehow ends up picking the wrong abs()
+# include <cstdlib>
+# include <cstring>
+#else
+# include <stdlib.h>
+# include <string.h>
+#endif
+
+#if defined(__cplusplus)
+#include "mozilla/fallible.h"
+#include "mozilla/mozalloc_abort.h"
+#include "mozilla/TemplateLib.h"
+#endif
+#include "mozilla/Attributes.h"
+#include "mozilla/Types.h"
+
+#define MOZALLOC_HAVE_XMALLOC
+
+#if defined(MOZ_ALWAYS_INLINE_EVEN_DEBUG)
+# define MOZALLOC_INLINE MOZ_ALWAYS_INLINE_EVEN_DEBUG
+#elif defined(HAVE_FORCEINLINE)
+# define MOZALLOC_INLINE __forceinline
+#else
+# define MOZALLOC_INLINE inline
+#endif
+
+/* Workaround build problem with Sun Studio 12 */
+#if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+# undef MOZ_MUST_USE
+# define MOZ_MUST_USE
+# undef MOZ_ALLOCATOR
+# define MOZ_ALLOCATOR
+#endif
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /* ifdef __cplusplus */
+
+/*
+ * We need to use malloc_impl and free_impl in this file when they are
+ * defined, because of how mozglue.dll is linked on Windows, where using
+ * malloc/free would end up using the symbols from the MSVCRT instead of
+ * ours.
+ */
+#ifndef free_impl
+#define free_impl free
+#define free_impl_
+#endif
+#ifndef malloc_impl
+#define malloc_impl malloc
+#define malloc_impl_
+#endif
+
+/*
+ * Each declaration below is analogous to a "standard" allocation
+ * function, except that the out-of-memory handling is made explicit.
+ * The |moz_x| versions will never return a NULL pointer; if memory
+ * is exhausted, they abort. The |moz_| versions may return NULL
+ * pointers if memory is exhausted: their return value must be checked.
+ *
+ * All these allocation functions are *guaranteed* to return a pointer
+ * to memory allocated in such a way that that memory can be freed by
+ * passing that pointer to |free()|.
+ */
+
+MFBT_API void* moz_xmalloc(size_t size)
+ MOZ_ALLOCATOR;
+
+MFBT_API void* moz_xcalloc(size_t nmemb, size_t size)
+ MOZ_ALLOCATOR;
+
+MFBT_API void* moz_xrealloc(void* ptr, size_t size)
+ MOZ_ALLOCATOR;
+
+MFBT_API char* moz_xstrdup(const char* str)
+ MOZ_ALLOCATOR;
+
+MFBT_API size_t moz_malloc_usable_size(void *ptr);
+
+MFBT_API size_t moz_malloc_size_of(const void *ptr);
+
+#if defined(HAVE_STRNDUP)
+MFBT_API char* moz_xstrndup(const char* str, size_t strsize)
+ MOZ_ALLOCATOR;
+#endif /* if defined(HAVE_STRNDUP) */
+
+
+#if defined(HAVE_POSIX_MEMALIGN)
+MFBT_API MOZ_MUST_USE
+int moz_xposix_memalign(void **ptr, size_t alignment, size_t size);
+
+MFBT_API MOZ_MUST_USE
+int moz_posix_memalign(void **ptr, size_t alignment, size_t size);
+#endif /* if defined(HAVE_POSIX_MEMALIGN) */
+
+
+#if defined(HAVE_MEMALIGN)
+MFBT_API void* moz_xmemalign(size_t boundary, size_t size)
+ MOZ_ALLOCATOR;
+#endif /* if defined(HAVE_MEMALIGN) */
+
+
+#if defined(HAVE_VALLOC)
+MFBT_API void* moz_xvalloc(size_t size)
+ MOZ_ALLOCATOR;
+#endif /* if defined(HAVE_VALLOC) */
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* ifdef __cplusplus */
+
+
+#ifdef __cplusplus
+
+/*
+ * We implement the default operators new/delete as part of
+ * libmozalloc, replacing their definitions in libstdc++. The
+ * operator new* definitions in libmozalloc will never return a NULL
+ * pointer.
+ *
+ * Each operator new immediately below returns a pointer to memory
+ * that can be delete'd by any of
+ *
+ * (1) the matching infallible operator delete immediately below
+ * (2) the matching "fallible" operator delete further below
+ * (3) the matching system |operator delete(void*, std::nothrow)|
+ * (4) the matching system |operator delete(void*) throw(std::bad_alloc)|
+ *
+ * NB: these are declared |throw(std::bad_alloc)|, though they will never
+ * throw that exception. This declaration is consistent with the rule
+ * that |::operator new() throw(std::bad_alloc)| will never return NULL.
+ */
+
+/* NB: This is defined just to silence vacuous warnings about symbol
+ * visibility on OS X/gcc. These symbols are force-inline and not
+ * exported. */
+#if defined(XP_MACOSX)
+# define MOZALLOC_EXPORT_NEW MFBT_API
+#else
+# define MOZALLOC_EXPORT_NEW
+#endif
+
+#if defined(ANDROID)
+/*
+ * It's important to always specify 'throw()' in GCC because it's used to tell
+ * GCC that 'new' may return null. That makes GCC null-check the result before
+ * potentially initializing the memory to zero.
+ * Also, the Android minimalistic headers don't include std::bad_alloc.
+ */
+#define MOZALLOC_THROW_IF_HAS_EXCEPTIONS throw()
+#define MOZALLOC_THROW_BAD_ALLOC_IF_HAS_EXCEPTIONS
+#elif defined(_MSC_VER)
+/*
+ * Suppress build warning spam (bug 578546).
+ */
+#define MOZALLOC_THROW_IF_HAS_EXCEPTIONS
+#define MOZALLOC_THROW_BAD_ALLOC_IF_HAS_EXCEPTIONS
+#else
+#define MOZALLOC_THROW_IF_HAS_EXCEPTIONS throw()
+#define MOZALLOC_THROW_BAD_ALLOC_IF_HAS_EXCEPTIONS throw(std::bad_alloc)
+#endif
+
+#define MOZALLOC_THROW_BAD_ALLOC MOZALLOC_THROW_BAD_ALLOC_IF_HAS_EXCEPTIONS
+
+MOZALLOC_EXPORT_NEW
+#if defined(__GNUC__) && !defined(__clang__) && defined(__SANITIZE_ADDRESS__)
+/* gcc's asan somehow doesn't like always_inline on this function. */
+__attribute__((gnu_inline)) inline
+#else
+MOZALLOC_INLINE
+#endif
+void* operator new(size_t size) MOZALLOC_THROW_BAD_ALLOC
+{
+ return moz_xmalloc(size);
+}
+
+MOZALLOC_EXPORT_NEW MOZALLOC_INLINE
+void* operator new(size_t size, const std::nothrow_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS
+{
+ return malloc_impl(size);
+}
+
+MOZALLOC_EXPORT_NEW MOZALLOC_INLINE
+void* operator new[](size_t size) MOZALLOC_THROW_BAD_ALLOC
+{
+ return moz_xmalloc(size);
+}
+
+MOZALLOC_EXPORT_NEW MOZALLOC_INLINE
+void* operator new[](size_t size, const std::nothrow_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS
+{
+ return malloc_impl(size);
+}
+
+MOZALLOC_EXPORT_NEW MOZALLOC_INLINE
+void operator delete(void* ptr) MOZALLOC_THROW_IF_HAS_EXCEPTIONS
+{
+ return free_impl(ptr);
+}
+
+MOZALLOC_EXPORT_NEW MOZALLOC_INLINE
+void operator delete(void* ptr, const std::nothrow_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS
+{
+ return free_impl(ptr);
+}
+
+MOZALLOC_EXPORT_NEW MOZALLOC_INLINE
+void operator delete[](void* ptr) MOZALLOC_THROW_IF_HAS_EXCEPTIONS
+{
+ return free_impl(ptr);
+}
+
+MOZALLOC_EXPORT_NEW MOZALLOC_INLINE
+void operator delete[](void* ptr, const std::nothrow_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS
+{
+ return free_impl(ptr);
+}
+
+
+/*
+ * We also add a new allocator variant: "fallible operator new."
+ * Unlike libmozalloc's implementations of the standard nofail
+ * allocators, this allocator is allowed to return NULL. It can be used
+ * as follows
+ *
+ * Foo* f = new (mozilla::fallible) Foo(...);
+ *
+ * operator delete(fallible) is defined for completeness only.
+ *
+ * Each operator new below returns a pointer to memory that can be
+ * delete'd by any of
+ *
+ * (1) the matching "fallible" operator delete below
+ * (2) the matching infallible operator delete above
+ * (3) the matching system |operator delete(void*, std::nothrow)|
+ * (4) the matching system |operator delete(void*) throw(std::bad_alloc)|
+ */
+
+MOZALLOC_INLINE
+void* operator new(size_t size, const mozilla::fallible_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS
+{
+ return malloc_impl(size);
+}
+
+MOZALLOC_INLINE
+void* operator new[](size_t size, const mozilla::fallible_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS
+{
+ return malloc_impl(size);
+}
+
+MOZALLOC_INLINE
+void operator delete(void* ptr, const mozilla::fallible_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS
+{
+ free_impl(ptr);
+}
+
+MOZALLOC_INLINE
+void operator delete[](void* ptr, const mozilla::fallible_t&) MOZALLOC_THROW_IF_HAS_EXCEPTIONS
+{
+ free_impl(ptr);
+}
+
+
+/*
+ * This policy is identical to MallocAllocPolicy, except it uses
+ * moz_xmalloc/moz_xcalloc/moz_xrealloc instead of
+ * malloc/calloc/realloc.
+ */
+class InfallibleAllocPolicy
+{
+public:
+ template <typename T>
+ T* maybe_pod_malloc(size_t aNumElems)
+ {
+ return pod_malloc<T>(aNumElems);
+ }
+
+ template <typename T>
+ T* maybe_pod_calloc(size_t aNumElems)
+ {
+ return pod_calloc<T>(aNumElems);
+ }
+
+ template <typename T>
+ T* maybe_pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize)
+ {
+ return pod_realloc<T>(aPtr, aOldSize, aNewSize);
+ }
+
+ template <typename T>
+ T* pod_malloc(size_t aNumElems)
+ {
+ if (aNumElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value) {
+ reportAllocOverflow();
+ }
+ return static_cast<T*>(moz_xmalloc(aNumElems * sizeof(T)));
+ }
+
+ template <typename T>
+ T* pod_calloc(size_t aNumElems)
+ {
+ return static_cast<T*>(moz_xcalloc(aNumElems, sizeof(T)));
+ }
+
+ template <typename T>
+ T* pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize)
+ {
+ if (aNewSize & mozilla::tl::MulOverflowMask<sizeof(T)>::value) {
+ reportAllocOverflow();
+ }
+ return static_cast<T*>(moz_xrealloc(aPtr, aNewSize * sizeof(T)));
+ }
+
+ void free_(void* aPtr)
+ {
+ free_impl(aPtr);
+ }
+
+ void reportAllocOverflow() const
+ {
+ mozalloc_abort("alloc overflow");
+ }
+
+ bool checkSimulatedOOM() const
+ {
+ return true;
+ }
+};
+
+#endif /* ifdef __cplusplus */
+
+#ifdef malloc_impl_
+#undef malloc_impl_
+#undef malloc_impl
+#endif
+#ifdef free_impl_
+#undef free_impl_
+#undef free_impl
+#endif
+
+#endif /* ifndef mozilla_mozalloc_h */
diff --git a/memory/mozalloc/mozalloc_abort.cpp b/memory/mozalloc/mozalloc_abort.cpp
new file mode 100644
index 000000000..a998d8164
--- /dev/null
+++ b/memory/mozalloc/mozalloc_abort.cpp
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: sw=4 ts=4 et :
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/mozalloc_abort.h"
+
+#ifdef ANDROID
+# include <android/log.h>
+#endif
+#ifdef MOZ_WIDGET_ANDROID
+# include "APKOpen.h"
+# include "dlfcn.h"
+#endif
+#include <stdio.h>
+
+#include "mozilla/Assertions.h"
+
+void
+mozalloc_abort(const char* const msg)
+{
+#ifndef ANDROID
+ fputs(msg, stderr);
+ fputs("\n", stderr);
+#else
+ __android_log_print(ANDROID_LOG_ERROR, "Gecko", "mozalloc_abort: %s", msg);
+#endif
+#ifdef MOZ_WIDGET_ANDROID
+ abortThroughJava(msg);
+#endif
+ MOZ_CRASH();
+}
+
+#ifdef MOZ_WIDGET_ANDROID
+template <size_t N>
+void fillAbortMessage(char (&msg)[N], uintptr_t retAddress) {
+ /*
+ * On Android, we often don't have reliable backtrace when crashing inside
+ * abort(). Therefore, we try to find out who is calling abort() and add
+ * that to the message.
+ */
+ Dl_info info = {};
+ dladdr(reinterpret_cast<void*>(retAddress), &info);
+
+ const char* const module = info.dli_fname ? info.dli_fname : "";
+ const char* const base_module = strrchr(module, '/');
+ const void* const module_offset =
+ reinterpret_cast<void*>(retAddress - uintptr_t(info.dli_fbase));
+ const char* const sym = info.dli_sname ? info.dli_sname : "";
+
+ snprintf(msg, sizeof(msg), "abort() called from %s:%p (%s)",
+ base_module ? base_module + 1 : module, module_offset, sym);
+}
+#endif
+
+#if defined(XP_UNIX) && !defined(MOZ_ASAN)
+// Define abort() here, so that it is used instead of the system abort(). This
+// lets us control the behavior when aborting, in order to get better results
+// on *NIX platforms. See mozalloc_abort for details.
+//
+// For AddressSanitizer, we must not redefine system abort because the ASan
+// option "abort_on_error=1" calls abort() and therefore causes the following
+// call chain with our redefined abort:
+//
+// ASan -> abort() -> moz_abort() -> MOZ_CRASH() -> Segmentation fault
+//
+// That segmentation fault will be interpreted as another bug by ASan and as a
+// result, ASan will just exit(1) instead of aborting.
+void abort(void)
+{
+#ifdef MOZ_WIDGET_ANDROID
+ char msg[64] = {};
+ fillAbortMessage(msg, uintptr_t(__builtin_return_address(0)));
+#else
+ const char* const msg = "Redirecting call to abort() to mozalloc_abort\n";
+#endif
+
+ mozalloc_abort(msg);
+
+ // We won't reach here because mozalloc_abort() is MOZ_NORETURN. But that
+ // annotation isn't used on ARM (see mozalloc_abort.h for why) so we add a
+ // redundant MOZ_CRASH() here to avoid a "'noreturn' function does return"
+ // warning.
+ MOZ_CRASH();
+}
+#endif
+
diff --git a/memory/mozalloc/mozalloc_abort.h b/memory/mozalloc/mozalloc_abort.h
new file mode 100644
index 000000000..065cebcb3
--- /dev/null
+++ b/memory/mozalloc/mozalloc_abort.h
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: sw=4 ts=4 et :
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_mozalloc_abort_h
+#define mozilla_mozalloc_abort_h
+
+#include "mozilla/Attributes.h"
+#include "mozilla/Types.h"
+
+/**
+ * Terminate this process in such a way that breakpad is triggered, if
+ * at all possible.
+ *
+ * Note: MOZ_NORETURN seems to break crash stacks on ARM, so we don't
+ * use that annotation there.
+ */
+MFBT_API
+#if !defined(__arm__)
+ MOZ_NORETURN
+#endif
+ void mozalloc_abort(const char* const msg);
+
+
+#endif /* ifndef mozilla_mozalloc_abort_h */
diff --git a/memory/mozalloc/mozalloc_oom.cpp b/memory/mozalloc/mozalloc_oom.cpp
new file mode 100644
index 000000000..820888cdb
--- /dev/null
+++ b/memory/mozalloc/mozalloc_oom.cpp
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: sw=4 ts=4 et :
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/mozalloc_abort.h"
+#include "mozilla/mozalloc_oom.h"
+#include "mozilla/Assertions.h"
+
+static mozalloc_oom_abort_handler gAbortHandler;
+
+#define OOM_MSG_LEADER "out of memory: 0x"
+#define OOM_MSG_DIGITS "0000000000000000" // large enough for 2^64
+#define OOM_MSG_TRAILER " bytes requested"
+#define OOM_MSG_FIRST_DIGIT_OFFSET sizeof(OOM_MSG_LEADER) - 1
+#define OOM_MSG_LAST_DIGIT_OFFSET sizeof(OOM_MSG_LEADER) + \
+ sizeof(OOM_MSG_DIGITS) - 3
+
+static const char *hex = "0123456789ABCDEF";
+
+void
+mozalloc_handle_oom(size_t size)
+{
+ char oomMsg[] = OOM_MSG_LEADER OOM_MSG_DIGITS OOM_MSG_TRAILER;
+ size_t i;
+
+ // NB: this is handle_oom() stage 1, which simply aborts on OOM.
+ // we might proceed to a stage 2 in which an attempt is made to
+ // reclaim memory
+
+ if (gAbortHandler)
+ gAbortHandler(size);
+
+ static_assert(OOM_MSG_FIRST_DIGIT_OFFSET > 0,
+ "Loop below will never terminate (i can't go below 0)");
+
+ // Insert size into the diagnostic message using only primitive operations
+ for (i = OOM_MSG_LAST_DIGIT_OFFSET;
+ size && i >= OOM_MSG_FIRST_DIGIT_OFFSET; i--) {
+ oomMsg[i] = hex[size % 16];
+ size /= 16;
+ }
+
+ mozalloc_abort(oomMsg);
+}
+
+void
+mozalloc_set_oom_abort_handler(mozalloc_oom_abort_handler handler)
+{
+ gAbortHandler = handler;
+}
diff --git a/memory/mozalloc/mozalloc_oom.h b/memory/mozalloc/mozalloc_oom.h
new file mode 100644
index 000000000..35bb9acc8
--- /dev/null
+++ b/memory/mozalloc/mozalloc_oom.h
@@ -0,0 +1,31 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: sw=4 ts=4 et :
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_mozalloc_oom_h
+#define mozilla_mozalloc_oom_h
+
+#include "mozalloc.h"
+
+/**
+ * Called when memory is critically low. Returns iff it was able to
+ * remedy the critical memory situation; if not, it will abort().
+ */
+MFBT_API void mozalloc_handle_oom(size_t requestedSize);
+
+/**
+ * Called by embedders (specifically Mozilla breakpad) which wants to be
+ * notified of an intentional abort, to annotate any crash report with
+ * the size of the allocation on which we aborted.
+ */
+typedef void (*mozalloc_oom_abort_handler)(size_t size);
+MFBT_API void mozalloc_set_oom_abort_handler(mozalloc_oom_abort_handler handler);
+
+/* TODO: functions to query system memory usage and register
+ * critical-memory handlers. */
+
+
+#endif /* ifndef mozilla_mozalloc_oom_h */
diff --git a/memory/mozalloc/msvc_raise_wrappers.cpp b/memory/mozalloc/msvc_raise_wrappers.cpp
new file mode 100644
index 000000000..820663f63
--- /dev/null
+++ b/memory/mozalloc/msvc_raise_wrappers.cpp
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: sw=4 ts=4 et :
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <stdio.h>
+
+#include "mozalloc_abort.h"
+
+__declspec(noreturn) static void abort_from_exception(const char* const which,
+ const char* const what);
+static void
+abort_from_exception(const char* const which, const char* const what)
+{
+ fprintf(stderr, "fatal: STL threw %s: ", which);
+ mozalloc_abort(what);
+}
+
+namespace std {
+
+// NB: user code is not supposed to touch the std:: namespace. We're
+// doing this after careful review because we want to define our own
+// exception throwing semantics. Don't try this at home!
+
+MFBT_API __declspec(noreturn) void
+moz_Xinvalid_argument(const char* what)
+{
+ abort_from_exception("invalid_argument", what);
+}
+
+MFBT_API __declspec(noreturn) void
+moz_Xlength_error(const char* what)
+{
+ abort_from_exception("length_error", what);
+}
+
+MFBT_API __declspec(noreturn) void
+moz_Xout_of_range(const char* what)
+{
+ abort_from_exception("out_of_range", what);
+}
+
+MFBT_API __declspec(noreturn) void
+moz_Xoverflow_error(const char* what)
+{
+ abort_from_exception("overflow_error", what);
+}
+
+MFBT_API __declspec(noreturn) void
+moz_Xruntime_error(const char* what)
+{
+ abort_from_exception("runtime_error", what);
+}
+
+MFBT_API __declspec(noreturn) void
+moz_Xbad_function_call()
+{
+ abort_from_exception("bad_function_call", "bad function call");
+}
+
+} // namespace std
diff --git a/memory/mozalloc/msvc_raise_wrappers.h b/memory/mozalloc/msvc_raise_wrappers.h
new file mode 100644
index 000000000..91b77f453
--- /dev/null
+++ b/memory/mozalloc/msvc_raise_wrappers.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: sw=4 ts=4 et :
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_msvc_raise_wrappers_h
+#define mozilla_msvc_raise_wrappers_h
+
+#ifdef _XSTDDEF_
+# error "Unable to wrap _RAISE(); CRT _RAISE() already defined"
+#endif
+#ifdef _XUTILITY_
+# error "Unable to wrap _X[exception](); CRT versions already declared"
+#endif
+#ifdef _FUNCTIONAL_
+# error "Unable to wrap _Xbad_function_call(); CRT version already declared"
+#endif
+
+#include "mozilla/mozalloc_abort.h"
+
+// xutility will declare the following functions in the std namespace.
+// We #define them to be named differently so we can ensure the exception
+// throwing semantics of these functions work exactly the way we want, by
+// defining our own versions in msvc_raise_wrappers.cpp.
+# define _Xinvalid_argument moz_Xinvalid_argument
+# define _Xlength_error moz_Xlength_error
+# define _Xout_of_range moz_Xout_of_range
+# define _Xoverflow_error moz_Xoverflow_error
+# define _Xruntime_error moz_Xruntime_error
+// used by <functional>
+# define _Xbad_function_call moz_Xbad_function_call
+
+# include <xstddef>
+# include <xutility>
+
+# undef _RAISE
+# define _RAISE(x) mozalloc_abort((x).what())
+
+#endif // ifndef mozilla_msvc_raise_wrappers_h
diff --git a/memory/mozalloc/staticruntime/moz.build b/memory/mozalloc/staticruntime/moz.build
new file mode 100644
index 000000000..55c71907d
--- /dev/null
+++ b/memory/mozalloc/staticruntime/moz.build
@@ -0,0 +1,35 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+NO_VISIBILITY_FLAGS = True
+
+if CONFIG['WRAP_STL_INCLUDES']:
+ DEFINES['_HAS_EXCEPTIONS'] = 0
+ if CONFIG['MOZ_MSVC_STL_WRAP_RAISE']:
+ SOURCES += [
+ '../msvc_raise_wrappers.cpp',
+ ]
+
+UNIFIED_SOURCES += [
+ '../mozalloc.cpp',
+ '../mozalloc_abort.cpp',
+ '../mozalloc_oom.cpp',
+]
+
+# Keep this file separate to avoid #include'ing windows.h everywhere.
+SOURCES += [
+ '../winheap.cpp',
+]
+
+LOCAL_INCLUDES += ['!/xpcom']
+
+DISABLE_STL_WRAPPING = True
+
+DEFINES['IMPL_MFBT'] = True
+
+USE_STATIC_LIBS = True
+
+Library('mozalloc_staticruntime')
diff --git a/memory/mozalloc/throw_gcc.h b/memory/mozalloc/throw_gcc.h
new file mode 100644
index 000000000..4264df63d
--- /dev/null
+++ b/memory/mozalloc/throw_gcc.h
@@ -0,0 +1,145 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: sw=4 ts=4 et :
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_throw_gcc_h
+#define mozilla_throw_gcc_h
+
+#include "mozilla/Attributes.h"
+
+#include <stdio.h> // snprintf
+#include <string.h> // strerror
+
+// For gcc, we define these inline to abort so that we're absolutely
+// certain that (i) no exceptions are thrown from Gecko; (ii) these
+// errors are always terminal and caught by breakpad.
+
+#include "mozilla/mozalloc_abort.h"
+
+// libc++ 4.0.0 and higher use C++11 [[noreturn]] attributes for the functions
+// below, and since clang does not allow mixing __attribute__((noreturn)) and
+// [[noreturn]], we have to explicitly use the latter here. See bug 1329520.
+#if defined(__clang__)
+# if __has_feature(cxx_attributes) && \
+ defined(_LIBCPP_VERSION) && _LIBCPP_VERSION >= 4000
+# define MOZ_THROW_NORETURN [[noreturn]]
+# endif
+#endif
+#ifndef MOZ_THROW_NORETURN
+# define MOZ_THROW_NORETURN MOZ_NORETURN
+#endif
+
+namespace std {
+
+// NB: user code is not supposed to touch the std:: namespace. We're
+// doing this after careful review because we want to define our own
+// exception throwing semantics. Don't try this at home!
+
+MOZ_THROW_NORETURN MOZ_EXPORT MOZ_ALWAYS_INLINE void
+__throw_bad_exception(void)
+{
+ mozalloc_abort("fatal: STL threw bad_exception");
+}
+
+MOZ_THROW_NORETURN MOZ_EXPORT MOZ_ALWAYS_INLINE void
+__throw_bad_alloc(void)
+{
+ mozalloc_abort("fatal: STL threw bad_alloc");
+}
+
+MOZ_THROW_NORETURN MOZ_EXPORT MOZ_ALWAYS_INLINE void
+__throw_bad_cast(void)
+{
+ mozalloc_abort("fatal: STL threw bad_cast");
+}
+
+MOZ_THROW_NORETURN MOZ_EXPORT MOZ_ALWAYS_INLINE void
+__throw_bad_typeid(void)
+{
+ mozalloc_abort("fatal: STL threw bad_typeid");
+}
+
+// used by <functional>
+MOZ_THROW_NORETURN MOZ_EXPORT MOZ_ALWAYS_INLINE void
+__throw_bad_function_call(void)
+{
+ mozalloc_abort("fatal: STL threw bad_function_call");
+}
+
+MOZ_THROW_NORETURN MOZ_EXPORT MOZ_ALWAYS_INLINE void
+__throw_logic_error(const char* msg)
+{
+ mozalloc_abort(msg);
+}
+
+MOZ_THROW_NORETURN MOZ_EXPORT MOZ_ALWAYS_INLINE void
+__throw_domain_error(const char* msg)
+{
+ mozalloc_abort(msg);
+}
+
+MOZ_THROW_NORETURN MOZ_EXPORT MOZ_ALWAYS_INLINE void
+__throw_invalid_argument(const char* msg)
+{
+ mozalloc_abort(msg);
+}
+
+MOZ_THROW_NORETURN MOZ_EXPORT MOZ_ALWAYS_INLINE void
+__throw_length_error(const char* msg)
+{
+ mozalloc_abort(msg);
+}
+
+MOZ_THROW_NORETURN MOZ_EXPORT MOZ_ALWAYS_INLINE void
+__throw_out_of_range(const char* msg)
+{
+ mozalloc_abort(msg);
+}
+
+MOZ_THROW_NORETURN MOZ_EXPORT MOZ_ALWAYS_INLINE void
+__throw_runtime_error(const char* msg)
+{
+ mozalloc_abort(msg);
+}
+
+MOZ_THROW_NORETURN MOZ_EXPORT MOZ_ALWAYS_INLINE void
+__throw_range_error(const char* msg)
+{
+ mozalloc_abort(msg);
+}
+
+MOZ_THROW_NORETURN MOZ_EXPORT MOZ_ALWAYS_INLINE void
+__throw_overflow_error(const char* msg)
+{
+ mozalloc_abort(msg);
+}
+
+MOZ_THROW_NORETURN MOZ_EXPORT MOZ_ALWAYS_INLINE void
+__throw_underflow_error(const char* msg)
+{
+ mozalloc_abort(msg);
+}
+
+MOZ_THROW_NORETURN MOZ_EXPORT MOZ_ALWAYS_INLINE void
+__throw_ios_failure(const char* msg)
+{
+ mozalloc_abort(msg);
+}
+
+MOZ_THROW_NORETURN MOZ_EXPORT MOZ_ALWAYS_INLINE void
+__throw_system_error(int err)
+{
+ char error[128];
+ snprintf(error, sizeof(error)-1,
+ "fatal: STL threw system_error: %s (%d)", strerror(err), err);
+ mozalloc_abort(error);
+}
+
+} // namespace std
+
+#undef MOZ_THROW_NORETURN
+
+#endif // mozilla_throw_gcc_h
diff --git a/memory/mozalloc/throw_msvc.h b/memory/mozalloc/throw_msvc.h
new file mode 100644
index 000000000..e6ebf46dc
--- /dev/null
+++ b/memory/mozalloc/throw_msvc.h
@@ -0,0 +1,17 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: sw=4 ts=4 et :
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_throw_msvc_h
+#define mozilla_throw_msvc_h
+
+#if defined(MOZ_MSVC_STL_WRAP_RAISE)
+# include "msvc_raise_wrappers.h"
+#else
+# error "Unknown STL wrapper tactic"
+#endif
+
+#endif // mozilla_throw_msvc_h
diff --git a/memory/mozalloc/winheap.cpp b/memory/mozalloc/winheap.cpp
new file mode 100644
index 000000000..79ff35fff
--- /dev/null
+++ b/memory/mozalloc/winheap.cpp
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: sw=4 ts=4 et :
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/Types.h"
+#include <windows.h>
+
+// Building with USE_STATIC_LIBS = True sets -MT instead of -MD. -MT sets _MT,
+// while -MD sets _MT and _DLL.
+#if defined(_MT) && !defined(_DLL)
+#define MOZ_STATIC_RUNTIME
+#endif
+
+#if defined(MOZ_MEMORY) && !defined(MOZ_STATIC_RUNTIME)
+// mozalloc.cpp is part of the same library as mozmemory, thus MOZ_MEMORY_IMPL
+// is needed.
+#define MOZ_MEMORY_IMPL
+#include "mozmemory_wrap.h"
+
+// See mozmemory_wrap.h for more details. This file is part of libmozglue, so
+// it needs to use _impl suffixes. However, with libmozglue growing, this is
+// becoming cumbersome, so we will likely use a malloc.h wrapper of some sort
+// and allow the use of the functions without a _impl suffix.
+#define MALLOC_DECL(name, return_type, ...) \
+ extern "C" MOZ_MEMORY_API return_type name ## _impl(__VA_ARGS__);
+#define MALLOC_FUNCS MALLOC_FUNCS_MALLOC
+#include "malloc_decls.h"
+
+// Warning: C4273: 'HeapAlloc': inconsistent dll linkage
+// The Windows headers define HeapAlloc as dllimport, but we define it as
+// dllexport, which is a voluntary inconsistency.
+#pragma warning(disable: 4273)
+
+MFBT_API
+LPVOID WINAPI HeapAlloc(_In_ HANDLE hHeap, _In_ DWORD dwFlags,
+ _In_ SIZE_T dwBytes)
+{
+ if (dwFlags & HEAP_ZERO_MEMORY) {
+ return calloc_impl(1, dwBytes);
+ }
+ return malloc_impl(dwBytes);
+}
+
+MFBT_API
+LPVOID WINAPI HeapReAlloc(_In_ HANDLE hHeap, _In_ DWORD dwFlags,
+ _In_ LPVOID lpMem, _In_ SIZE_T dwBytes)
+{
+ // The HeapReAlloc contract is that failures preserve the existing
+ // allocation. We can't try to realloc in-place without possibly
+ // freeing the original allocation, breaking the contract.
+ // We also can't guarantee we zero all the memory from the end of
+ // the original allocation to the end of the new one because of the
+ // difference between the originally requested size and what
+ // malloc_usable_size would return us.
+ // So for both cases, just tell the caller we can't do what they
+ // requested.
+ if (dwFlags & (HEAP_REALLOC_IN_PLACE_ONLY | HEAP_ZERO_MEMORY)) {
+ return NULL;
+ }
+ return realloc_impl(lpMem, dwBytes);
+}
+
+MFBT_API
+BOOL WINAPI HeapFree(_In_ HANDLE hHeap, _In_ DWORD dwFlags,
+ _In_ LPVOID lpMem)
+{
+ free_impl(lpMem);
+ return true;
+}
+
+#endif