DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (1aeaa33a64f9)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
/* -*- 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

// 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(3) {}

  // 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;
  }

#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;
  }
};
#endif

#endif  // __cplusplus

#endif  // replace_malloc_bridge_h