summaryrefslogtreecommitdiffstats
path: root/memory/build/replace_malloc_bridge.h
diff options
context:
space:
mode:
Diffstat (limited to 'memory/build/replace_malloc_bridge.h')
-rw-r--r--memory/build/replace_malloc_bridge.h257
1 files changed, 257 insertions, 0 deletions
diff --git a/memory/build/replace_malloc_bridge.h b/memory/build/replace_malloc_bridge.h
new file mode 100644
index 0000000000..358d9f25c4
--- /dev/null
+++ b/memory/build/replace_malloc_bridge.h
@@ -0,0 +1,257 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 replace_malloc_bridge_h
+#define replace_malloc_bridge_h
+
+// The replace-malloc bridge allows bidirectional method calls between
+// a program and the replace-malloc library that has been loaded for it.
+// In Firefox, this is used to allow method calls between code in libxul
+// and code in the replace-malloc library, without libxul needing to link
+// against that library or vice-versa.
+//
+// Subsystems can add methods for their own need. Replace-malloc libraries
+// can decide to implement those methods or not.
+//
+// Replace-malloc libraries can provide such a bridge by implementing
+// a ReplaceMallocBridge-derived class, and a replace_get_bridge function
+// returning an instance of that class. The default methods in
+// ReplaceMallocBridge are expected to return values that callers would
+// understand as "the bridge doesn't implement this method", so that a
+// replace-malloc library doesn't have to implement all methods.
+//
+// The ReplaceMallocBridge class contains definitions for methods for
+// all replace-malloc libraries. Each library picks the methods it wants
+// to reply to in its ReplaceMallocBridge-derived class instance.
+// All methods of ReplaceMallocBridge must be virtual. Similarly,
+// anything passed as an argument to those methods must be plain data, or
+// an instance of a class with only virtual methods.
+//
+// Binary compatibility is expected to be maintained, such that a newer
+// Firefox can be used with an old replace-malloc library, or an old
+// Firefox can be used with a newer replace-malloc library. As such, only
+// new virtual methods should be added to ReplaceMallocBridge, and
+// each change should have a corresponding bump of the mVersion value.
+// At the same time, each virtual method should have a corresponding
+// wrapper calling the virtual method on the instance from
+// ReplaceMallocBridge::Get(), giving it the version the virtual method
+// was added.
+//
+// Parts that are not relevant to the replace-malloc library end of the
+// bridge are hidden when REPLACE_MALLOC_IMPL is not defined, which is
+// the case when including replace_malloc.h.
+
+struct ReplaceMallocBridge;
+
+#include "mozilla/Types.h"
+
+MOZ_BEGIN_EXTERN_C
+
+#ifndef REPLACE_MALLOC_IMPL
+// Returns the replace-malloc bridge if there is one to be returned.
+MFBT_API ReplaceMallocBridge* get_bridge();
+#endif
+
+// Table of malloc functions.
+// e.g. void* (*malloc)(size_t), etc.
+
+#define MALLOC_DECL(name, return_type, ...) \
+ typedef return_type(name##_impl_t)(__VA_ARGS__);
+
+#include "malloc_decls.h"
+
+#define MALLOC_DECL(name, return_type, ...) name##_impl_t* name;
+
+typedef struct {
+#include "malloc_decls.h"
+} malloc_table_t;
+
+MOZ_END_EXTERN_C
+
+#ifdef __cplusplus
+
+// Table of malloc hook functions.
+// Those functions are called with the arguments and results of malloc
+// functions after they are called.
+// e.g. void* (*malloc_hook)(void*, size_t), etc.
+// They can either return the result they're given, or alter it before
+// returning it.
+// The hooks corresponding to functions, like free(void*), that return no
+// value, don't take an extra argument.
+// The table must at least contain a pointer for malloc_hook and free_hook
+// functions. They will be used as fallback if no pointer is given for
+// other allocation functions, like calloc_hook.
+namespace mozilla {
+namespace detail {
+template <typename R, typename... Args>
+struct AllocHookType {
+ using Type = R (*)(R, Args...);
+};
+
+template <typename... Args>
+struct AllocHookType<void, Args...> {
+ using Type = void (*)(Args...);
+};
+
+} // namespace detail
+} // namespace mozilla
+
+# define MALLOC_DECL(name, return_type, ...) \
+ typename mozilla::detail::AllocHookType<return_type, ##__VA_ARGS__>::Type \
+ name##_hook;
+
+typedef struct {
+# include "malloc_decls.h"
+ // Like free_hook, but called before realloc_hook. free_hook is called
+ // instead of not given.
+ void (*realloc_hook_before)(void* aPtr);
+} malloc_hook_table_t;
+
+namespace mozilla {
+namespace dmd {
+struct DMDFuncs;
+} // namespace dmd
+
+namespace phc {
+class AddrInfo;
+} // namespace phc
+
+// Callbacks to register debug file handles for Poison IO interpose.
+// See Mozilla(|Un)RegisterDebugHandle in xpcom/build/PoisonIOInterposer.h
+struct DebugFdRegistry {
+ virtual void RegisterHandle(intptr_t aFd);
+
+ virtual void UnRegisterHandle(intptr_t aFd);
+};
+
+} // namespace mozilla
+
+struct ReplaceMallocBridge {
+ ReplaceMallocBridge() : mVersion(4) {}
+
+ // This method was added in version 1 of the bridge.
+ virtual mozilla::dmd::DMDFuncs* GetDMDFuncs() { return nullptr; }
+
+ // Send a DebugFdRegistry instance to the replace-malloc library so that
+ // it can register/unregister file descriptors whenever needed. The
+ // instance is valid until the process dies.
+ // This method was added in version 2 of the bridge.
+ virtual void InitDebugFd(mozilla::DebugFdRegistry&) {}
+
+ // Register a list of malloc functions and hook functions to the
+ // replace-malloc library so that it can choose to dispatch to them
+ // when needed. The details of what is dispatched when is left to the
+ // replace-malloc library.
+ // Passing a nullptr for either table will unregister a previously
+ // registered table under the same name.
+ // Returns nullptr if registration failed.
+ // If registration succeeded, a table of "pure" malloc functions is
+ // returned. Those "pure" malloc functions won't call hooks.
+ // /!\ Do not rely on registration/unregistration to be instantaneous.
+ // Functions from a previously registered table may still be called for
+ // a brief time after RegisterHook returns.
+ // This method was added in version 3 of the bridge.
+ virtual const malloc_table_t* RegisterHook(
+ const char* aName, const malloc_table_t* aTable,
+ const malloc_hook_table_t* aHookTable) {
+ return nullptr;
+ }
+
+ // If this is a PHC-handled address, return true, and if an AddrInfo is
+ // provided, fill in all of its fields. Otherwise, return false and leave
+ // AddrInfo unchanged.
+ // This method was added in version 4 of the bridge.
+ virtual bool IsPHCAllocation(const void*, mozilla::phc::AddrInfo*) {
+ return false;
+ }
+
+ // Disable PHC allocations on the current thread. Only useful for tests. Note
+ // that PHC deallocations will still occur as needed.
+ // This method was added in version 4 of the bridge.
+ virtual void DisablePHCOnCurrentThread() {}
+
+ // Re-enable PHC allocations on the current thread. Only useful for tests.
+ // This method was added in version 4 of the bridge.
+ virtual void ReenablePHCOnCurrentThread() {}
+
+ // Test whether PHC allocations are enabled on the current thread. Only
+ // useful for tests.
+ // This method was added in version 4 of the bridge.
+ virtual bool IsPHCEnabledOnCurrentThread() { return false; }
+
+# ifndef REPLACE_MALLOC_IMPL
+ // Returns the replace-malloc bridge if its version is at least the
+ // requested one.
+ static ReplaceMallocBridge* Get(int aMinimumVersion) {
+ static ReplaceMallocBridge* sSingleton = get_bridge();
+ return (sSingleton && sSingleton->mVersion >= aMinimumVersion) ? sSingleton
+ : nullptr;
+ }
+# endif
+
+ protected:
+ const int mVersion;
+};
+
+# ifndef REPLACE_MALLOC_IMPL
+// Class containing wrappers for calls to ReplaceMallocBridge methods.
+// Those wrappers need to be static methods in a class because compilers
+// complain about unused static global functions, and linkers complain
+// about multiple definitions of non-static global functions.
+// Using a separate class from ReplaceMallocBridge allows the function
+// names to be identical.
+struct ReplaceMalloc {
+ // Don't call this method from performance critical code. Use
+ // mozilla::dmd::DMDFuncs::Get() instead, it has less overhead.
+ static mozilla::dmd::DMDFuncs* GetDMDFuncs() {
+ auto singleton = ReplaceMallocBridge::Get(/* minimumVersion */ 1);
+ return singleton ? singleton->GetDMDFuncs() : nullptr;
+ }
+
+ static void InitDebugFd(mozilla::DebugFdRegistry& aRegistry) {
+ auto singleton = ReplaceMallocBridge::Get(/* minimumVersion */ 2);
+ if (singleton) {
+ singleton->InitDebugFd(aRegistry);
+ }
+ }
+
+ static const malloc_table_t* RegisterHook(
+ const char* aName, const malloc_table_t* aTable,
+ const malloc_hook_table_t* aHookTable) {
+ auto singleton = ReplaceMallocBridge::Get(/* minimumVersion */ 3);
+ return singleton ? singleton->RegisterHook(aName, aTable, aHookTable)
+ : nullptr;
+ }
+
+ static bool IsPHCAllocation(const void* aPtr, mozilla::phc::AddrInfo* aOut) {
+ auto singleton = ReplaceMallocBridge::Get(/* minimumVersion */ 4);
+ return singleton ? singleton->IsPHCAllocation(aPtr, aOut) : false;
+ }
+
+ static void DisablePHCOnCurrentThread() {
+ auto singleton = ReplaceMallocBridge::Get(/* minimumVersion */ 4);
+ if (singleton) {
+ singleton->DisablePHCOnCurrentThread();
+ }
+ }
+
+ static void ReenablePHCOnCurrentThread() {
+ auto singleton = ReplaceMallocBridge::Get(/* minimumVersion */ 4);
+ if (singleton) {
+ singleton->ReenablePHCOnCurrentThread();
+ }
+ }
+
+ static bool IsPHCEnabledOnCurrentThread() {
+ auto singleton = ReplaceMallocBridge::Get(/* minimumVersion */ 4);
+ return singleton ? singleton->IsPHCEnabledOnCurrentThread() : false;
+ }
+};
+# endif
+
+#endif // __cplusplus
+
+#endif // replace_malloc_bridge_h