| 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 28 matching lines...) Expand all Loading... |
| 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> | 44 #include <stddef.h> |
| 45 #ifdef HAVE_STDINT_H | 45 #ifdef HAVE_STDINT_H |
| 46 #include <stdint.h> | 46 #include <stdint.h> |
| 47 #endif | 47 #endif |
| 48 #include <algorithm> | 48 #include <algorithm> |
| 49 #include "base/basictypes.h" | |
| 50 #include "base/logging.h" | 49 #include "base/logging.h" |
| 51 #include "base/spinlock.h" | 50 #include "base/spinlock.h" |
| 52 #include "maybe_threads.h" | 51 #include "maybe_threads.h" |
| 53 #include "malloc_hook-inl.h" | 52 #include "malloc_hook-inl.h" |
| 54 #include <google/malloc_hook.h> | 53 #include <gperftools/malloc_hook.h> |
| 55 | 54 |
| 56 // This #ifdef should almost never be set. Set NO_TCMALLOC_SAMPLES if | 55 // This #ifdef should almost never be set. Set NO_TCMALLOC_SAMPLES if |
| 57 // you're porting to a system where you really can't get a stacktrace. | 56 // you're porting to a system where you really can't get a stacktrace. |
| 58 #ifdef NO_TCMALLOC_SAMPLES | 57 #ifdef NO_TCMALLOC_SAMPLES |
| 59 // We use #define so code compiles even if you #include stacktrace.h somehow. | 58 // We use #define so code compiles even if you #include stacktrace.h somehow. |
| 60 # define GetStackTrace(stack, depth, skip) (0) | 59 # define GetStackTrace(stack, depth, skip) (0) |
| 61 #else | 60 #else |
| 62 # include <google/stacktrace.h> | 61 # include <gperftools/stacktrace.h> |
| 63 #endif | 62 #endif |
| 64 | 63 |
| 65 // __THROW is defined in glibc systems. It means, counter-intuitively, | 64 // __THROW is defined in glibc systems. It means, counter-intuitively, |
| 66 // "This function will never throw an exception." It's an optional | 65 // "This function will never throw an exception." It's an optional |
| 67 // optimization tool, but we may need to use it to match glibc prototypes. | 66 // optimization tool, but we may need to use it to match glibc prototypes. |
| 68 #ifndef __THROW // I guess we're not on a glibc system | 67 #ifndef __THROW // I guess we're not on a glibc system |
| 69 # define __THROW // __THROW is just an optimization, so ok to make it "" | 68 # define __THROW // __THROW is just an optimization, so ok to make it "" |
| 70 #endif | 69 #endif |
| 71 | 70 |
| 72 using std::copy; | 71 using std::copy; |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 197 // End of DEPRECATED code section. | 196 // End of DEPRECATED code section. |
| 198 | 197 |
| 199 // This lock is shared between all implementations of HookList::Add & Remove. | 198 // 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 | 199 // 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., | 200 // 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. | 201 // per-thread allocation in debug builds), which could cause infinite recursion. |
| 203 static SpinLock hooklist_spinlock(base::LINKER_INITIALIZED); | 202 static SpinLock hooklist_spinlock(base::LINKER_INITIALIZED); |
| 204 | 203 |
| 205 template <typename T> | 204 template <typename T> |
| 206 bool HookList<T>::Add(T value_as_t) { | 205 bool HookList<T>::Add(T value_as_t) { |
| 207 // Note: we need to check this _before_ reinterpret_cast, since | 206 AtomicWord value = bit_cast<AtomicWord>(value_as_t); |
| 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) { | 207 if (value == 0) { |
| 214 // This should not actually happen, but just to be sure... | |
| 215 return false; | 208 return false; |
| 216 } | 209 } |
| 217 SpinLockHolder l(&hooklist_spinlock); | 210 SpinLockHolder l(&hooklist_spinlock); |
| 218 // Find the first slot in data that is 0. | 211 // Find the first slot in data that is 0. |
| 219 int index = 0; | 212 int index = 0; |
| 220 while ((index < kHookListMaxValues) && | 213 while ((index < kHookListMaxValues) && |
| 221 (base::subtle::NoBarrier_Load(&priv_data[index]) != 0)) { | 214 (base::subtle::NoBarrier_Load(&priv_data[index]) != 0)) { |
| 222 ++index; | 215 ++index; |
| 223 } | 216 } |
| 224 if (index == kHookListMaxValues) { | 217 if (index == kHookListMaxValues) { |
| 225 return false; | 218 return false; |
| 226 } | 219 } |
| 227 AtomicWord prev_num_hooks = base::subtle::Acquire_Load(&priv_end); | 220 AtomicWord prev_num_hooks = base::subtle::Acquire_Load(&priv_end); |
| 228 base::subtle::Release_Store(&priv_data[index], value); | 221 base::subtle::Release_Store(&priv_data[index], value); |
| 229 if (prev_num_hooks <= index) { | 222 if (prev_num_hooks <= index) { |
| 230 base::subtle::Release_Store(&priv_end, index + 1); | 223 base::subtle::Release_Store(&priv_end, index + 1); |
| 231 } | 224 } |
| 232 return true; | 225 return true; |
| 233 } | 226 } |
| 234 | 227 |
| 235 template <typename T> | 228 template <typename T> |
| 236 bool HookList<T>::Remove(T value_as_t) { | 229 bool HookList<T>::Remove(T value_as_t) { |
| 237 if (value_as_t == 0) { | 230 if (value_as_t == 0) { |
| 238 return false; | 231 return false; |
| 239 } | 232 } |
| 240 SpinLockHolder l(&hooklist_spinlock); | 233 SpinLockHolder l(&hooklist_spinlock); |
| 241 AtomicWord hooks_end = base::subtle::Acquire_Load(&priv_end); | 234 AtomicWord hooks_end = base::subtle::Acquire_Load(&priv_end); |
| 242 int index = 0; | 235 int index = 0; |
| 243 // Note: we need to cast back to T since T may be smaller than AtomicWord. | 236 while (index < hooks_end && value_as_t != bit_cast<T>( |
| 244 while (index < hooks_end && value_as_t != reinterpret_cast<T>( | |
| 245 base::subtle::Acquire_Load(&priv_data[index]))) { | 237 base::subtle::Acquire_Load(&priv_data[index]))) { |
| 246 ++index; | 238 ++index; |
| 247 } | 239 } |
| 248 if (index == hooks_end) { | 240 if (index == hooks_end) { |
| 249 return false; | 241 return false; |
| 250 } | 242 } |
| 251 base::subtle::Release_Store(&priv_data[index], 0); | 243 base::subtle::Release_Store(&priv_data[index], 0); |
| 252 if (hooks_end == index + 1) { | 244 if (hooks_end == index + 1) { |
| 253 // Adjust hooks_end down to the lowest possible value. | 245 // Adjust hooks_end down to the lowest possible value. |
| 254 hooks_end = index; | 246 hooks_end = index; |
| 255 while ((hooks_end > 0) && | 247 while ((hooks_end > 0) && |
| 256 (base::subtle::Acquire_Load(&priv_data[hooks_end - 1]) == 0)) { | 248 (base::subtle::Acquire_Load(&priv_data[hooks_end - 1]) == 0)) { |
| 257 --hooks_end; | 249 --hooks_end; |
| 258 } | 250 } |
| 259 base::subtle::Release_Store(&priv_end, hooks_end); | 251 base::subtle::Release_Store(&priv_end, hooks_end); |
| 260 } | 252 } |
| 261 return true; | 253 return true; |
| 262 } | 254 } |
| 263 | 255 |
| 264 template <typename T> | 256 template <typename T> |
| 265 int HookList<T>::Traverse(T* output_array, int n) const { | 257 int HookList<T>::Traverse(T* output_array, int n) const { |
| 266 AtomicWord hooks_end = base::subtle::Acquire_Load(&priv_end); | 258 AtomicWord hooks_end = base::subtle::Acquire_Load(&priv_end); |
| 267 int actual_hooks_end = 0; | 259 int actual_hooks_end = 0; |
| 268 for (int i = 0; i < hooks_end && n > 0; ++i) { | 260 for (int i = 0; i < hooks_end && n > 0; ++i) { |
| 269 AtomicWord data = base::subtle::Acquire_Load(&priv_data[i]); | 261 AtomicWord data = base::subtle::Acquire_Load(&priv_data[i]); |
| 270 if (data != 0) { | 262 if (data != 0) { |
| 271 *output_array++ = reinterpret_cast<const T&>(data); | 263 *output_array++ = bit_cast<T>(data); |
| 272 ++actual_hooks_end; | 264 ++actual_hooks_end; |
| 273 --n; | 265 --n; |
| 274 } | 266 } |
| 275 } | 267 } |
| 276 return actual_hooks_end; | 268 return actual_hooks_end; |
| 277 } | 269 } |
| 278 | 270 |
| 279 // Initialize a HookList (optionally with the given initial_value in index 0). | 271 // Initialize a HookList (optionally with the given initial_value in index 0). |
| 280 #define INIT_HOOK_LIST { 0 } | 272 #define INIT_HOOK_LIST { 0 } |
| 281 #define INIT_HOOK_LIST_WITH_VALUE(initial_value) \ | 273 #define INIT_HOOK_LIST_WITH_VALUE(initial_value) \ |
| (...skipping 416 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 698 #endif | 690 #endif |
| 699 } | 691 } |
| 700 | 692 |
| 701 // On systems where we know how, we override mmap/munmap/mremap/sbrk | 693 // On systems where we know how, we override mmap/munmap/mremap/sbrk |
| 702 // to provide support for calling the related hooks (in addition, | 694 // to provide support for calling the related hooks (in addition, |
| 703 // of course, to doing what these functions normally do). | 695 // of course, to doing what these functions normally do). |
| 704 | 696 |
| 705 #if defined(__linux) | 697 #if defined(__linux) |
| 706 # include "malloc_hook_mmap_linux.h" | 698 # include "malloc_hook_mmap_linux.h" |
| 707 | 699 |
| 708 // This code doesn't even compile on my freebsd 8.1 (x86_64) system, | 700 #elif defined(__FreeBSD__) |
| 709 // so comment it out for now. TODO(csilvers): fix this! | |
| 710 #elif 0 && defined(__FreeBSD__) | |
| 711 # include "malloc_hook_mmap_freebsd.h" | 701 # include "malloc_hook_mmap_freebsd.h" |
| 712 | 702 |
| 713 #else | 703 #else |
| 714 | 704 |
| 715 /*static*/void* MallocHook::UnhookedMMap(void *start, size_t length, int prot, | 705 /*static*/void* MallocHook::UnhookedMMap(void *start, size_t length, int prot, |
| 716 int flags, int fd, off_t offset) { | 706 int flags, int fd, off_t offset) { |
| 717 void* result; | 707 void* result; |
| 718 if (!MallocHook::InvokeMmapReplacement( | 708 if (!MallocHook::InvokeMmapReplacement( |
| 719 start, length, prot, flags, fd, offset, &result)) { | 709 start, length, prot, flags, fd, offset, &result)) { |
| 720 result = mmap(start, length, prot, flags, fd, offset); | 710 result = mmap(start, length, prot, flags, fd, offset); |
| 721 } | 711 } |
| 722 return result; | 712 return result; |
| 723 } | 713 } |
| 724 | 714 |
| 725 /*static*/int MallocHook::UnhookedMUnmap(void *start, size_t length) { | 715 /*static*/int MallocHook::UnhookedMUnmap(void *start, size_t length) { |
| 726 int result; | 716 int result; |
| 727 if (!MallocHook::InvokeMunmapReplacement(start, length, &result)) { | 717 if (!MallocHook::InvokeMunmapReplacement(start, length, &result)) { |
| 728 result = munmap(start, length); | 718 result = munmap(start, length); |
| 729 } | 719 } |
| 730 return result; | 720 return result; |
| 731 } | 721 } |
| 732 | 722 |
| 733 #endif | 723 #endif |
| OLD | NEW |