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