Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(17)

Side by Side Diff: third_party/tcmalloc/chromium/src/malloc_hook.cc

Issue 7050034: Merge google-perftools r109 (the current contents of third_party/tcmalloc/vendor) (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2005, Google Inc. 1 // Copyright (c) 2005, Google Inc.
2 // All rights reserved. 2 // All rights reserved.
3 // 3 //
4 // Redistribution and use in source and binary forms, with or without 4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are 5 // modification, are permitted provided that the following conditions are
6 // met: 6 // met:
7 // 7 //
8 // * Redistributions of source code must retain the above copyright 8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer. 9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above 10 // * Redistributions in binary form must reproduce the above
(...skipping 23 matching lines...) Expand all
34 34
35 // Disable the glibc prototype of mremap(), as older versions of the 35 // Disable the glibc prototype of mremap(), as older versions of the
36 // system headers define this function with only four arguments, 36 // system headers define this function with only four arguments,
37 // whereas newer versions allow an optional fifth argument: 37 // whereas newer versions allow an optional fifth argument:
38 #ifdef HAVE_MMAP 38 #ifdef HAVE_MMAP
39 # define mremap glibc_mremap 39 # define mremap glibc_mremap
40 # include <sys/mman.h> 40 # include <sys/mman.h>
41 # undef mremap 41 # undef mremap
42 #endif 42 #endif
43 43
44 #include <stddef.h>
45 #ifdef HAVE_STDINT_H
46 #include <stdint.h>
47 #endif
44 #include <algorithm> 48 #include <algorithm>
45 #include "base/basictypes.h" 49 #include "base/basictypes.h"
46 #include "base/logging.h" 50 #include "base/logging.h"
51 #include "base/spinlock.h"
52 #include "maybe_threads.h"
47 #include "malloc_hook-inl.h" 53 #include "malloc_hook-inl.h"
48 #include <google/malloc_hook.h> 54 #include <google/malloc_hook.h>
49 55
50 // This #ifdef should almost never be set. Set NO_TCMALLOC_SAMPLES if 56 // This #ifdef should almost never be set. Set NO_TCMALLOC_SAMPLES if
51 // you're porting to a system where you really can't get a stacktrace. 57 // you're porting to a system where you really can't get a stacktrace.
52 #ifdef NO_TCMALLOC_SAMPLES 58 #ifdef NO_TCMALLOC_SAMPLES
53 // We use #define so code compiles even if you #include stacktrace.h somehow. 59 // We use #define so code compiles even if you #include stacktrace.h somehow.
54 # define GetStackTrace(stack, depth, skip) (0) 60 # define GetStackTrace(stack, depth, skip) (0)
55 #else 61 #else
56 # include <google/stacktrace.h> 62 # include <google/stacktrace.h>
57 #endif 63 #endif
58 64
59 // __THROW is defined in glibc systems. It means, counter-intuitively, 65 // __THROW is defined in glibc systems. It means, counter-intuitively,
60 // "This function will never throw an exception." It's an optional 66 // "This function will never throw an exception." It's an optional
61 // optimization tool, but we may need to use it to match glibc prototypes. 67 // optimization tool, but we may need to use it to match glibc prototypes.
62 #ifndef __THROW // I guess we're not on a glibc system 68 #ifndef __THROW // I guess we're not on a glibc system
63 # define __THROW // __THROW is just an optimization, so ok to make it "" 69 # define __THROW // __THROW is just an optimization, so ok to make it ""
64 #endif 70 #endif
65 71
66 using std::copy; 72 using std::copy;
67 73
68 74
69 // Declarations of three default weak hook functions, that can be overridden by 75 // Declaration of default weak initialization function, that can be overridden
70 // linking-in a strong definition (as heap-checker.cc does) 76 // by linking-in a strong definition (as heap-checker.cc does). This is
77 // extern "C" so that it doesn't trigger gold's --detect-odr-violations warning,
78 // which only looks at C++ symbols.
71 // 79 //
72 // These default hooks let some other library we link in 80 // This function is declared here as weak, and defined later, rather than a more
73 // to define strong versions of InitialMallocHook_New, InitialMallocHook_MMap, 81 // straightforward simple weak definition, as a workround for an icc compiler
74 // InitialMallocHook_PreMMap, InitialMallocHook_PreSbrk, and 82 // issue ((Intel reference 290819). This issue causes icc to resolve weak
75 // InitialMallocHook_Sbrk to have a chance to hook into the very first 83 // symbols too early, at compile rather than link time. By declaring it (weak)
76 // invocation of an allocation function call, mmap, or sbrk. 84 // here, then defining it below after its use, we can avoid the problem.
85 extern "C" {
86 ATTRIBUTE_WEAK void MallocHook_InitAtFirstAllocation_HeapLeakChecker();
87 }
88
89 namespace {
90
91 void RemoveInitialHooksAndCallInitializers(); // below.
92
93 pthread_once_t once = PTHREAD_ONCE_INIT;
94
95 // These hooks are installed in MallocHook as the only initial hooks. The first
96 // hook that is called will run RemoveInitialHooksAndCallInitializers (see the
97 // definition below) and then redispatch to any malloc hooks installed by
98 // RemoveInitialHooksAndCallInitializers.
77 // 99 //
78 // These functions are declared here as weak, and defined later, rather than a 100 // Note(llib): there is a possibility of a race in the event that there are
79 // more straightforward simple weak definition, as a workround for an icc 101 // multiple threads running before the first allocation. This is pretty
80 // compiler issue ((Intel reference 290819). This issue causes icc to resolve 102 // difficult to achieve, but if it is then multiple threads may concurrently do
81 // weak symbols too early, at compile rather than link time. By declaring it 103 // allocations. The first caller will call
82 // (weak) here, then defining it below after its use, we can avoid the problem. 104 // RemoveInitialHooksAndCallInitializers via one of the initial hooks. A
83 // 105 // concurrent allocation may, depending on timing either:
84 ATTRIBUTE_WEAK 106 // * still have its initial malloc hook installed, run that and block on waiting
85 extern void InitialMallocHook_New(const void* ptr, size_t size); 107 // for the first caller to finish its call to
108 // RemoveInitialHooksAndCallInitializers, and proceed normally.
109 // * occur some time during the RemoveInitialHooksAndCallInitializers call, at
110 // which point there could be no initial hooks and the subsequent hooks that
111 // are about to be set up by RemoveInitialHooksAndCallInitializers haven't
112 // been installed yet. I think the worst we can get is that some allocations
113 // will not get reported to some hooks set by the initializers called from
114 // RemoveInitialHooksAndCallInitializers.
86 115
87 ATTRIBUTE_WEAK 116 void InitialNewHook(const void* ptr, size_t size) {
88 extern void InitialMallocHook_PreMMap(const void* start, 117 perftools_pthread_once(&once, &RemoveInitialHooksAndCallInitializers);
89 size_t size, 118 MallocHook::InvokeNewHook(ptr, size);
90 int protection, 119 }
91 int flags,
92 int fd,
93 off_t offset);
94 120
95 ATTRIBUTE_WEAK 121 void InitialPreMMapHook(const void* start,
96 extern void InitialMallocHook_MMap(const void* result, 122 size_t size,
97 const void* start, 123 int protection,
98 size_t size, 124 int flags,
99 int protection, 125 int fd,
100 int flags, 126 off_t offset) {
101 int fd, 127 perftools_pthread_once(&once, &RemoveInitialHooksAndCallInitializers);
102 off_t offset); 128 MallocHook::InvokePreMmapHook(start, size, protection, flags, fd, offset);
129 }
103 130
104 ATTRIBUTE_WEAK 131 void InitialPreSbrkHook(std::ptrdiff_t increment) {
105 extern void InitialMallocHook_PreSbrk(std::ptrdiff_t increment); 132 perftools_pthread_once(&once, &RemoveInitialHooksAndCallInitializers);
133 MallocHook::InvokePreSbrkHook(increment);
134 }
106 135
107 ATTRIBUTE_WEAK 136 // This function is called at most once by one of the above initial malloc
108 extern void InitialMallocHook_Sbrk(const void* result, std::ptrdiff_t increment) ; 137 // hooks. It removes all initial hooks and initializes all other clients that
138 // want to get control at the very first memory allocation. The initializers
139 // may assume that the initial malloc hooks have been removed. The initializers
140 // may set up malloc hooks and allocate memory.
141 void RemoveInitialHooksAndCallInitializers() {
142 RAW_CHECK(MallocHook::RemoveNewHook(&InitialNewHook), "");
143 RAW_CHECK(MallocHook::RemovePreMmapHook(&InitialPreMMapHook), "");
144 RAW_CHECK(MallocHook::RemovePreSbrkHook(&InitialPreSbrkHook), "");
145
146 // HeapLeakChecker is currently the only module that needs to get control on
147 // the first memory allocation, but one can add other modules by following the
148 // same weak/strong function pattern.
149 MallocHook_InitAtFirstAllocation_HeapLeakChecker();
150 }
151
152 } // namespace
153
154 // Weak default initialization function that must go after its use.
155 extern "C" void MallocHook_InitAtFirstAllocation_HeapLeakChecker() {
156 // Do nothing.
157 }
109 158
110 namespace base { namespace internal { 159 namespace base { namespace internal {
160
161 // The code below is DEPRECATED.
111 template<typename PtrT> 162 template<typename PtrT>
112 PtrT AtomicPtr<PtrT>::Exchange(PtrT new_val) { 163 PtrT AtomicPtr<PtrT>::Exchange(PtrT new_val) {
113 base::subtle::MemoryBarrier(); // Release semantics. 164 base::subtle::MemoryBarrier(); // Release semantics.
114 // Depending on the system, NoBarrier_AtomicExchange(AtomicWord*) 165 // Depending on the system, NoBarrier_AtomicExchange(AtomicWord*)
115 // may have been defined to return an AtomicWord, Atomic32, or 166 // may have been defined to return an AtomicWord, Atomic32, or
116 // Atomic64. We hide that implementation detail here with an 167 // Atomic64. We hide that implementation detail here with an
117 // explicit cast. This prevents MSVC 2005, at least, from complaining. 168 // explicit cast. This prevents MSVC 2005, at least, from complaining.
118 PtrT old_val = reinterpret_cast<PtrT>(static_cast<AtomicWord>( 169 PtrT old_val = reinterpret_cast<PtrT>(static_cast<AtomicWord>(
119 base::subtle::NoBarrier_AtomicExchange( 170 base::subtle::NoBarrier_AtomicExchange(
120 &data_, 171 &data_,
121 reinterpret_cast<AtomicWord>(new_val)))); 172 reinterpret_cast<AtomicWord>(new_val))));
122 base::subtle::MemoryBarrier(); // And acquire semantics. 173 base::subtle::MemoryBarrier(); // And acquire semantics.
123 return old_val; 174 return old_val;
124 } 175 }
125 176
126 AtomicPtr<MallocHook::NewHook> new_hook_ = { 177 template<typename PtrT>
127 reinterpret_cast<AtomicWord>(InitialMallocHook_New) }; 178 PtrT AtomicPtr<PtrT>::CompareAndSwap(PtrT old_val, PtrT new_val) {
179 base::subtle::MemoryBarrier(); // Release semantics.
180 PtrT retval = reinterpret_cast<PtrT>(static_cast<AtomicWord>(
181 base::subtle::NoBarrier_CompareAndSwap(
182 &data_,
183 reinterpret_cast<AtomicWord>(old_val),
184 reinterpret_cast<AtomicWord>(new_val))));
185 base::subtle::MemoryBarrier(); // And acquire semantics.
186 return retval;
187 }
188
189 AtomicPtr<MallocHook::NewHook> new_hook_ = { 0 };
128 AtomicPtr<MallocHook::DeleteHook> delete_hook_ = { 0 }; 190 AtomicPtr<MallocHook::DeleteHook> delete_hook_ = { 0 };
129 AtomicPtr<MallocHook::PreMmapHook> premmap_hook_ = { 191 AtomicPtr<MallocHook::PreMmapHook> premmap_hook_ = { 0 };
130 reinterpret_cast<AtomicWord>(InitialMallocHook_PreMMap) }; 192 AtomicPtr<MallocHook::MmapHook> mmap_hook_ = { 0 };
131 AtomicPtr<MallocHook::MmapHook> mmap_hook_ = {
132 reinterpret_cast<AtomicWord>(InitialMallocHook_MMap) };
133 AtomicPtr<MallocHook::MunmapHook> munmap_hook_ = { 0 }; 193 AtomicPtr<MallocHook::MunmapHook> munmap_hook_ = { 0 };
134 AtomicPtr<MallocHook::MremapHook> mremap_hook_ = { 0 }; 194 AtomicPtr<MallocHook::MremapHook> mremap_hook_ = { 0 };
135 AtomicPtr<MallocHook::PreSbrkHook> presbrk_hook_ = { 195 AtomicPtr<MallocHook::PreSbrkHook> presbrk_hook_ = { 0 };
136 reinterpret_cast<AtomicWord>(InitialMallocHook_PreSbrk) }; 196 AtomicPtr<MallocHook::SbrkHook> sbrk_hook_ = { 0 };
137 AtomicPtr<MallocHook::SbrkHook> sbrk_hook_ = { 197 // End of DEPRECATED code section.
138 reinterpret_cast<AtomicWord>(InitialMallocHook_Sbrk) }; 198
199 // This lock is shared between all implementations of HookList::Add & Remove.
200 // The potential for contention is very small. This needs to be a SpinLock and
201 // not a Mutex since it's possible for Mutex locking to allocate memory (e.g.,
202 // per-thread allocation in debug builds), which could cause infinite recursion.
203 static SpinLock hooklist_spinlock(base::LINKER_INITIALIZED);
204
205 template <typename T>
206 bool HookList<T>::Add(T value_as_t) {
207 // Note: we need to check this _before_ reinterpret_cast, since
208 // reinterpret_cast may include random junk from memory.
209 if (value_as_t == 0) {
210 return false;
211 }
212 AtomicWord value = reinterpret_cast<const AtomicWord&>(value_as_t);
213 if (value == 0) {
214 // This should not actually happen, but just to be sure...
215 return false;
216 }
217 SpinLockHolder l(&hooklist_spinlock);
218 // Find the first slot in data that is 0.
219 int index = 0;
220 while ((index < kHookListMaxValues) &&
221 (base::subtle::NoBarrier_Load(&priv_data[index]) != 0)) {
222 ++index;
223 }
224 if (index == kHookListMaxValues) {
225 return false;
226 }
227 AtomicWord prev_num_hooks = base::subtle::Acquire_Load(&priv_end);
228 base::subtle::Release_Store(&priv_data[index], value);
229 if (prev_num_hooks <= index) {
230 base::subtle::Release_Store(&priv_end, index + 1);
231 }
232 return true;
233 }
234
235 template <typename T>
236 bool HookList<T>::Remove(T value_as_t) {
237 if (value_as_t == 0) {
238 return false;
239 }
240 SpinLockHolder l(&hooklist_spinlock);
241 AtomicWord hooks_end = base::subtle::Acquire_Load(&priv_end);
242 int index = 0;
243 // Note: we need to cast back to T since T may be smaller than AtomicWord.
244 while (index < hooks_end && value_as_t != reinterpret_cast<T>(
245 base::subtle::Acquire_Load(&priv_data[index]))) {
246 ++index;
247 }
248 if (index == hooks_end) {
249 return false;
250 }
251 base::subtle::Release_Store(&priv_data[index], 0);
252 if (hooks_end == index + 1) {
253 // Adjust hooks_end down to the lowest possible value.
254 hooks_end = index;
255 while ((hooks_end > 0) &&
256 (base::subtle::Acquire_Load(&priv_data[hooks_end - 1]) == 0)) {
257 --hooks_end;
258 }
259 base::subtle::Release_Store(&priv_end, hooks_end);
260 }
261 return true;
262 }
263
264 template <typename T>
265 int HookList<T>::Traverse(T* output_array, int n) const {
266 AtomicWord hooks_end = base::subtle::Acquire_Load(&priv_end);
267 int actual_hooks_end = 0;
268 for (int i = 0; i < hooks_end && n > 0; ++i) {
269 AtomicWord data = base::subtle::Acquire_Load(&priv_data[i]);
270 if (data != 0) {
271 *output_array++ = reinterpret_cast<const T&>(data);
272 ++actual_hooks_end;
273 --n;
274 }
275 }
276 return actual_hooks_end;
277 }
278
279 // Initialize a HookList (optionally with the given initial_value in index 0).
280 #define INIT_HOOK_LIST { 0 }
281 #define INIT_HOOK_LIST_WITH_VALUE(initial_value) \
282 { 1, { reinterpret_cast<AtomicWord>(initial_value) } }
283
284 // Explicit instantiation for malloc_hook_test.cc. This ensures all the methods
285 // are instantiated.
286 template class HookList<MallocHook::NewHook>;
287
288 HookList<MallocHook::NewHook> new_hooks_ =
289 INIT_HOOK_LIST_WITH_VALUE(&InitialNewHook);
290 HookList<MallocHook::DeleteHook> delete_hooks_ = INIT_HOOK_LIST;
291 HookList<MallocHook::PreMmapHook> premmap_hooks_ =
292 INIT_HOOK_LIST_WITH_VALUE(&InitialPreMMapHook);
293 HookList<MallocHook::MmapHook> mmap_hooks_ = INIT_HOOK_LIST;
294 HookList<MallocHook::MunmapHook> munmap_hooks_ = INIT_HOOK_LIST;
295 HookList<MallocHook::MremapHook> mremap_hooks_ = INIT_HOOK_LIST;
296 HookList<MallocHook::PreSbrkHook> presbrk_hooks_ =
297 INIT_HOOK_LIST_WITH_VALUE(InitialPreSbrkHook);
298 HookList<MallocHook::SbrkHook> sbrk_hooks_ = INIT_HOOK_LIST;
299
300 // These lists contain either 0 or 1 hooks.
301 HookList<MallocHook::MmapReplacement> mmap_replacement_ = { 0 };
302 HookList<MallocHook::MunmapReplacement> munmap_replacement_ = { 0 };
303
304 #undef INIT_HOOK_LIST_WITH_VALUE
305 #undef INIT_HOOK_LIST
139 306
140 } } // namespace base::internal 307 } } // namespace base::internal
141 308
309 // The code below is DEPRECATED.
142 using base::internal::new_hook_; 310 using base::internal::new_hook_;
143 using base::internal::delete_hook_; 311 using base::internal::delete_hook_;
144 using base::internal::premmap_hook_; 312 using base::internal::premmap_hook_;
145 using base::internal::mmap_hook_; 313 using base::internal::mmap_hook_;
146 using base::internal::munmap_hook_; 314 using base::internal::munmap_hook_;
147 using base::internal::mremap_hook_; 315 using base::internal::mremap_hook_;
148 using base::internal::presbrk_hook_; 316 using base::internal::presbrk_hook_;
149 using base::internal::sbrk_hook_; 317 using base::internal::sbrk_hook_;
150 318 // End of DEPRECATED code section.
319
320 using base::internal::kHookListMaxValues;
321 using base::internal::new_hooks_;
322 using base::internal::delete_hooks_;
323 using base::internal::premmap_hooks_;
324 using base::internal::mmap_hooks_;
325 using base::internal::mmap_replacement_;
326 using base::internal::munmap_hooks_;
327 using base::internal::munmap_replacement_;
328 using base::internal::mremap_hooks_;
329 using base::internal::presbrk_hooks_;
330 using base::internal::sbrk_hooks_;
151 331
152 // These are available as C bindings as well as C++, hence their 332 // These are available as C bindings as well as C++, hence their
153 // definition outside the MallocHook class. 333 // definition outside the MallocHook class.
154 extern "C" 334 extern "C"
335 int MallocHook_AddNewHook(MallocHook_NewHook hook) {
336 RAW_VLOG(10, "AddNewHook(%p)", hook);
337 return new_hooks_.Add(hook);
338 }
339
340 extern "C"
341 int MallocHook_RemoveNewHook(MallocHook_NewHook hook) {
342 RAW_VLOG(10, "RemoveNewHook(%p)", hook);
343 return new_hooks_.Remove(hook);
344 }
345
346 extern "C"
347 int MallocHook_AddDeleteHook(MallocHook_DeleteHook hook) {
348 RAW_VLOG(10, "AddDeleteHook(%p)", hook);
349 return delete_hooks_.Add(hook);
350 }
351
352 extern "C"
353 int MallocHook_RemoveDeleteHook(MallocHook_DeleteHook hook) {
354 RAW_VLOG(10, "RemoveDeleteHook(%p)", hook);
355 return delete_hooks_.Remove(hook);
356 }
357
358 extern "C"
359 int MallocHook_AddPreMmapHook(MallocHook_PreMmapHook hook) {
360 RAW_VLOG(10, "AddPreMmapHook(%p)", hook);
361 return premmap_hooks_.Add(hook);
362 }
363
364 extern "C"
365 int MallocHook_RemovePreMmapHook(MallocHook_PreMmapHook hook) {
366 RAW_VLOG(10, "RemovePreMmapHook(%p)", hook);
367 return premmap_hooks_.Remove(hook);
368 }
369
370 extern "C"
371 int MallocHook_SetMmapReplacement(MallocHook_MmapReplacement hook) {
372 RAW_VLOG(10, "SetMmapReplacement(%p)", hook);
373 // NOTE this is a best effort CHECK. Concurrent sets could succeed since
374 // this test is outside of the Add spin lock.
375 RAW_CHECK(mmap_replacement_.empty(), "Only one MMapReplacement is allowed.");
376 return mmap_replacement_.Add(hook);
377 }
378
379 extern "C"
380 int MallocHook_RemoveMmapReplacement(MallocHook_MmapReplacement hook) {
381 RAW_VLOG(10, "RemoveMmapReplacement(%p)", hook);
382 return mmap_replacement_.Remove(hook);
383 }
384
385 extern "C"
386 int MallocHook_AddMmapHook(MallocHook_MmapHook hook) {
387 RAW_VLOG(10, "AddMmapHook(%p)", hook);
388 return mmap_hooks_.Add(hook);
389 }
390
391 extern "C"
392 int MallocHook_RemoveMmapHook(MallocHook_MmapHook hook) {
393 RAW_VLOG(10, "RemoveMmapHook(%p)", hook);
394 return mmap_hooks_.Remove(hook);
395 }
396
397 extern "C"
398 int MallocHook_AddMunmapHook(MallocHook_MunmapHook hook) {
399 RAW_VLOG(10, "AddMunmapHook(%p)", hook);
400 return munmap_hooks_.Add(hook);
401 }
402
403 extern "C"
404 int MallocHook_RemoveMunmapHook(MallocHook_MunmapHook hook) {
405 RAW_VLOG(10, "RemoveMunmapHook(%p)", hook);
406 return munmap_hooks_.Remove(hook);
407 }
408
409 extern "C"
410 int MallocHook_SetMunmapReplacement(MallocHook_MunmapReplacement hook) {
411 RAW_VLOG(10, "SetMunmapReplacement(%p)", hook);
412 // NOTE this is a best effort CHECK. Concurrent sets could succeed since
413 // this test is outside of the Add spin lock.
414 RAW_CHECK(munmap_replacement_.empty(),
415 "Only one MunmapReplacement is allowed.");
416 return munmap_replacement_.Add(hook);
417 }
418
419 extern "C"
420 int MallocHook_RemoveMunmapReplacement(MallocHook_MunmapReplacement hook) {
421 RAW_VLOG(10, "RemoveMunmapReplacement(%p)", hook);
422 return munmap_replacement_.Remove(hook);
423 }
424
425 extern "C"
426 int MallocHook_AddMremapHook(MallocHook_MremapHook hook) {
427 RAW_VLOG(10, "AddMremapHook(%p)", hook);
428 return mremap_hooks_.Add(hook);
429 }
430
431 extern "C"
432 int MallocHook_RemoveMremapHook(MallocHook_MremapHook hook) {
433 RAW_VLOG(10, "RemoveMremapHook(%p)", hook);
434 return mremap_hooks_.Remove(hook);
435 }
436
437 extern "C"
438 int MallocHook_AddPreSbrkHook(MallocHook_PreSbrkHook hook) {
439 RAW_VLOG(10, "AddPreSbrkHook(%p)", hook);
440 return presbrk_hooks_.Add(hook);
441 }
442
443 extern "C"
444 int MallocHook_RemovePreSbrkHook(MallocHook_PreSbrkHook hook) {
445 RAW_VLOG(10, "RemovePreSbrkHook(%p)", hook);
446 return presbrk_hooks_.Remove(hook);
447 }
448
449 extern "C"
450 int MallocHook_AddSbrkHook(MallocHook_SbrkHook hook) {
451 RAW_VLOG(10, "AddSbrkHook(%p)", hook);
452 return sbrk_hooks_.Add(hook);
453 }
454
455 extern "C"
456 int MallocHook_RemoveSbrkHook(MallocHook_SbrkHook hook) {
457 RAW_VLOG(10, "RemoveSbrkHook(%p)", hook);
458 return sbrk_hooks_.Remove(hook);
459 }
460
461 // The code below is DEPRECATED.
462 extern "C"
155 MallocHook_NewHook MallocHook_SetNewHook(MallocHook_NewHook hook) { 463 MallocHook_NewHook MallocHook_SetNewHook(MallocHook_NewHook hook) {
464 RAW_VLOG(10, "SetNewHook(%p)", hook);
156 return new_hook_.Exchange(hook); 465 return new_hook_.Exchange(hook);
157 } 466 }
158 467
159 extern "C" 468 extern "C"
160 MallocHook_DeleteHook MallocHook_SetDeleteHook(MallocHook_DeleteHook hook) { 469 MallocHook_DeleteHook MallocHook_SetDeleteHook(MallocHook_DeleteHook hook) {
470 RAW_VLOG(10, "SetDeleteHook(%p)", hook);
161 return delete_hook_.Exchange(hook); 471 return delete_hook_.Exchange(hook);
162 } 472 }
163 473
164 extern "C" 474 extern "C"
165 MallocHook_PreMmapHook MallocHook_SetPreMmapHook(MallocHook_PreMmapHook hook) { 475 MallocHook_PreMmapHook MallocHook_SetPreMmapHook(MallocHook_PreMmapHook hook) {
476 RAW_VLOG(10, "SetPreMmapHook(%p)", hook);
166 return premmap_hook_.Exchange(hook); 477 return premmap_hook_.Exchange(hook);
167 } 478 }
168 479
169 extern "C" 480 extern "C"
170 MallocHook_MmapHook MallocHook_SetMmapHook(MallocHook_MmapHook hook) { 481 MallocHook_MmapHook MallocHook_SetMmapHook(MallocHook_MmapHook hook) {
482 RAW_VLOG(10, "SetMmapHook(%p)", hook);
171 return mmap_hook_.Exchange(hook); 483 return mmap_hook_.Exchange(hook);
172 } 484 }
173 485
174 extern "C" 486 extern "C"
175 MallocHook_MunmapHook MallocHook_SetMunmapHook(MallocHook_MunmapHook hook) { 487 MallocHook_MunmapHook MallocHook_SetMunmapHook(MallocHook_MunmapHook hook) {
488 RAW_VLOG(10, "SetMunmapHook(%p)", hook);
176 return munmap_hook_.Exchange(hook); 489 return munmap_hook_.Exchange(hook);
177 } 490 }
178 491
179 extern "C" 492 extern "C"
180 MallocHook_MremapHook MallocHook_SetMremapHook(MallocHook_MremapHook hook) { 493 MallocHook_MremapHook MallocHook_SetMremapHook(MallocHook_MremapHook hook) {
494 RAW_VLOG(10, "SetMremapHook(%p)", hook);
181 return mremap_hook_.Exchange(hook); 495 return mremap_hook_.Exchange(hook);
182 } 496 }
183 497
184 extern "C" 498 extern "C"
185 MallocHook_PreSbrkHook MallocHook_SetPreSbrkHook(MallocHook_PreSbrkHook hook) { 499 MallocHook_PreSbrkHook MallocHook_SetPreSbrkHook(MallocHook_PreSbrkHook hook) {
500 RAW_VLOG(10, "SetPreSbrkHook(%p)", hook);
186 return presbrk_hook_.Exchange(hook); 501 return presbrk_hook_.Exchange(hook);
187 } 502 }
188 503
189 extern "C" 504 extern "C"
190 MallocHook_SbrkHook MallocHook_SetSbrkHook(MallocHook_SbrkHook hook) { 505 MallocHook_SbrkHook MallocHook_SetSbrkHook(MallocHook_SbrkHook hook) {
506 RAW_VLOG(10, "SetSbrkHook(%p)", hook);
191 return sbrk_hook_.Exchange(hook); 507 return sbrk_hook_.Exchange(hook);
192 } 508 }
193 509 // End of DEPRECATED code section.
194 510
195 // The definitions of weak default malloc hooks (New, MMap, and Sbrk) 511 // Note: embedding the function calls inside the traversal of HookList would be
196 // that self deinstall on their first call. This is entirely for 512 // very confusing, as it is legal for a hook to remove itself and add other
197 // efficiency: the default version of these functions will be called a 513 // hooks. Doing traversal first, and then calling the hooks ensures we only
198 // maximum of one time. If these functions were a no-op instead, they'd 514 // call the hooks registered at the start.
199 // be called every time, costing an extra function call per malloc. 515 #define INVOKE_HOOKS(HookType, hook_list, args) do { \
200 // 516 HookType hooks[kHookListMaxValues]; \
201 // However, this 'delete self' isn't safe in general -- it's possible 517 int num_hooks = hook_list.Traverse(hooks, kHookListMaxValues); \
202 // that this function will be called via a daisy chain. That is, 518 for (int i = 0; i < num_hooks; ++i) { \
203 // someone else might do 519 (*hooks[i])args; \
204 // old_hook = MallocHook::SetNewHook(&myhook); 520 } \
205 // void myhook(void* ptr, size_t size) { 521 } while (0)
206 // do_my_stuff(); 522
207 // old_hook(ptr, size); // daisy-chain the hooks 523 // There should only be one replacement. Return the result of the first
208 // } 524 // one, or false if there is none.
209 // If old_hook is InitialMallocHook_New(), then this is broken code! -- 525 #define INVOKE_REPLACEMENT(HookType, hook_list, args) do { \
210 // after the first run it'll deregister not only InitialMallocHook_New() 526 HookType hooks[kHookListMaxValues]; \
211 // but also myhook. To protect against that, InitialMallocHook_New() 527 int num_hooks = hook_list.Traverse(hooks, kHookListMaxValues); \
212 // makes sure it's the 'top-level' hook before doing the deregistration. 528 return (num_hooks > 0 && (*hooks[0])args); \
213 // This means the daisy-chain case will be less efficient because the 529 } while (0)
214 // hook will be called, and do an if check, for every new. Alas. 530
215 // TODO(csilvers): add support for removing a hook from the middle of a chain. 531
216 532 void MallocHook::InvokeNewHookSlow(const void* p, size_t s) {
217 void InitialMallocHook_New(const void* ptr, size_t size) { 533 INVOKE_HOOKS(NewHook, new_hooks_, (p, s));
218 if (MallocHook::GetNewHook() == &InitialMallocHook_New) 534 }
219 MallocHook::SetNewHook(NULL); 535
220 } 536 void MallocHook::InvokeDeleteHookSlow(const void* p) {
221 537 INVOKE_HOOKS(DeleteHook, delete_hooks_, (p));
222 void InitialMallocHook_PreMMap(const void* start, 538 }
223 size_t size, 539
224 int protection, 540 void MallocHook::InvokePreMmapHookSlow(const void* start,
225 int flags, 541 size_t size,
226 int fd, 542 int protection,
227 off_t offset) { 543 int flags,
228 if (MallocHook::GetPreMmapHook() == &InitialMallocHook_PreMMap) 544 int fd,
229 MallocHook::SetPreMmapHook(NULL); 545 off_t offset) {
230 } 546 INVOKE_HOOKS(PreMmapHook, premmap_hooks_, (start, size, protection, flags, fd,
231 547 offset));
232 void InitialMallocHook_MMap(const void* result, 548 }
233 const void* start, 549
234 size_t size, 550 void MallocHook::InvokeMmapHookSlow(const void* result,
235 int protection, 551 const void* start,
236 int flags, 552 size_t size,
237 int fd, 553 int protection,
238 off_t offset) { 554 int flags,
239 if (MallocHook::GetMmapHook() == &InitialMallocHook_MMap) 555 int fd,
240 MallocHook::SetMmapHook(NULL); 556 off_t offset) {
241 } 557 INVOKE_HOOKS(MmapHook, mmap_hooks_, (result, start, size, protection, flags,
242 558 fd, offset));
243 void InitialMallocHook_PreSbrk(std::ptrdiff_t increment) { 559 }
244 if (MallocHook::GetPreSbrkHook() == &InitialMallocHook_PreSbrk) 560
245 MallocHook::SetPreSbrkHook(NULL); 561 bool MallocHook::InvokeMmapReplacementSlow(const void* start,
246 } 562 size_t size,
247 563 int protection,
248 void InitialMallocHook_Sbrk(const void* result, std::ptrdiff_t increment) { 564 int flags,
249 if (MallocHook::GetSbrkHook() == &InitialMallocHook_Sbrk) 565 int fd,
250 MallocHook::SetSbrkHook(NULL); 566 off_t offset,
251 } 567 void** result) {
568 INVOKE_REPLACEMENT(MmapReplacement, mmap_replacement_,
569 (start, size, protection, flags, fd, offset, result));
570 }
571
572 void MallocHook::InvokeMunmapHookSlow(const void* p, size_t s) {
573 INVOKE_HOOKS(MunmapHook, munmap_hooks_, (p, s));
574 }
575
576 bool MallocHook::InvokeMunmapReplacementSlow(const void* p,
577 size_t s,
578 int* result) {
579 INVOKE_REPLACEMENT(MunmapReplacement, munmap_replacement_, (p, s, result));
580 }
581
582 void MallocHook::InvokeMremapHookSlow(const void* result,
583 const void* old_addr,
584 size_t old_size,
585 size_t new_size,
586 int flags,
587 const void* new_addr) {
588 INVOKE_HOOKS(MremapHook, mremap_hooks_, (result, old_addr, old_size, new_size,
589 flags, new_addr));
590 }
591
592 void MallocHook::InvokePreSbrkHookSlow(std::ptrdiff_t increment) {
593 INVOKE_HOOKS(PreSbrkHook, presbrk_hooks_, (increment));
594 }
595
596 void MallocHook::InvokeSbrkHookSlow(const void* result, std::ptrdiff_t increment ) {
597 INVOKE_HOOKS(SbrkHook, sbrk_hooks_, (result, increment));
598 }
599
600 #undef INVOKE_HOOKS
252 601
253 DEFINE_ATTRIBUTE_SECTION_VARS(google_malloc); 602 DEFINE_ATTRIBUTE_SECTION_VARS(google_malloc);
254 DECLARE_ATTRIBUTE_SECTION_VARS(google_malloc); 603 DECLARE_ATTRIBUTE_SECTION_VARS(google_malloc);
255 // actual functions are in debugallocation.cc or tcmalloc.cc 604 // actual functions are in debugallocation.cc or tcmalloc.cc
256 DEFINE_ATTRIBUTE_SECTION_VARS(malloc_hook); 605 DEFINE_ATTRIBUTE_SECTION_VARS(malloc_hook);
257 DECLARE_ATTRIBUTE_SECTION_VARS(malloc_hook); 606 DECLARE_ATTRIBUTE_SECTION_VARS(malloc_hook);
258 // actual functions are in this file, malloc_hook.cc, and low_level_alloc.cc 607 // actual functions are in this file, malloc_hook.cc, and low_level_alloc.cc
259 608
260 #define ADDR_IN_ATTRIBUTE_SECTION(addr, name) \ 609 #define ADDR_IN_ATTRIBUTE_SECTION(addr, name) \
261 (reinterpret_cast<uintptr_t>(ATTRIBUTE_SECTION_START(name)) <= \ 610 (reinterpret_cast<uintptr_t>(ATTRIBUTE_SECTION_START(name)) <= \
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
391 if (!pagesize) pagesize = getpagesize(); 740 if (!pagesize) pagesize = getpagesize();
392 741
393 // Check that the offset is page aligned 742 // Check that the offset is page aligned
394 if (offset & (pagesize - 1)) { 743 if (offset & (pagesize - 1)) {
395 result = MAP_FAILED; 744 result = MAP_FAILED;
396 errno = EINVAL; 745 errno = EINVAL;
397 goto out; 746 goto out;
398 } 747 }
399 748
400 result = (void *)syscall(SYS_mmap2, 749 result = (void *)syscall(SYS_mmap2,
401 start, length, prot, flags, fd, offset / pagesize); 750 start, length, prot, flags, fd,
751 (off_t) (offset / pagesize));
402 if (result != MAP_FAILED || errno != ENOSYS) goto out; 752 if (result != MAP_FAILED || errno != ENOSYS) goto out;
403 753
404 // We don't have mmap2() after all - don't bother trying it in future 754 // We don't have mmap2() after all - don't bother trying it in future
405 have_mmap2 = false; 755 have_mmap2 = false;
406 } 756 }
407 757
408 if (((off_t)offset) != offset) { 758 if (((off_t)offset) != offset) {
409 // If we're trying to map a 64-bit offset, fail now since we don't 759 // If we're trying to map a 64-bit offset, fail now since we don't
410 // have 64-bit mmap() support. 760 // have 64-bit mmap() support.
411 result = MAP_FAILED; 761 result = MAP_FAILED;
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
449 void* mremap(void* old_addr, size_t old_size, size_t new_size, 799 void* mremap(void* old_addr, size_t old_size, size_t new_size,
450 int flags, ...) __THROW 800 int flags, ...) __THROW
451 ATTRIBUTE_SECTION(malloc_hook); 801 ATTRIBUTE_SECTION(malloc_hook);
452 void* sbrk(std::ptrdiff_t increment) __THROW 802 void* sbrk(std::ptrdiff_t increment) __THROW
453 ATTRIBUTE_SECTION(malloc_hook); 803 ATTRIBUTE_SECTION(malloc_hook);
454 } 804 }
455 805
456 extern "C" void* mmap64(void *start, size_t length, int prot, int flags, 806 extern "C" void* mmap64(void *start, size_t length, int prot, int flags,
457 int fd, __off64_t offset) __THROW { 807 int fd, __off64_t offset) __THROW {
458 MallocHook::InvokePreMmapHook(start, length, prot, flags, fd, offset); 808 MallocHook::InvokePreMmapHook(start, length, prot, flags, fd, offset);
459 void *result = do_mmap64(start, length, prot, flags, fd, offset); 809 void *result;
810 if (!MallocHook::InvokeMmapReplacement(
811 start, length, prot, flags, fd, offset, &result)) {
812 result = do_mmap64(start, length, prot, flags, fd, offset);
813 }
460 MallocHook::InvokeMmapHook(result, start, length, prot, flags, fd, offset); 814 MallocHook::InvokeMmapHook(result, start, length, prot, flags, fd, offset);
461 return result; 815 return result;
462 } 816 }
463 817
464 #if !defined(__USE_FILE_OFFSET64) || !defined(__REDIRECT_NTH) 818 #if !defined(__USE_FILE_OFFSET64) || !defined(__REDIRECT_NTH)
465 819
466 extern "C" void* mmap(void *start, size_t length, int prot, int flags, 820 extern "C" void* mmap(void *start, size_t length, int prot, int flags,
467 int fd, off_t offset) __THROW { 821 int fd, off_t offset) __THROW {
468 MallocHook::InvokePreMmapHook(start, length, prot, flags, fd, offset); 822 MallocHook::InvokePreMmapHook(start, length, prot, flags, fd, offset);
469 void *result = do_mmap64(start, length, prot, flags, fd, 823 void *result;
470 static_cast<size_t>(offset)); // avoid sign extension 824 if (!MallocHook::InvokeMmapReplacement(
825 start, length, prot, flags, fd, offset, &result)) {
826 result = do_mmap64(start, length, prot, flags, fd,
827 static_cast<size_t>(offset)); // avoid sign extension
828 }
471 MallocHook::InvokeMmapHook(result, start, length, prot, flags, fd, offset); 829 MallocHook::InvokeMmapHook(result, start, length, prot, flags, fd, offset);
472 return result; 830 return result;
473 } 831 }
474 832
475 #endif // !defined(__USE_FILE_OFFSET64) || !defined(__REDIRECT_NTH) 833 #endif // !defined(__USE_FILE_OFFSET64) || !defined(__REDIRECT_NTH)
476 834
477 extern "C" int munmap(void* start, size_t length) __THROW { 835 extern "C" int munmap(void* start, size_t length) __THROW {
478 MallocHook::InvokeMunmapHook(start, length); 836 MallocHook::InvokeMunmapHook(start, length);
479 return syscall(SYS_munmap, start, length); 837 int result;
838 if (!MallocHook::InvokeMunmapReplacement(start, length, &result)) {
839 result = syscall(SYS_munmap, start, length);
840 }
841 return result;
480 } 842 }
481 843
482 extern "C" void* mremap(void* old_addr, size_t old_size, size_t new_size, 844 extern "C" void* mremap(void* old_addr, size_t old_size, size_t new_size,
483 int flags, ...) __THROW { 845 int flags, ...) __THROW {
484 va_list ap; 846 va_list ap;
485 va_start(ap, flags); 847 va_start(ap, flags);
486 void *new_address = va_arg(ap, void *); 848 void *new_address = va_arg(ap, void *);
487 va_end(ap); 849 va_end(ap);
488 void* result = sys_mremap(old_addr, old_size, new_size, flags, new_address); 850 void* result = sys_mremap(old_addr, old_size, new_size, flags, new_address);
489 MallocHook::InvokeMremapHook(result, old_addr, old_size, new_size, flags, 851 MallocHook::InvokeMremapHook(result, old_addr, old_size, new_size, flags,
490 new_address); 852 new_address);
491 return result; 853 return result;
492 } 854 }
493 855
494 // libc's version: 856 // libc's version:
495 extern "C" void* __sbrk(std::ptrdiff_t increment); 857 extern "C" void* __sbrk(std::ptrdiff_t increment);
496 858
497 extern "C" void* sbrk(std::ptrdiff_t increment) __THROW { 859 extern "C" void* sbrk(std::ptrdiff_t increment) __THROW {
498 MallocHook::InvokePreSbrkHook(increment); 860 MallocHook::InvokePreSbrkHook(increment);
499 void *result = __sbrk(increment); 861 void *result = __sbrk(increment);
500 MallocHook::InvokeSbrkHook(result, increment); 862 MallocHook::InvokeSbrkHook(result, increment);
501 return result; 863 return result;
502 } 864 }
503 865
504 /*static*/void* MallocHook::UnhookedMMap(void *start, size_t length, int prot, 866 /*static*/void* MallocHook::UnhookedMMap(void *start, size_t length, int prot,
505 int flags, int fd, off_t offset) { 867 int flags, int fd, off_t offset) {
506 return do_mmap64(start, length, prot, flags, fd, offset); 868 void* result;
869 if (!MallocHook::InvokeMmapReplacement(
870 start, length, prot, flags, fd, offset, &result)) {
871 result = do_mmap64(start, length, prot, flags, fd, offset);
872 }
873 return result;
507 } 874 }
508 875
509 /*static*/int MallocHook::UnhookedMUnmap(void *start, size_t length) { 876 /*static*/int MallocHook::UnhookedMUnmap(void *start, size_t length) {
510 return sys_munmap(start, length); 877 int result;
878 if (!MallocHook::InvokeMunmapReplacement(start, length, &result)) {
879 result = sys_munmap(start, length);
880 }
881 return result;
511 } 882 }
512 883
513 #else // defined(__linux) && 884 #else // defined(__linux) &&
514 // (defined(__i386__) || defined(__x86_64__) || defined(__PPC__)) 885 // (defined(__i386__) || defined(__x86_64__) || defined(__PPC__))
515 886
516 /*static*/void* MallocHook::UnhookedMMap(void *start, size_t length, int prot, 887 /*static*/void* MallocHook::UnhookedMMap(void *start, size_t length, int prot,
517 int flags, int fd, off_t offset) { 888 int flags, int fd, off_t offset) {
518 return mmap(start, length, prot, flags, fd, offset); 889 void* result;
890 if (!MallocHook::InvokeMmapReplacement(
891 start, length, prot, flags, fd, offset, &result)) {
892 result = mmap(start, length, prot, flags, fd, offset);
893 }
894 return result;
519 } 895 }
520 896
521 /*static*/int MallocHook::UnhookedMUnmap(void *start, size_t length) { 897 /*static*/int MallocHook::UnhookedMUnmap(void *start, size_t length) {
522 return munmap(start, length); 898 int result;
899 if (!MallocHook::InvokeMunmapReplacement(start, length, &result)) {
900 result = munmap(start, length);
901 }
902 return result;
523 } 903 }
524 904
525 #endif // defined(__linux) && 905 #endif // defined(__linux) &&
526 // (defined(__i386__) || defined(__x86_64__) || defined(__PPC__)) 906 // (defined(__i386__) || defined(__x86_64__) || defined(__PPC__))
OLDNEW
« no previous file with comments | « third_party/tcmalloc/chromium/src/malloc_extension.cc ('k') | third_party/tcmalloc/chromium/src/malloc_hook-inl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698