summaryrefslogtreecommitdiffstats
path: root/memory/mozalloc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /memory/mozalloc
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'memory/mozalloc')
-rw-r--r--memory/mozalloc/cxxalloc.cpp26
-rw-r--r--memory/mozalloc/cxxalloc.h82
-rw-r--r--memory/mozalloc/moz.build59
-rw-r--r--memory/mozalloc/mozalloc.cpp159
-rw-r--r--memory/mozalloc/mozalloc.h198
-rw-r--r--memory/mozalloc/mozalloc_abort.cpp96
-rw-r--r--memory/mozalloc/mozalloc_abort.h28
-rw-r--r--memory/mozalloc/mozalloc_oom.cpp52
-rw-r--r--memory/mozalloc/mozalloc_oom.h29
-rw-r--r--memory/mozalloc/msvc_raise_wrappers.cpp17
-rw-r--r--memory/mozalloc/throw_gcc.h152
-rw-r--r--memory/mozalloc/winheap.cpp55
12 files changed, 953 insertions, 0 deletions
diff --git a/memory/mozalloc/cxxalloc.cpp b/memory/mozalloc/cxxalloc.cpp
new file mode 100644
index 0000000000..41f419fe2d
--- /dev/null
+++ b/memory/mozalloc/cxxalloc.cpp
@@ -0,0 +1,26 @@
+/* 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/. */
+
+#define MOZ_MEMORY_IMPL
+#include "mozmemory_wrap.h"
+#define MALLOC_FUNCS MALLOC_FUNCS_MALLOC
+// See mozmemory_wrap.h for more details. Files that are part of libmozglue,
+// need to use _impl suffixes, which is becoming cumbersome. We'll have to use
+// something like a malloc.h wrapper and allow the use of the functions without
+// a _impl suffix. In the meanwhile, this is enough to get by for C++ code.
+#define MALLOC_DECL(name, return_type, ...) \
+ MOZ_MEMORY_API return_type name##_impl(__VA_ARGS__);
+#include "malloc_decls.h"
+
+#include "mozilla/Attributes.h"
+
+extern "C" MFBT_API void* moz_xmalloc(size_t size) MOZ_INFALLIBLE_ALLOCATOR;
+
+namespace std {
+struct nothrow_t;
+}
+
+#define MOZALLOC_EXPORT_NEW MFBT_API
+
+#include "mozilla/cxxalloc.h"
diff --git a/memory/mozalloc/cxxalloc.h b/memory/mozalloc/cxxalloc.h
new file mode 100644
index 0000000000..c6fb4bb1dc
--- /dev/null
+++ b/memory/mozalloc/cxxalloc.h
@@ -0,0 +1,82 @@
+/* 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_cxxalloc_h
+#define mozilla_cxxalloc_h
+
+/*
+ * 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 system |operator delete(void*, std::nothrow)|
+ * (3) the matching system |operator delete(void*) noexcept(false)|
+ *
+ * NB: these are declared |noexcept(false)|, though they will never
+ * throw that exception. This declaration is consistent with the rule
+ * that |::operator new() noexcept(false)| will never return NULL.
+ *
+ * NB: mozilla::fallible can be used instead of std::nothrow.
+ */
+
+#ifndef MOZALLOC_EXPORT_NEW
+# define MOZALLOC_EXPORT_NEW MFBT_API
+#endif
+
+MOZALLOC_EXPORT_NEW void* operator new(size_t size) noexcept(false) {
+ return moz_xmalloc(size);
+}
+
+MOZALLOC_EXPORT_NEW void* operator new(size_t size,
+ const std::nothrow_t&) noexcept(true) {
+ return malloc_impl(size);
+}
+
+MOZALLOC_EXPORT_NEW void* operator new[](size_t size) noexcept(false) {
+ return moz_xmalloc(size);
+}
+
+MOZALLOC_EXPORT_NEW void* operator new[](size_t size,
+ const std::nothrow_t&) noexcept(true) {
+ return malloc_impl(size);
+}
+
+MOZALLOC_EXPORT_NEW void operator delete(void* ptr) noexcept(true) {
+ return free_impl(ptr);
+}
+
+MOZALLOC_EXPORT_NEW void operator delete(void* ptr,
+ const std::nothrow_t&) noexcept(true) {
+ return free_impl(ptr);
+}
+
+MOZALLOC_EXPORT_NEW void operator delete[](void* ptr) noexcept(true) {
+ return free_impl(ptr);
+}
+
+MOZALLOC_EXPORT_NEW void operator delete[](
+ void* ptr, const std::nothrow_t&) noexcept(true) {
+ return free_impl(ptr);
+}
+
+#if defined(XP_WIN)
+// We provide the global sized delete overloads unconditionally because the
+// MSVC runtime headers do, despite compiling with /Zc:sizedDealloc-
+MOZALLOC_EXPORT_NEW void operator delete(void* ptr,
+ size_t /*size*/) noexcept(true) {
+ return free_impl(ptr);
+}
+
+MOZALLOC_EXPORT_NEW void operator delete[](void* ptr,
+ size_t /*size*/) noexcept(true) {
+ return free_impl(ptr);
+}
+#endif
+
+#endif /* mozilla_cxxalloc_h */
diff --git a/memory/mozalloc/moz.build b/memory/mozalloc/moz.build
new file mode 100644
index 0000000000..c5cd784607
--- /dev/null
+++ b/memory/mozalloc/moz.build
@@ -0,0 +1,59 @@
+# -*- 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/.
+NoVisibilityFlags()
+
+EXPORTS.mozilla += [
+ "cxxalloc.h",
+ "mozalloc.h",
+ "mozalloc_abort.h",
+ "mozalloc_oom.h",
+]
+
+if CONFIG["WRAP_STL_INCLUDES"]:
+ if CONFIG["CC_TYPE"] in ("clang", "gcc"):
+ EXPORTS.mozilla += ["throw_gcc.h"]
+ elif CONFIG["CC_TYPE"] == "clang-cl":
+ DEFINES["_HAS_EXCEPTIONS"] = 0
+ SOURCES += [
+ "msvc_raise_wrappers.cpp",
+ ]
+
+if CONFIG["OS_TARGET"] == "WINNT":
+ # Don't build winheap.cpp when mozglue is a static library.
+ if CONFIG["MOZ_MEMORY"] or not CONFIG["JS_STANDALONE"]:
+ # Keep this file separate to avoid #include'ing windows.h everywhere.
+ SOURCES += [
+ "winheap.cpp",
+ ]
+
+UNIFIED_SOURCES += [
+ "mozalloc.cpp",
+ "mozalloc_abort.cpp",
+ "mozalloc_oom.cpp",
+]
+
+if CONFIG["MOZ_MEMORY"]:
+ # In MinGW, we don't want to actually export these functions out of the library
+ # as the functions in libc++ correctly forward to jemalloc and exporting them
+ # produces duplicate symbol errors.
+ if not (CONFIG["CC_TYPE"] == "clang" and CONFIG["OS_TARGET"] == "WINNT"):
+ SOURCES += [
+ "cxxalloc.cpp",
+ ]
+
+FINAL_LIBRARY = "mozglue"
+
+# The strndup declaration in string.h is in an ifdef __USE_GNU section
+DEFINES["_GNU_SOURCE"] = True
+
+DisableStlWrapping()
+
+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 0000000000..aef8ab943a
--- /dev/null
+++ b/memory/mozalloc/mozalloc.cpp
@@ -0,0 +1,159 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 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
+
+#if defined(MALLOC_H)
+# include MALLOC_H // for memalign, malloc_size, malloc_us
+#endif // if defined(MALLOC_H)
+
+#if !defined(MOZ_MEMORY)
+// When jemalloc is disabled, or when building the static runtime variant,
+// we need not to use the suffixes.
+
+# include <stdlib.h> // for malloc, free
+# if defined(XP_UNIX)
+# include <unistd.h>
+# endif // if defined(XP_UNIX)
+
+# define malloc_impl malloc
+# define calloc_impl calloc
+# define realloc_impl realloc
+# define free_impl free
+# define memalign_impl memalign
+# 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 <cstring>
+
+#include <sys/types.h>
+
+#include "mozilla/Assertions.h"
+#include "mozilla/CheckedInt.h"
+#include "mozilla/Likely.h"
+#include "mozilla/mozalloc.h"
+#include "mozilla/mozalloc_oom.h" // for mozalloc_handle_oom
+
+#if defined(MOZ_MEMORY)
+MOZ_MEMORY_API char* strdup_impl(const char*);
+MOZ_MEMORY_API char* strndup_impl(const char*, size_t);
+#endif
+
+void* moz_xmalloc(size_t size) {
+ void* ptr = malloc_impl(size);
+ if (MOZ_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 (MOZ_UNLIKELY(!ptr && nmemb && size)) {
+ mozilla::CheckedInt<size_t> totalSize =
+ mozilla::CheckedInt<size_t>(nmemb) * size;
+ mozalloc_handle_oom(totalSize.isValid() ? totalSize.value() : SIZE_MAX);
+ return moz_xcalloc(nmemb, size);
+ }
+ return ptr;
+}
+
+void* moz_xrealloc(void* ptr, size_t size) {
+ void* newptr = realloc_impl(ptr, size);
+ if (MOZ_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 (MOZ_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 (MOZ_UNLIKELY(!dup)) {
+ mozalloc_handle_oom(strsize);
+ return moz_xstrndup(str, strsize);
+ }
+ return dup;
+}
+#endif // if defined(HAVE_STRNDUP)
+
+void* moz_xmemdup(const void* ptr, size_t size) {
+ void* newPtr = moz_xmalloc(size);
+ memcpy(newPtr, ptr, size);
+ return newPtr;
+}
+
+#ifndef __wasm__
+# ifndef HAVE_MEMALIGN
+// We always have a definition of memalign, but system headers don't
+// necessarily come with a declaration.
+extern "C" void* memalign(size_t, size_t);
+# endif
+
+void* moz_xmemalign(size_t boundary, size_t size) {
+ void* ptr = memalign_impl(boundary, size);
+ if (MOZ_UNLIKELY(!ptr && EINVAL != errno)) {
+ mozalloc_handle_oom(size);
+ return moz_xmemalign(boundary, size);
+ }
+ // non-NULL ptr or errno == EINVAL
+ return ptr;
+}
+#endif
+
+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);
+}
+
+#if defined(MOZ_MEMORY)
+# include "mozjemalloc_types.h"
+// mozmemory.h declares jemalloc_ptr_info(), but including that header in this
+// file is complicated. So we just redeclare it here instead, and include
+// mozjemalloc_types.h for jemalloc_ptr_info_t.
+MOZ_JEMALLOC_API void jemalloc_ptr_info(const void* ptr,
+ jemalloc_ptr_info_t* info);
+#endif
+
+size_t moz_malloc_enclosing_size_of(const void* ptr) {
+#if defined(MOZ_MEMORY)
+ jemalloc_ptr_info_t info;
+ jemalloc_ptr_info(ptr, &info);
+ return jemalloc_ptr_is_live(&info) ? info.size : 0;
+#else
+ return 0;
+#endif
+}
diff --git a/memory/mozalloc/mozalloc.h b/memory/mozalloc/mozalloc.h
new file mode 100644
index 0000000000..1ebbb83237
--- /dev/null
+++ b/memory/mozalloc/mozalloc.h
@@ -0,0 +1,198 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 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>
+#else
+# include <stdlib.h>
+#endif
+
+#if defined(MOZ_MEMORY) && defined(IMPL_MFBT)
+# define MOZ_MEMORY_IMPL
+# include "mozmemory_wrap.h"
+# define MALLOC_FUNCS MALLOC_FUNCS_MALLOC
+// See mozmemory_wrap.h for more details. Files that are part of libmozglue,
+// need to use _impl suffixes, which is becoming cumbersome. We'll have to use
+// something like a malloc.h wrapper and allow the use of the functions without
+// a _impl suffix. In the meanwhile, this is enough to get by for C++ code.
+# define NOTHROW_MALLOC_DECL(name, return_type, ...) \
+ MOZ_MEMORY_API return_type name##_impl(__VA_ARGS__) noexcept(true);
+# define MALLOC_DECL(name, return_type, ...) \
+ MOZ_MEMORY_API return_type name##_impl(__VA_ARGS__);
+# include "malloc_decls.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"
+
+MOZ_BEGIN_EXTERN_C
+
+/*
+ * 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_INFALLIBLE_ALLOCATOR;
+
+MFBT_API void* moz_xcalloc(size_t nmemb, size_t size) MOZ_INFALLIBLE_ALLOCATOR;
+
+MFBT_API void* moz_xrealloc(void* ptr, size_t size) MOZ_INFALLIBLE_ALLOCATOR;
+
+MFBT_API char* moz_xstrdup(const char* str) MOZ_INFALLIBLE_ALLOCATOR;
+
+#if defined(HAVE_STRNDUP)
+MFBT_API char* moz_xstrndup(const char* str,
+ size_t strsize) MOZ_INFALLIBLE_ALLOCATOR;
+#endif /* if defined(HAVE_STRNDUP) */
+
+MFBT_API void* moz_xmemdup(const void* ptr,
+ size_t size) MOZ_INFALLIBLE_ALLOCATOR;
+
+MFBT_API void* moz_xmemalign(size_t boundary,
+ size_t size) MOZ_INFALLIBLE_ALLOCATOR;
+
+MFBT_API size_t moz_malloc_usable_size(void* ptr);
+
+MFBT_API size_t moz_malloc_size_of(const void* ptr);
+
+/*
+ * Like moz_malloc_size_of(), but works reliably with interior pointers, i.e.
+ * pointers into the middle of a live allocation.
+ */
+MFBT_API size_t moz_malloc_enclosing_size_of(const void* ptr);
+
+MOZ_END_EXTERN_C
+
+#ifdef __cplusplus
+
+/* NB: This is defined with MFBT_API just to silence vacuous warnings
+ * about symbol visibility on OS X/gcc.
+ * These symbols are force-inline mainly for performance reasons, and
+ * not exported. While the standard doesn't allow that, we are in a
+ * controlled environment where the issues the standard tries to
+ * prevent don't apply, and we can't end up in situations where
+ * operator new and operator delete are inconsistent. */
+# ifdef __clang__
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Winline-new-delete"
+# endif
+
+# if defined(XP_MACOSX)
+# define MOZALLOC_EXPORT_NEW MFBT_API MOZ_ALWAYS_INLINE_EVEN_DEBUG
+# else
+# define MOZALLOC_EXPORT_NEW MOZ_ALWAYS_INLINE_EVEN_DEBUG
+# endif
+
+# include "mozilla/cxxalloc.h"
+# ifdef __clang__
+# pragma clang diagnostic pop
+# endif
+
+/*
+ * 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)));
+ }
+
+ template <typename T>
+ void free_(T* aPtr, size_t aNumElems = 0) {
+ 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 0000000000..3cfc92533e
--- /dev/null
+++ b/memory/mozalloc/mozalloc_abort.cpp
@@ -0,0 +1,96 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 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 <string.h>
+
+#include "mozilla/Assertions.h"
+#include "mozilla/Sprintf.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_UNSAFE(msg);
+}
+
+#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 : "";
+
+ SprintfLiteral(msg, "abort() called from %s:%p (%s)",
+ base_module ? base_module + 1 : module, module_offset, sym);
+}
+#endif
+
+#if defined(XP_UNIX) && !defined(MOZ_ASAN) && !defined(MOZ_TSAN) && \
+ !defined(LIBFUZZER)
+// 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.
+//
+// The same applies to ThreadSanitizer when run with "halt_on_error=1" in
+// combination with "abort_on_error=1".
+//
+// When building with libFuzzer, it pulls in the UndefinedBehaviorSanitizer
+// runtime which also requires the same workaround as with ASan or TSan.
+extern "C" 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
+ // unreachable marker here to avoid a "'noreturn' function does return"
+ // warning.
+ MOZ_ASSUME_UNREACHABLE_MARKER();
+}
+#endif
diff --git a/memory/mozalloc/mozalloc_abort.h b/memory/mozalloc/mozalloc_abort.h
new file mode 100644
index 0000000000..b9ff92a18e
--- /dev/null
+++ b/memory/mozalloc/mozalloc_abort.h
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 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.
+ */
+extern "C" 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 0000000000..efe5dab4a2
--- /dev/null
+++ b/memory/mozalloc/mozalloc_oom.cpp
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 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"
+
+#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
+
+MFBT_DATA size_t gOOMAllocationSize = 0;
+
+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
+ // Warning: when stage 2 is done by, for example, notifying
+ // "memory-pressure" synchronously, please audit all
+ // nsExpirationTrackers and ensure that the actions they take
+ // on memory-pressure notifications (via NotifyExpired) are safe.
+ // Note that Document::SelectorCache::NotifyExpired is _known_
+ // to not be safe: it will delete the selector it's caching,
+ // which might be in use at the time under querySelector or
+ // querySelectorAll.
+
+ gOOMAllocationSize = 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);
+}
diff --git a/memory/mozalloc/mozalloc_oom.h b/memory/mozalloc/mozalloc_oom.h
new file mode 100644
index 0000000000..be504bac85
--- /dev/null
+++ b/memory/mozalloc/mozalloc_oom.h
@@ -0,0 +1,29 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 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().
+ */
+#ifdef __wasm__
+__attribute__((import_module("env")))
+__attribute__((import_name("mozalloc_handle_oom")))
+#endif
+MFBT_API void
+mozalloc_handle_oom(size_t requestedSize);
+
+extern MFBT_DATA size_t gOOMAllocationSize;
+
+/* 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 0000000000..6eb8bdbe31
--- /dev/null
+++ b/memory/mozalloc/msvc_raise_wrappers.cpp
@@ -0,0 +1,17 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 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 <exception>
+#include "mozalloc_abort.h"
+
+static void __cdecl RaiseHandler(const std::exception& e) {
+ mozalloc_abort(e.what());
+}
+
+static struct StaticScopeStruct final {
+ StaticScopeStruct() { std::exception::_Set_raise_handler(RaiseHandler); }
+} StaticScopeInvoke;
diff --git a/memory/mozalloc/throw_gcc.h b/memory/mozalloc/throw_gcc.h
new file mode 100644
index 0000000000..6a452ca5fc
--- /dev/null
+++ b/memory/mozalloc/throw_gcc.h
@@ -0,0 +1,152 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 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
+
+#if !defined(_LIBCPP_VERSION) || _LIBCPP_VERSION < 14000
+
+# 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
+
+// MinGW doesn't appropriately inline these functions in debug builds,
+// so we need to do some extra coercion for it to do so. Bug 1332747
+# ifdef __MINGW32__
+# define MOZ_THROW_INLINE MOZ_ALWAYS_INLINE_EVEN_DEBUG
+# define MOZ_THROW_EXPORT
+# else
+# define MOZ_THROW_INLINE MOZ_ALWAYS_INLINE
+# define MOZ_THROW_EXPORT MOZ_EXPORT
+# 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_THROW_EXPORT MOZ_THROW_INLINE void __throw_bad_exception(
+ void) {
+ mozalloc_abort("fatal: STL threw bad_exception");
+}
+
+MOZ_THROW_NORETURN MOZ_THROW_EXPORT MOZ_THROW_INLINE void __throw_bad_alloc(
+ void) {
+ mozalloc_abort("fatal: STL threw bad_alloc");
+}
+
+MOZ_THROW_NORETURN MOZ_THROW_EXPORT MOZ_THROW_INLINE void __throw_bad_cast(
+ void) {
+ mozalloc_abort("fatal: STL threw bad_cast");
+}
+
+MOZ_THROW_NORETURN MOZ_THROW_EXPORT MOZ_THROW_INLINE void __throw_bad_typeid(
+ void) {
+ mozalloc_abort("fatal: STL threw bad_typeid");
+}
+
+// used by <functional>
+MOZ_THROW_NORETURN MOZ_THROW_EXPORT MOZ_THROW_INLINE void
+__throw_bad_function_call(void) {
+ mozalloc_abort("fatal: STL threw bad_function_call");
+}
+
+MOZ_THROW_NORETURN MOZ_THROW_EXPORT MOZ_THROW_INLINE void __throw_logic_error(
+ const char* msg) {
+ mozalloc_abort(msg);
+}
+
+MOZ_THROW_NORETURN MOZ_THROW_EXPORT MOZ_THROW_INLINE void __throw_domain_error(
+ const char* msg) {
+ mozalloc_abort(msg);
+}
+
+MOZ_THROW_NORETURN MOZ_THROW_EXPORT MOZ_THROW_INLINE void
+__throw_invalid_argument(const char* msg) {
+ mozalloc_abort(msg);
+}
+
+MOZ_THROW_NORETURN MOZ_THROW_EXPORT MOZ_THROW_INLINE void __throw_length_error(
+ const char* msg) {
+ mozalloc_abort(msg);
+}
+
+MOZ_THROW_NORETURN MOZ_THROW_EXPORT MOZ_THROW_INLINE void __throw_out_of_range(
+ const char* msg) {
+ mozalloc_abort(msg);
+}
+
+MOZ_THROW_NORETURN MOZ_THROW_EXPORT MOZ_THROW_INLINE void __throw_runtime_error(
+ const char* msg) {
+ mozalloc_abort(msg);
+}
+
+MOZ_THROW_NORETURN MOZ_THROW_EXPORT MOZ_THROW_INLINE void __throw_range_error(
+ const char* msg) {
+ mozalloc_abort(msg);
+}
+
+MOZ_THROW_NORETURN MOZ_THROW_EXPORT MOZ_THROW_INLINE void
+__throw_overflow_error(const char* msg) {
+ mozalloc_abort(msg);
+}
+
+MOZ_THROW_NORETURN MOZ_THROW_EXPORT MOZ_THROW_INLINE void
+__throw_underflow_error(const char* msg) {
+ mozalloc_abort(msg);
+}
+
+MOZ_THROW_NORETURN MOZ_THROW_EXPORT MOZ_THROW_INLINE void __throw_ios_failure(
+ const char* msg) {
+ mozalloc_abort(msg);
+}
+
+MOZ_THROW_NORETURN MOZ_THROW_EXPORT MOZ_THROW_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);
+}
+
+MOZ_THROW_NORETURN MOZ_EXPORT MOZ_ALWAYS_INLINE void __throw_regex_error(
+ int err) {
+ char error[128];
+ snprintf(error, sizeof(error) - 1, "fatal: STL threw regex_error: %s (%d)",
+ strerror(err), err);
+ mozalloc_abort(error);
+}
+
+} // namespace std
+
+# undef MOZ_THROW_NORETURN
+# undef MOZ_THROW_INLINE
+
+#endif
+
+#endif // mozilla_throw_gcc_h
diff --git a/memory/mozalloc/winheap.cpp b/memory/mozalloc/winheap.cpp
new file mode 100644
index 0000000000..1d2e1e5599
--- /dev/null
+++ b/memory/mozalloc/winheap.cpp
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 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.h"
+#include <windows.h>
+
+#if !defined(MOZ_MEMORY)
+# include <malloc.h>
+# define malloc_impl malloc
+# define calloc_impl calloc
+# define realloc_impl realloc
+# define free_impl free
+#endif
+
+// 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;
+}