| 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 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 45 #include <sys/mman.h> | 45 #include <sys/mman.h> |
| 46 #endif | 46 #endif |
| 47 #ifdef HAVE_PTHREAD | 47 #ifdef HAVE_PTHREAD |
| 48 #include <pthread.h> | 48 #include <pthread.h> |
| 49 #endif | 49 #endif |
| 50 #include <sys/stat.h> | 50 #include <sys/stat.h> |
| 51 #include <sys/types.h> | 51 #include <sys/types.h> |
| 52 #include <time.h> | 52 #include <time.h> |
| 53 #include <assert.h> | 53 #include <assert.h> |
| 54 | 54 |
| 55 #ifdef HAVE_LINUX_PTRACE_H | 55 #if defined(HAVE_LINUX_PTRACE_H) && !defined(__native_client__) |
| 56 #include <linux/ptrace.h> | 56 #include <linux/ptrace.h> |
| 57 #endif | 57 #endif |
| 58 #ifdef HAVE_SYS_SYSCALL_H | 58 #ifdef HAVE_SYS_SYSCALL_H |
| 59 #include <sys/syscall.h> | 59 #include <sys/syscall.h> |
| 60 #endif | 60 #endif |
| 61 #if defined(_WIN32) || defined(__CYGWIN__) || defined(__CYGWIN32__) || defined(_
_MINGW32__) | 61 #if defined(_WIN32) || defined(__CYGWIN__) || defined(__CYGWIN32__) || defined(_
_MINGW32__) |
| 62 #include <wtypes.h> | 62 #include <wtypes.h> |
| 63 #include <winbase.h> | 63 #include <winbase.h> |
| 64 #undef ERROR // windows defines these as macros, which can cause trouble | 64 #undef ERROR // windows defines these as macros, which can cause trouble |
| 65 #undef max | 65 #undef max |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 271 static pid_t heap_checker_pid = 0; | 271 static pid_t heap_checker_pid = 0; |
| 272 | 272 |
| 273 // If we did heap profiling during global constructors execution | 273 // If we did heap profiling during global constructors execution |
| 274 static bool constructor_heap_profiling = false; | 274 static bool constructor_heap_profiling = false; |
| 275 | 275 |
| 276 // RAW_VLOG level we dump key INFO messages at. If you want to turn | 276 // RAW_VLOG level we dump key INFO messages at. If you want to turn |
| 277 // off these messages, set the environment variable PERFTOOLS_VERBOSE=-1. | 277 // off these messages, set the environment variable PERFTOOLS_VERBOSE=-1. |
| 278 static const int heap_checker_info_level = 0; | 278 static const int heap_checker_info_level = 0; |
| 279 | 279 |
| 280 //---------------------------------------------------------------------- | 280 //---------------------------------------------------------------------- |
| 281 // Cancel our InitialMallocHook_* if present. | |
| 282 static void CancelInitialMallocHooks(); // defined below | |
| 283 | |
| 284 //---------------------------------------------------------------------- | |
| 285 // HeapLeakChecker's own memory allocator that is | 281 // HeapLeakChecker's own memory allocator that is |
| 286 // independent of the normal program allocator. | 282 // independent of the normal program allocator. |
| 287 //---------------------------------------------------------------------- | 283 //---------------------------------------------------------------------- |
| 288 | 284 |
| 289 // Wrapper of LowLevelAlloc for STL_Allocator and direct use. | 285 // Wrapper of LowLevelAlloc for STL_Allocator and direct use. |
| 290 // We always access this class under held heap_checker_lock, | 286 // We always access this class under held heap_checker_lock, |
| 291 // this allows us to in particular protect the period when threads are stopped | 287 // this allows us to in particular protect the period when threads are stopped |
| 292 // at random spots with ListAllProcessThreads by heap_checker_lock, | 288 // at random spots with ListAllProcessThreads by heap_checker_lock, |
| 293 // w/o worrying about the lock in LowLevelAlloc::Arena. | 289 // w/o worrying about the lock in LowLevelAlloc::Arena. |
| 294 // We rely on the fact that we use an own arena with an own lock here. | 290 // We rely on the fact that we use an own arena with an own lock here. |
| (...skipping 917 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1212 // we can do everything in that main thread, | 1208 // we can do everything in that main thread, |
| 1213 // so that CPU profiler can collect all its samples. | 1209 // so that CPU profiler can collect all its samples. |
| 1214 // Returns the number of threads in the process. | 1210 // Returns the number of threads in the process. |
| 1215 static int IsOneThread(void* parameter, int num_threads, | 1211 static int IsOneThread(void* parameter, int num_threads, |
| 1216 pid_t* thread_pids, va_list ap) { | 1212 pid_t* thread_pids, va_list ap) { |
| 1217 if (num_threads != 1) { | 1213 if (num_threads != 1) { |
| 1218 RAW_LOG(WARNING, "Have threads: Won't CPU-profile the bulk of leak " | 1214 RAW_LOG(WARNING, "Have threads: Won't CPU-profile the bulk of leak " |
| 1219 "checking work happening in IgnoreLiveThreadsLocked!"); | 1215 "checking work happening in IgnoreLiveThreadsLocked!"); |
| 1220 } | 1216 } |
| 1221 ResumeAllProcessThreads(num_threads, thread_pids); | 1217 ResumeAllProcessThreads(num_threads, thread_pids); |
| 1218 RAW_LOG(INFO, "IsOneThread returning %d", num_threads); |
| 1222 return num_threads; | 1219 return num_threads; |
| 1223 } | 1220 } |
| 1224 | 1221 |
| 1225 // Dummy for IgnoreAllLiveObjectsLocked below. | 1222 // Dummy for IgnoreAllLiveObjectsLocked below. |
| 1226 // Making it global helps with compiler warnings. | 1223 // Making it global helps with compiler warnings. |
| 1227 static va_list dummy_ap; | 1224 static va_list dummy_ap; |
| 1228 | 1225 |
| 1229 // static | 1226 // static |
| 1230 void HeapLeakChecker::IgnoreAllLiveObjectsLocked(const void* self_stack_top) { | 1227 void HeapLeakChecker::IgnoreAllLiveObjectsLocked(const void* self_stack_top) { |
| 1231 RAW_DCHECK(heap_checker_lock.IsHeld(), ""); | 1228 RAW_DCHECK(heap_checker_lock.IsHeld(), ""); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1269 bool want_and_can_run_in_main_thread = | 1266 bool want_and_can_run_in_main_thread = |
| 1270 ProfilingIsEnabledForAllThreads() && | 1267 ProfilingIsEnabledForAllThreads() && |
| 1271 ListAllProcessThreads(NULL, IsOneThread) == 1; | 1268 ListAllProcessThreads(NULL, IsOneThread) == 1; |
| 1272 // When the normal path of ListAllProcessThreads below is taken, | 1269 // When the normal path of ListAllProcessThreads below is taken, |
| 1273 // we fully suspend the threads right here before any liveness checking | 1270 // we fully suspend the threads right here before any liveness checking |
| 1274 // and keep them suspended for the whole time of liveness checking | 1271 // and keep them suspended for the whole time of liveness checking |
| 1275 // inside of the IgnoreLiveThreadsLocked callback. | 1272 // inside of the IgnoreLiveThreadsLocked callback. |
| 1276 // (The threads can't (de)allocate due to lock on the delete hook but | 1273 // (The threads can't (de)allocate due to lock on the delete hook but |
| 1277 // if not suspended they could still mess with the pointer | 1274 // if not suspended they could still mess with the pointer |
| 1278 // graph while we walk it). | 1275 // graph while we walk it). |
| 1276 RAW_LOG(INFO, "want_and_can_run_in_main_thread: %d", want_and_can_run_in_mai
n_thread); |
| 1279 int r = want_and_can_run_in_main_thread | 1277 int r = want_and_can_run_in_main_thread |
| 1280 ? IgnoreLiveThreadsLocked(NULL, 1, &self_thread_pid, dummy_ap) | 1278 ? IgnoreLiveThreadsLocked(NULL, 1, &self_thread_pid, dummy_ap) |
| 1281 : ListAllProcessThreads(NULL, IgnoreLiveThreadsLocked); | 1279 : ListAllProcessThreads(NULL, IgnoreLiveThreadsLocked); |
| 1282 need_to_ignore_non_thread_objects = r < 0; | 1280 need_to_ignore_non_thread_objects = r < 0; |
| 1283 if (r < 0) { | 1281 if (r < 0) { |
| 1284 RAW_LOG(WARNING, "Thread finding failed with %d errno=%d", r, errno); | 1282 RAW_LOG(WARNING, "Thread finding failed with %d errno=%d", r, errno); |
| 1285 if (thread_listing_status == CALLBACK_COMPLETED) { | 1283 if (thread_listing_status == CALLBACK_COMPLETED) { |
| 1286 RAW_LOG(INFO, "Thread finding callback " | 1284 RAW_LOG(INFO, "Thread finding callback " |
| 1287 "finished ok; hopefully everything is fine"); | 1285 "finished ok; hopefully everything is fine"); |
| 1288 need_to_ignore_non_thread_objects = false; | 1286 need_to_ignore_non_thread_objects = false; |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1466 if (!HaveOnHeapLocked(&ptr, &object_size)) { | 1464 if (!HaveOnHeapLocked(&ptr, &object_size)) { |
| 1467 RAW_LOG(ERROR, "No live heap object at %p to ignore", ptr); | 1465 RAW_LOG(ERROR, "No live heap object at %p to ignore", ptr); |
| 1468 } else { | 1466 } else { |
| 1469 RAW_VLOG(10, "Going to ignore live object at %p of %"PRIuS" bytes", | 1467 RAW_VLOG(10, "Going to ignore live object at %p of %"PRIuS" bytes", |
| 1470 ptr, object_size); | 1468 ptr, object_size); |
| 1471 if (ignored_objects == NULL) { | 1469 if (ignored_objects == NULL) { |
| 1472 ignored_objects = new(Allocator::Allocate(sizeof(IgnoredObjectsMap))) | 1470 ignored_objects = new(Allocator::Allocate(sizeof(IgnoredObjectsMap))) |
| 1473 IgnoredObjectsMap; | 1471 IgnoredObjectsMap; |
| 1474 } | 1472 } |
| 1475 if (!ignored_objects->insert(make_pair(AsInt(ptr), object_size)).second) { | 1473 if (!ignored_objects->insert(make_pair(AsInt(ptr), object_size)).second) { |
| 1476 RAW_LOG(FATAL, "Object at %p is already being ignored", ptr); | 1474 RAW_LOG(WARNING, "Object at %p is already being ignored", ptr); |
| 1477 } | 1475 } |
| 1478 } | 1476 } |
| 1479 } | 1477 } |
| 1480 | 1478 |
| 1481 // static | 1479 // static |
| 1482 void HeapLeakChecker::UnIgnoreObject(const void* ptr) { | 1480 void HeapLeakChecker::UnIgnoreObject(const void* ptr) { |
| 1483 SpinLockHolder l(&heap_checker_lock); | 1481 SpinLockHolder l(&heap_checker_lock); |
| 1484 if (!heap_checker_on) return; | 1482 if (!heap_checker_on) return; |
| 1485 size_t object_size; | 1483 size_t object_size; |
| 1486 if (!HaveOnHeapLocked(&ptr, &object_size)) { | 1484 if (!HaveOnHeapLocked(&ptr, &object_size)) { |
| (...skipping 802 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2289 // static | 2287 // static |
| 2290 const void* HeapLeakChecker::GetAllocCaller(void* ptr) { | 2288 const void* HeapLeakChecker::GetAllocCaller(void* ptr) { |
| 2291 // this is used only in the unittest, so the heavy checks are fine | 2289 // this is used only in the unittest, so the heavy checks are fine |
| 2292 HeapProfileTable::AllocInfo info; | 2290 HeapProfileTable::AllocInfo info; |
| 2293 { SpinLockHolder l(&heap_checker_lock); | 2291 { SpinLockHolder l(&heap_checker_lock); |
| 2294 RAW_CHECK(heap_profile->FindAllocDetails(ptr, &info), ""); | 2292 RAW_CHECK(heap_profile->FindAllocDetails(ptr, &info), ""); |
| 2295 } | 2293 } |
| 2296 RAW_CHECK(info.stack_depth >= 1, ""); | 2294 RAW_CHECK(info.stack_depth >= 1, ""); |
| 2297 return info.call_stack[0]; | 2295 return info.call_stack[0]; |
| 2298 } | 2296 } |
| OLD | NEW |