tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

replace_malloc_bridge.h (8165B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef replace_malloc_bridge_h
      8 #define replace_malloc_bridge_h
      9 
     10 // The replace-malloc bridge allows bidirectional method calls between
     11 // a program and the replace-malloc library that has been loaded for it.
     12 // In Firefox, this is used to allow method calls between code in libxul
     13 // and code in the replace-malloc library, without libxul needing to link
     14 // against that library or vice-versa.
     15 //
     16 // Subsystems can add methods for their own need. Replace-malloc libraries
     17 // can decide to implement those methods or not.
     18 //
     19 // Replace-malloc libraries can provide such a bridge by implementing
     20 // a ReplaceMallocBridge-derived class, and a get_bridge function
     21 // returning an instance of that class. The default methods in
     22 // ReplaceMallocBridge are expected to return values that callers would
     23 // understand as "the bridge doesn't implement this method", so that a
     24 // replace-malloc library doesn't have to implement all methods.
     25 //
     26 // The ReplaceMallocBridge class contains definitions for methods for
     27 // all replace-malloc libraries. Each library picks the methods it wants
     28 // to reply to in its ReplaceMallocBridge-derived class instance.
     29 // All methods of ReplaceMallocBridge must be virtual. Similarly,
     30 // anything passed as an argument to those methods must be plain data, or
     31 // an instance of a class with only virtual methods.
     32 //
     33 // Binary compatibility is expected to be maintained, such that a newer
     34 // Firefox can be used with an old replace-malloc library, or an old
     35 // Firefox can be used with a newer replace-malloc library. As such, only
     36 // new virtual methods should be added to ReplaceMallocBridge, and
     37 // each change should have a corresponding bump of the mVersion value.
     38 // At the same time, each virtual method should have a corresponding
     39 // wrapper calling the virtual method on the instance from
     40 // ReplaceMallocBridge::Get(), giving it the version the virtual method
     41 // was added.
     42 //
     43 // Parts that are not relevant to the replace-malloc library end of the
     44 // bridge are hidden when REPLACE_MALLOC_IMPL is not defined, which is
     45 // the case when including replace_malloc.h.
     46 
     47 struct ReplaceMallocBridge;
     48 
     49 #include "mozilla/Types.h"
     50 
     51 #ifdef _WIN32
     52 typedef void* platform_handle_t;
     53 #else
     54 typedef int platform_handle_t;
     55 #endif
     56 
     57 // Include once without MALLOC_DECL set so it can include other headers.
     58 #include "malloc_decls.h"
     59 
     60 MOZ_BEGIN_EXTERN_C
     61 
     62 #ifndef REPLACE_MALLOC_IMPL
     63 // Returns the replace-malloc bridge if there is one to be returned.
     64 MFBT_API ReplaceMallocBridge* get_bridge();
     65 #endif
     66 
     67 // Table of malloc functions.
     68 //   e.g. void* (*malloc)(size_t), etc.
     69 
     70 #define MALLOC_DECL(name, return_type, ...) \
     71  typedef return_type(name##_impl_t)(__VA_ARGS__);
     72 
     73 #include "malloc_decls.h"
     74 
     75 #define MALLOC_DECL(name, return_type, ...) name##_impl_t* name;
     76 
     77 typedef struct {
     78 #include "malloc_decls.h"
     79 } malloc_table_t;
     80 
     81 MOZ_END_EXTERN_C
     82 
     83 #ifdef __cplusplus
     84 
     85 // Table of malloc hook functions.
     86 // Those functions are called with the arguments and results of malloc
     87 // functions after they are called.
     88 //   e.g. void* (*malloc_hook)(void*, size_t), etc.
     89 // They can either return the result they're given, or alter it before
     90 // returning it.
     91 // The hooks corresponding to functions, like free(void*), that return no
     92 // value, don't take an extra argument.
     93 // The table must at least contain a pointer for malloc_hook and free_hook
     94 // functions. They will be used as fallback if no pointer is given for
     95 // other allocation functions, like calloc_hook.
     96 namespace mozilla {
     97 namespace detail {
     98 template <typename R, typename... Args>
     99 struct AllocHookType {
    100  using Type = R (*)(R, Args...);
    101 };
    102 
    103 template <typename... Args>
    104 struct AllocHookType<void, Args...> {
    105  using Type = void (*)(Args...);
    106 };
    107 
    108 }  // namespace detail
    109 }  // namespace mozilla
    110 
    111 #  define MALLOC_DECL(name, return_type, ...)                                 \
    112    typename mozilla::detail::AllocHookType<return_type, ##__VA_ARGS__>::Type \
    113        name##_hook;
    114 
    115 typedef struct {
    116 #  include "malloc_decls.h"
    117  // Like free_hook, but called before realloc_hook. free_hook is called
    118  // instead of not given.
    119  void (*realloc_hook_before)(void* aPtr);
    120 } malloc_hook_table_t;
    121 
    122 namespace mozilla {
    123 namespace dmd {
    124 struct DMDFuncs;
    125 }  // namespace dmd
    126 
    127 namespace phc {
    128 
    129 class AddrInfo;
    130 
    131 }  // namespace phc
    132 
    133 // Callbacks to register debug file handles for Poison IO interpose.
    134 // See Mozilla(|Un)RegisterDebugHandle in xpcom/build/PoisonIOInterposer.h
    135 struct DebugFdRegistry {
    136  virtual void RegisterHandle(platform_handle_t aFd);
    137 
    138  virtual void UnRegisterHandle(platform_handle_t aFd);
    139 };
    140 }  // namespace mozilla
    141 
    142 struct ReplaceMallocBridge {
    143  ReplaceMallocBridge() : mVersion(6) {}
    144 
    145  // This method was added in version 1 of the bridge.
    146  virtual mozilla::dmd::DMDFuncs* GetDMDFuncs() { return nullptr; }
    147 
    148  // Send a DebugFdRegistry instance to the replace-malloc library so that
    149  // it can register/unregister file descriptors whenever needed. The
    150  // instance is valid until the process dies.
    151  // This method was added in version 2 of the bridge.
    152  virtual void InitDebugFd(mozilla::DebugFdRegistry&) {}
    153 
    154  // Register a list of malloc functions and hook functions to the
    155  // replace-malloc library so that it can choose to dispatch to them
    156  // when needed. The details of what is dispatched when is left to the
    157  // replace-malloc library.
    158  // Passing a nullptr for either table will unregister a previously
    159  // registered table under the same name.
    160  // Returns nullptr if registration failed.
    161  // If registration succeeded, a table of "pure" malloc functions is
    162  // returned. Those "pure" malloc functions won't call hooks.
    163  // /!\ Do not rely on registration/unregistration to be instantaneous.
    164  // Functions from a previously registered table may still be called for
    165  // a brief time after RegisterHook returns.
    166  // This method was added in version 3 of the bridge.
    167  virtual const malloc_table_t* RegisterHook(
    168      const char* aName, const malloc_table_t* aTable,
    169      const malloc_hook_table_t* aHookTable) {
    170    return nullptr;
    171  }
    172 
    173 #  ifndef REPLACE_MALLOC_IMPL
    174  // Returns the replace-malloc bridge if its version is at least the
    175  // requested one.
    176  static ReplaceMallocBridge* Get(int aMinimumVersion) {
    177    static ReplaceMallocBridge* sSingleton = get_bridge();
    178    return (sSingleton && sSingleton->mVersion >= aMinimumVersion) ? sSingleton
    179                                                                   : nullptr;
    180  }
    181 #  endif
    182 
    183 protected:
    184  const int mVersion;
    185 };
    186 
    187 #  ifndef REPLACE_MALLOC_IMPL
    188 // Class containing wrappers for calls to ReplaceMallocBridge methods.
    189 // Those wrappers need to be static methods in a class because compilers
    190 // complain about unused static global functions, and linkers complain
    191 // about multiple definitions of non-static global functions.
    192 // Using a separate class from ReplaceMallocBridge allows the function
    193 // names to be identical.
    194 struct ReplaceMalloc {
    195  // Don't call this method from performance critical code. Use
    196  // mozilla::dmd::DMDFuncs::Get() instead, it has less overhead.
    197  static mozilla::dmd::DMDFuncs* GetDMDFuncs() {
    198    auto singleton = ReplaceMallocBridge::Get(/* minimumVersion */ 1);
    199    return singleton ? singleton->GetDMDFuncs() : nullptr;
    200  }
    201 
    202  static void InitDebugFd(mozilla::DebugFdRegistry& aRegistry) {
    203    auto singleton = ReplaceMallocBridge::Get(/* minimumVersion */ 2);
    204    if (singleton) {
    205      singleton->InitDebugFd(aRegistry);
    206    }
    207  }
    208 
    209  static const malloc_table_t* RegisterHook(
    210      const char* aName, const malloc_table_t* aTable,
    211      const malloc_hook_table_t* aHookTable) {
    212    auto singleton = ReplaceMallocBridge::Get(/* minimumVersion */ 3);
    213    return singleton ? singleton->RegisterHook(aName, aTable, aHookTable)
    214                     : nullptr;
    215  }
    216 };
    217 #  endif
    218 
    219 #endif  // __cplusplus
    220 
    221 #endif  // replace_malloc_bridge_h