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/. */
7 #ifndef replace_malloc_bridge_h
8 #define replace_malloc_bridge_h
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.
16 // Subsystems can add methods for their own need. Replace-malloc libraries
17 // can decide to implement those methods or not.
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.
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.
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
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.
47 struct ReplaceMallocBridge
;
49 #include "mozilla/Types.h"
53 #ifndef REPLACE_MALLOC_IMPL
54 // Returns the replace-malloc bridge if there is one to be returned.
55 MFBT_API ReplaceMallocBridge
* get_bridge();
58 // Table of malloc functions.
59 // e.g. void* (*malloc)(size_t), etc.
61 #define MALLOC_DECL(name, return_type, ...) \
62 typedef return_type(name##_impl_t)(__VA_ARGS__);
64 #include "malloc_decls.h"
66 #define MALLOC_DECL(name, return_type, ...) name##_impl_t* name;
69 #include "malloc_decls.h"
76 // Table of malloc hook functions.
77 // Those functions are called with the arguments and results of malloc
78 // functions after they are called.
79 // e.g. void* (*malloc_hook)(void*, size_t), etc.
80 // They can either return the result they're given, or alter it before
82 // The hooks corresponding to functions, like free(void*), that return no
83 // value, don't take an extra argument.
84 // The table must at least contain a pointer for malloc_hook and free_hook
85 // functions. They will be used as fallback if no pointer is given for
86 // other allocation functions, like calloc_hook.
89 template <typename R
, typename
... Args
>
90 struct AllocHookType
{
91 using Type
= R (*)(R
, Args
...);
94 template <typename
... Args
>
95 struct AllocHookType
<void, Args
...> {
96 using Type
= void (*)(Args
...);
100 } // namespace mozilla
102 # define MALLOC_DECL(name, return_type, ...) \
103 typename mozilla::detail::AllocHookType<return_type, ##__VA_ARGS__>::Type \
107 # include "malloc_decls.h"
108 // Like free_hook, but called before realloc_hook. free_hook is called
109 // instead of not given.
110 void (*realloc_hook_before
)(void* aPtr
);
111 } malloc_hook_table_t
;
122 // The amount of memory used for PHC metadata, eg information about each
123 // allocation including stacks.
124 size_t mMetadataBytes
= 0;
126 // The amount of memory lost due to rounding allocation sizes up to the
127 // nearest page. AKA internal fragmentation.
128 size_t mFragmentationBytes
= 0;
132 // Callbacks to register debug file handles for Poison IO interpose.
133 // See Mozilla(|Un)RegisterDebugHandle in xpcom/build/PoisonIOInterposer.h
134 struct DebugFdRegistry
{
135 virtual void RegisterHandle(intptr_t aFd
);
137 virtual void UnRegisterHandle(intptr_t aFd
);
139 } // namespace mozilla
141 struct ReplaceMallocBridge
{
142 ReplaceMallocBridge() : mVersion(5) {}
144 // This method was added in version 1 of the bridge.
145 virtual mozilla::dmd::DMDFuncs
* GetDMDFuncs() { return nullptr; }
147 // Send a DebugFdRegistry instance to the replace-malloc library so that
148 // it can register/unregister file descriptors whenever needed. The
149 // instance is valid until the process dies.
150 // This method was added in version 2 of the bridge.
151 virtual void InitDebugFd(mozilla::DebugFdRegistry
&) {}
153 // Register a list of malloc functions and hook functions to the
154 // replace-malloc library so that it can choose to dispatch to them
155 // when needed. The details of what is dispatched when is left to the
156 // replace-malloc library.
157 // Passing a nullptr for either table will unregister a previously
158 // registered table under the same name.
159 // Returns nullptr if registration failed.
160 // If registration succeeded, a table of "pure" malloc functions is
161 // returned. Those "pure" malloc functions won't call hooks.
162 // /!\ Do not rely on registration/unregistration to be instantaneous.
163 // Functions from a previously registered table may still be called for
164 // a brief time after RegisterHook returns.
165 // This method was added in version 3 of the bridge.
166 virtual const malloc_table_t
* RegisterHook(
167 const char* aName
, const malloc_table_t
* aTable
,
168 const malloc_hook_table_t
* aHookTable
) {
172 // If this is a PHC-handled address, return true, and if an AddrInfo is
173 // provided, fill in all of its fields. Otherwise, return false and leave
174 // AddrInfo unchanged.
175 // This method was added in version 4 of the bridge.
176 virtual bool IsPHCAllocation(const void*, mozilla::phc::AddrInfo
*) {
180 // Disable PHC allocations on the current thread. Only useful for tests. Note
181 // that PHC deallocations will still occur as needed.
182 // This method was added in version 4 of the bridge.
183 virtual void DisablePHCOnCurrentThread() {}
185 // Re-enable PHC allocations on the current thread. Only useful for tests.
186 // This method was added in version 4 of the bridge.
187 virtual void ReenablePHCOnCurrentThread() {}
189 // Test whether PHC allocations are enabled on the current thread. Only
191 // This method was added in version 4 of the bridge.
192 virtual bool IsPHCEnabledOnCurrentThread() { return false; }
194 // Return PHC memory usage information by filling in the supplied structure.
195 // This method was added in version 5 of the bridge.
196 virtual void PHCMemoryUsage(mozilla::phc::MemoryUsage
& aMemoryUsage
) {}
198 # ifndef REPLACE_MALLOC_IMPL
199 // Returns the replace-malloc bridge if its version is at least the
201 static ReplaceMallocBridge
* Get(int aMinimumVersion
) {
202 static ReplaceMallocBridge
* sSingleton
= get_bridge();
203 return (sSingleton
&& sSingleton
->mVersion
>= aMinimumVersion
) ? sSingleton
212 # ifndef REPLACE_MALLOC_IMPL
213 // Class containing wrappers for calls to ReplaceMallocBridge methods.
214 // Those wrappers need to be static methods in a class because compilers
215 // complain about unused static global functions, and linkers complain
216 // about multiple definitions of non-static global functions.
217 // Using a separate class from ReplaceMallocBridge allows the function
218 // names to be identical.
219 struct ReplaceMalloc
{
220 // Don't call this method from performance critical code. Use
221 // mozilla::dmd::DMDFuncs::Get() instead, it has less overhead.
222 static mozilla::dmd::DMDFuncs
* GetDMDFuncs() {
223 auto singleton
= ReplaceMallocBridge::Get(/* minimumVersion */ 1);
224 return singleton
? singleton
->GetDMDFuncs() : nullptr;
227 static void InitDebugFd(mozilla::DebugFdRegistry
& aRegistry
) {
228 auto singleton
= ReplaceMallocBridge::Get(/* minimumVersion */ 2);
230 singleton
->InitDebugFd(aRegistry
);
234 static const malloc_table_t
* RegisterHook(
235 const char* aName
, const malloc_table_t
* aTable
,
236 const malloc_hook_table_t
* aHookTable
) {
237 auto singleton
= ReplaceMallocBridge::Get(/* minimumVersion */ 3);
238 return singleton
? singleton
->RegisterHook(aName
, aTable
, aHookTable
)
242 static bool IsPHCAllocation(const void* aPtr
, mozilla::phc::AddrInfo
* aOut
) {
243 auto singleton
= ReplaceMallocBridge::Get(/* minimumVersion */ 4);
244 return singleton
? singleton
->IsPHCAllocation(aPtr
, aOut
) : false;
247 static void DisablePHCOnCurrentThread() {
248 auto singleton
= ReplaceMallocBridge::Get(/* minimumVersion */ 4);
250 singleton
->DisablePHCOnCurrentThread();
254 static void ReenablePHCOnCurrentThread() {
255 auto singleton
= ReplaceMallocBridge::Get(/* minimumVersion */ 4);
257 singleton
->ReenablePHCOnCurrentThread();
261 static bool IsPHCEnabledOnCurrentThread() {
262 auto singleton
= ReplaceMallocBridge::Get(/* minimumVersion */ 4);
263 return singleton
? singleton
->IsPHCEnabledOnCurrentThread() : false;
266 static void PHCMemoryUsage(mozilla::phc::MemoryUsage
& aMemoryUsage
) {
267 auto singleton
= ReplaceMallocBridge::Get(/* minimumVersion */ 5);
269 singleton
->PHCMemoryUsage(aMemoryUsage
);
275 #endif // __cplusplus
277 #endif // replace_malloc_bridge_h