| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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__)) |
| OLD | NEW |