replace_malloc_bridge.h 7.4 KB

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