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) |
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 |
66 #undef min | 66 #undef min |
67 #endif | 67 #endif |
68 | 68 |
69 #include <string> | 69 #include <string> |
70 #include <vector> | 70 #include <vector> |
71 #include <map> | 71 #include <map> |
72 #include <set> | 72 #include <set> |
73 #include <algorithm> | 73 #include <algorithm> |
74 #include <functional> | 74 #include <functional> |
75 | 75 |
76 #include <google/heap-checker.h> | 76 #include <gperftools/heap-checker.h> |
77 | 77 |
78 #include "base/basictypes.h" | 78 #include "base/basictypes.h" |
79 #include "base/googleinit.h" | 79 #include "base/googleinit.h" |
80 #include "base/logging.h" | 80 #include "base/logging.h" |
81 #include <google/stacktrace.h> | 81 #include <gperftools/stacktrace.h> |
82 #include "base/commandlineflags.h" | 82 #include "base/commandlineflags.h" |
83 #include "base/elfcore.h" // for i386_regs | 83 #include "base/elfcore.h" // for i386_regs |
84 #include "base/thread_lister.h" | 84 #include "base/thread_lister.h" |
85 #include "heap-profile-table.h" | 85 #include "heap-profile-table.h" |
86 #include "base/low_level_alloc.h" | 86 #include "base/low_level_alloc.h" |
87 #include "malloc_hook-inl.h" | 87 #include "malloc_hook-inl.h" |
88 #include <google/malloc_hook.h> | 88 #include <gperftools/malloc_hook.h> |
89 #include <google/malloc_extension.h> | 89 #include <gperftools/malloc_extension.h> |
90 #include "maybe_threads.h" | 90 #include "maybe_threads.h" |
91 #include "memory_region_map.h" | 91 #include "memory_region_map.h" |
92 #include "base/spinlock.h" | 92 #include "base/spinlock.h" |
93 #include "base/sysinfo.h" | 93 #include "base/sysinfo.h" |
94 #include "base/stl_allocator.h" | 94 #include "base/stl_allocator.h" |
95 | 95 |
96 using std::string; | 96 using std::string; |
97 using std::basic_string; | 97 using std::basic_string; |
98 using std::pair; | 98 using std::pair; |
99 using std::map; | 99 using std::map; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
137 //---------------------------------------------------------------------- | 137 //---------------------------------------------------------------------- |
138 // Flags that control heap-checking | 138 // Flags that control heap-checking |
139 //---------------------------------------------------------------------- | 139 //---------------------------------------------------------------------- |
140 | 140 |
141 DEFINE_string(heap_check, | 141 DEFINE_string(heap_check, |
142 EnvToString("HEAPCHECK", ""), | 142 EnvToString("HEAPCHECK", ""), |
143 "The heap leak checking to be done over the whole executable: " | 143 "The heap leak checking to be done over the whole executable: " |
144 "\"minimal\", \"normal\", \"strict\", " | 144 "\"minimal\", \"normal\", \"strict\", " |
145 "\"draconian\", \"as-is\", and \"local\" " | 145 "\"draconian\", \"as-is\", and \"local\" " |
146 " or the empty string are the supported choices. " | 146 " or the empty string are the supported choices. " |
147 "(See HeapLeakChecker::InternalInitStart for details.)"); | 147 "(See HeapLeakChecker_InternalInitStart for details.)"); |
148 | 148 |
149 DEFINE_bool(heap_check_report, true, "Obsolete"); | 149 DEFINE_bool(heap_check_report, true, "Obsolete"); |
150 | 150 |
151 DEFINE_bool(heap_check_before_constructors, | 151 DEFINE_bool(heap_check_before_constructors, |
152 true, | 152 true, |
153 "deprecated; pretty much always true now"); | 153 "deprecated; pretty much always true now"); |
154 | 154 |
155 DEFINE_bool(heap_check_after_destructors, | 155 DEFINE_bool(heap_check_after_destructors, |
156 EnvToBool("HEAP_CHECK_AFTER_DESTRUCTORS", false), | 156 EnvToBool("HEAP_CHECK_AFTER_DESTRUCTORS", false), |
157 "If overall heap check is to end after global destructors " | 157 "If overall heap check is to end after global destructors " |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
275 static pid_t heap_checker_pid = 0; | 275 static pid_t heap_checker_pid = 0; |
276 | 276 |
277 // If we did heap profiling during global constructors execution | 277 // If we did heap profiling during global constructors execution |
278 static bool constructor_heap_profiling = false; | 278 static bool constructor_heap_profiling = false; |
279 | 279 |
280 // RAW_VLOG level we dump key INFO messages at. If you want to turn | 280 // RAW_VLOG level we dump key INFO messages at. If you want to turn |
281 // off these messages, set the environment variable PERFTOOLS_VERBOSE=-1. | 281 // off these messages, set the environment variable PERFTOOLS_VERBOSE=-1. |
282 static const int heap_checker_info_level = 0; | 282 static const int heap_checker_info_level = 0; |
283 | 283 |
284 //---------------------------------------------------------------------- | 284 //---------------------------------------------------------------------- |
285 // Cancel our InitialMallocHook_* if present. | |
286 static void CancelInitialMallocHooks(); // defined below | |
287 | |
288 //---------------------------------------------------------------------- | |
289 // HeapLeakChecker's own memory allocator that is | 285 // HeapLeakChecker's own memory allocator that is |
290 // independent of the normal program allocator. | 286 // independent of the normal program allocator. |
291 //---------------------------------------------------------------------- | 287 //---------------------------------------------------------------------- |
292 | 288 |
293 // Wrapper of LowLevelAlloc for STL_Allocator and direct use. | 289 // Wrapper of LowLevelAlloc for STL_Allocator and direct use. |
294 // We always access this class under held heap_checker_lock, | 290 // We always access this class under held heap_checker_lock, |
295 // this allows us to in particular protect the period when threads are stopped | 291 // this allows us to in particular protect the period when threads are stopped |
296 // at random spots with ListAllProcessThreads by heap_checker_lock, | 292 // at random spots with ListAllProcessThreads by heap_checker_lock, |
297 // w/o worrying about the lock in LowLevelAlloc::Arena. | 293 // w/o worrying about the lock in LowLevelAlloc::Arena. |
298 // We rely on the fact that we use an own arena with an own lock here. | 294 // We rely on the fact that we use an own arena with an own lock here. |
(...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
546 template<typename T> | 542 template<typename T> |
547 inline static const void* AsPtr(T addr) { | 543 inline static const void* AsPtr(T addr) { |
548 return reinterpret_cast<void*>(addr); | 544 return reinterpret_cast<void*>(addr); |
549 } | 545 } |
550 inline static uintptr_t AsInt(const void* ptr) { | 546 inline static uintptr_t AsInt(const void* ptr) { |
551 return reinterpret_cast<uintptr_t>(ptr); | 547 return reinterpret_cast<uintptr_t>(ptr); |
552 } | 548 } |
553 | 549 |
554 //---------------------------------------------------------------------- | 550 //---------------------------------------------------------------------- |
555 | 551 |
| 552 // We've seen reports that strstr causes heap-checker crashes in some |
| 553 // libc's (?): |
| 554 // http://code.google.com/p/gperftools/issues/detail?id=263 |
| 555 // It's simple enough to use our own. This is not in time-critical code. |
| 556 static const char* hc_strstr(const char* s1, const char* s2) { |
| 557 const size_t len = strlen(s2); |
| 558 RAW_CHECK(len > 0, "Unexpected empty string passed to strstr()"); |
| 559 for (const char* p = strchr(s1, *s2); p != NULL; p = strchr(p+1, *s2)) { |
| 560 if (strncmp(p, s2, len) == 0) { |
| 561 return p; |
| 562 } |
| 563 } |
| 564 return NULL; |
| 565 } |
| 566 |
| 567 //---------------------------------------------------------------------- |
| 568 |
556 // Our hooks for MallocHook | 569 // Our hooks for MallocHook |
557 static void NewHook(const void* ptr, size_t size) { | 570 static void NewHook(const void* ptr, size_t size) { |
558 if (ptr != NULL) { | 571 if (ptr != NULL) { |
559 const int counter = get_thread_disable_counter(); | 572 const int counter = get_thread_disable_counter(); |
560 const bool ignore = (counter > 0); | 573 const bool ignore = (counter > 0); |
561 RAW_VLOG(16, "Recording Alloc: %p of %"PRIuS "; %d", ptr, size, | 574 RAW_VLOG(16, "Recording Alloc: %p of %"PRIuS "; %d", ptr, size, |
562 int(counter)); | 575 int(counter)); |
| 576 |
| 577 // Fetch the caller's stack trace before acquiring heap_checker_lock. |
| 578 void* stack[HeapProfileTable::kMaxStackDepth]; |
| 579 int depth = HeapProfileTable::GetCallerStackTrace(0, stack); |
| 580 |
563 { SpinLockHolder l(&heap_checker_lock); | 581 { SpinLockHolder l(&heap_checker_lock); |
564 if (size > max_heap_object_size) max_heap_object_size = size; | 582 if (size > max_heap_object_size) max_heap_object_size = size; |
565 uintptr_t addr = AsInt(ptr); | 583 uintptr_t addr = AsInt(ptr); |
566 if (addr < min_heap_address) min_heap_address = addr; | 584 if (addr < min_heap_address) min_heap_address = addr; |
567 addr += size; | 585 addr += size; |
568 if (addr > max_heap_address) max_heap_address = addr; | 586 if (addr > max_heap_address) max_heap_address = addr; |
569 if (heap_checker_on) { | 587 if (heap_checker_on) { |
570 heap_profile->RecordAlloc(ptr, size, 0); | 588 heap_profile->RecordAlloc(ptr, size, depth, stack); |
571 if (ignore) { | 589 if (ignore) { |
572 heap_profile->MarkAsIgnored(ptr); | 590 heap_profile->MarkAsIgnored(ptr); |
573 } | 591 } |
574 } | 592 } |
575 } | 593 } |
576 RAW_VLOG(17, "Alloc Recorded: %p of %"PRIuS"", ptr, size); | 594 RAW_VLOG(17, "Alloc Recorded: %p of %"PRIuS"", ptr, size); |
577 } | 595 } |
578 } | 596 } |
579 | 597 |
580 static void DeleteHook(const void* ptr) { | 598 static void DeleteHook(const void* ptr) { |
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
763 return; | 781 return; |
764 } | 782 } |
765 } | 783 } |
766 RAW_VLOG(11, "%s-disabling %"PRIuS" bytes at %p", | 784 RAW_VLOG(11, "%s-disabling %"PRIuS" bytes at %p", |
767 (stack_disable ? "Stack" : "Range"), info.object_size, ptr); | 785 (stack_disable ? "Stack" : "Range"), info.object_size, ptr); |
768 live_objects->push_back(AllocObject(ptr, info.object_size, | 786 live_objects->push_back(AllocObject(ptr, info.object_size, |
769 MUST_BE_ON_HEAP)); | 787 MUST_BE_ON_HEAP)); |
770 } | 788 } |
771 } | 789 } |
772 | 790 |
| 791 static const char kUnnamedProcSelfMapEntry[] = "UNNAMED"; |
| 792 |
773 // This function takes some fields from a /proc/self/maps line: | 793 // This function takes some fields from a /proc/self/maps line: |
774 // | 794 // |
775 // start_address start address of a memory region. | 795 // start_address start address of a memory region. |
776 // end_address end address of a memory region | 796 // end_address end address of a memory region |
777 // permissions rwx + private/shared bit | 797 // permissions rwx + private/shared bit |
778 // filename filename of the mapped file | 798 // filename filename of the mapped file |
779 // | 799 // |
780 // If the region is not writeable, then it cannot have any heap | 800 // If the region is not writeable, then it cannot have any heap |
781 // pointers in it, otherwise we record it as a candidate live region | 801 // pointers in it, otherwise we record it as a candidate live region |
782 // to get filtered later. | 802 // to get filtered later. |
783 static void RecordGlobalDataLocked(uintptr_t start_address, | 803 static void RecordGlobalDataLocked(uintptr_t start_address, |
784 uintptr_t end_address, | 804 uintptr_t end_address, |
785 const char* permissions, | 805 const char* permissions, |
786 const char* filename) { | 806 const char* filename) { |
787 RAW_DCHECK(heap_checker_lock.IsHeld(), ""); | 807 RAW_DCHECK(heap_checker_lock.IsHeld(), ""); |
788 // Ignore non-writeable regions. | 808 // Ignore non-writeable regions. |
789 if (strchr(permissions, 'w') == NULL) return; | 809 if (strchr(permissions, 'w') == NULL) return; |
790 if (filename == NULL || *filename == '\0') filename = "UNNAMED"; | 810 if (filename == NULL || *filename == '\0') { |
| 811 filename = kUnnamedProcSelfMapEntry; |
| 812 } |
791 RAW_VLOG(11, "Looking into %s: 0x%" PRIxPTR "..0x%" PRIxPTR, | 813 RAW_VLOG(11, "Looking into %s: 0x%" PRIxPTR "..0x%" PRIxPTR, |
792 filename, start_address, end_address); | 814 filename, start_address, end_address); |
793 (*library_live_objects)[filename]. | 815 (*library_live_objects)[filename]. |
794 push_back(AllocObject(AsPtr(start_address), | 816 push_back(AllocObject(AsPtr(start_address), |
795 end_address - start_address, | 817 end_address - start_address, |
796 MAYBE_LIVE)); | 818 MAYBE_LIVE)); |
797 } | 819 } |
798 | 820 |
799 // See if 'library' from /proc/self/maps has base name 'library_base' | 821 // See if 'library' from /proc/self/maps has base name 'library_base' |
800 // i.e. contains it and has '.' or '-' after it. | 822 // i.e. contains it and has '.' or '-' after it. |
801 static bool IsLibraryNamed(const char* library, const char* library_base) { | 823 static bool IsLibraryNamed(const char* library, const char* library_base) { |
802 const char* p = strstr(library, library_base); | 824 const char* p = hc_strstr(library, library_base); |
803 size_t sz = strlen(library_base); | 825 size_t sz = strlen(library_base); |
804 return p != NULL && (p[sz] == '.' || p[sz] == '-'); | 826 return p != NULL && (p[sz] == '.' || p[sz] == '-'); |
805 } | 827 } |
806 | 828 |
807 // static | 829 // static |
808 void HeapLeakChecker::DisableLibraryAllocsLocked(const char* library, | 830 void HeapLeakChecker::DisableLibraryAllocsLocked(const char* library, |
809 uintptr_t start_address, | 831 uintptr_t start_address, |
810 uintptr_t end_address) { | 832 uintptr_t end_address) { |
811 RAW_DCHECK(heap_checker_lock.IsHeld(), ""); | 833 RAW_DCHECK(heap_checker_lock.IsHeld(), ""); |
812 int depth = 0; | 834 int depth = 0; |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
904 continue; | 926 continue; |
905 } | 927 } |
906 // Determine if any shared libraries are present (this is the same | 928 // Determine if any shared libraries are present (this is the same |
907 // list of extensions as is found in pprof). We want to ignore | 929 // list of extensions as is found in pprof). We want to ignore |
908 // 'fake' libraries with inode 0 when determining. However, some | 930 // 'fake' libraries with inode 0 when determining. However, some |
909 // systems don't share inodes via /proc, so we turn off this check | 931 // systems don't share inodes via /proc, so we turn off this check |
910 // if we don't see any evidence that we're getting inode info. | 932 // if we don't see any evidence that we're getting inode info. |
911 if (inode != 0) { | 933 if (inode != 0) { |
912 saw_nonzero_inode = true; | 934 saw_nonzero_inode = true; |
913 } | 935 } |
914 if ((strstr(filename, "lib") && strstr(filename, ".so")) || | 936 if ((hc_strstr(filename, "lib") && hc_strstr(filename, ".so")) || |
915 strstr(filename, ".dll") || | 937 hc_strstr(filename, ".dll") || |
916 // not all .dylib filenames start with lib. .dylib is big enough | 938 // not all .dylib filenames start with lib. .dylib is big enough |
917 // that we are unlikely to get false matches just checking that. | 939 // that we are unlikely to get false matches just checking that. |
918 strstr(filename, ".dylib") || strstr(filename, ".bundle")) { | 940 hc_strstr(filename, ".dylib") || hc_strstr(filename, ".bundle")) { |
919 saw_shared_lib = true; | 941 saw_shared_lib = true; |
920 if (inode != 0) { | 942 if (inode != 0) { |
921 saw_shared_lib_with_nonzero_inode = true; | 943 saw_shared_lib_with_nonzero_inode = true; |
922 } | 944 } |
923 } | 945 } |
924 | 946 |
925 switch (proc_maps_task) { | 947 switch (proc_maps_task) { |
926 case DISABLE_LIBRARY_ALLOCS: | 948 case DISABLE_LIBRARY_ALLOCS: |
927 // All lines starting like | 949 // All lines starting like |
928 // "401dc000-4030f000 r??p 00132000 03:01 13991972 lib/bin" | 950 // "401dc000-4030f000 r??p 00132000 03:01 13991972 lib/bin" |
(...skipping 455 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1384 const size_t remainder = AsInt(object) % pointer_source_alignment; | 1406 const size_t remainder = AsInt(object) % pointer_source_alignment; |
1385 if (remainder) { | 1407 if (remainder) { |
1386 object += pointer_source_alignment - remainder; | 1408 object += pointer_source_alignment - remainder; |
1387 if (size >= pointer_source_alignment - remainder) { | 1409 if (size >= pointer_source_alignment - remainder) { |
1388 size -= pointer_source_alignment - remainder; | 1410 size -= pointer_source_alignment - remainder; |
1389 } else { | 1411 } else { |
1390 size = 0; | 1412 size = 0; |
1391 } | 1413 } |
1392 } | 1414 } |
1393 if (size < sizeof(void*)) continue; | 1415 if (size < sizeof(void*)) continue; |
| 1416 |
| 1417 #ifdef NO_FRAME_POINTER |
| 1418 // Frame pointer omission requires us to use libunwind, which uses direct |
| 1419 // mmap and munmap system calls, and that needs special handling. |
| 1420 if (name2 == kUnnamedProcSelfMapEntry) { |
| 1421 static const uintptr_t page_mask = ~(getpagesize() - 1); |
| 1422 const uintptr_t addr = reinterpret_cast<uintptr_t>(object); |
| 1423 if ((addr & page_mask) == 0 && (size & page_mask) == 0) { |
| 1424 // This is an object we slurped from /proc/self/maps. |
| 1425 // It may or may not be readable at this point. |
| 1426 // |
| 1427 // In case all the above conditions made a mistake, and the object is |
| 1428 // not related to libunwind, we also verify that it's not readable |
| 1429 // before ignoring it. |
| 1430 if (msync(const_cast<char*>(object), size, MS_ASYNC) != 0) { |
| 1431 // Skip unreadable object, so we don't crash trying to sweep it. |
| 1432 RAW_VLOG(0, "Ignoring inaccessible object [%p, %p) " |
| 1433 "(msync error %d (%s))", |
| 1434 object, object + size, errno, strerror(errno)); |
| 1435 continue; |
| 1436 } |
| 1437 } |
| 1438 } |
| 1439 #endif |
| 1440 |
1394 const char* const max_object = object + size - sizeof(void*); | 1441 const char* const max_object = object + size - sizeof(void*); |
1395 while (object <= max_object) { | 1442 while (object <= max_object) { |
1396 // potentially unaligned load: | 1443 // potentially unaligned load: |
1397 const uintptr_t addr = *reinterpret_cast<const uintptr_t*>(object); | 1444 const uintptr_t addr = *reinterpret_cast<const uintptr_t*>(object); |
1398 // Do fast check before the more expensive HaveOnHeapLocked lookup: | 1445 // Do fast check before the more expensive HaveOnHeapLocked lookup: |
1399 // this code runs for all memory words that are potentially pointers: | 1446 // this code runs for all memory words that are potentially pointers: |
1400 const bool can_be_on_heap = | 1447 const bool can_be_on_heap = |
1401 // Order tests by the likelyhood of the test failing in 64/32 bit modes. | 1448 // Order tests by the likelyhood of the test failing in 64/32 bit modes. |
1402 // Yes, this matters: we either lose 5..6% speed in 32 bit mode | 1449 // Yes, this matters: we either lose 5..6% speed in 32 bit mode |
1403 // (which is already slower) or by a factor of 1.5..1.91 in 64 bit mode. | 1450 // (which is already slower) or by a factor of 1.5..1.91 in 64 bit mode. |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1456 //---------------------------------------------------------------------- | 1503 //---------------------------------------------------------------------- |
1457 // HeapLeakChecker leak check disabling components | 1504 // HeapLeakChecker leak check disabling components |
1458 //---------------------------------------------------------------------- | 1505 //---------------------------------------------------------------------- |
1459 | 1506 |
1460 // static | 1507 // static |
1461 void HeapLeakChecker::DisableChecksIn(const char* pattern) { | 1508 void HeapLeakChecker::DisableChecksIn(const char* pattern) { |
1462 RAW_LOG(WARNING, "DisableChecksIn(%s) is ignored", pattern); | 1509 RAW_LOG(WARNING, "DisableChecksIn(%s) is ignored", pattern); |
1463 } | 1510 } |
1464 | 1511 |
1465 // static | 1512 // static |
1466 void HeapLeakChecker::IgnoreObject(const void* ptr) { | 1513 void HeapLeakChecker::DoIgnoreObject(const void* ptr) { |
1467 SpinLockHolder l(&heap_checker_lock); | 1514 SpinLockHolder l(&heap_checker_lock); |
1468 if (!heap_checker_on) return; | 1515 if (!heap_checker_on) return; |
1469 size_t object_size; | 1516 size_t object_size; |
1470 if (!HaveOnHeapLocked(&ptr, &object_size)) { | 1517 if (!HaveOnHeapLocked(&ptr, &object_size)) { |
1471 RAW_LOG(ERROR, "No live heap object at %p to ignore", ptr); | 1518 RAW_LOG(ERROR, "No live heap object at %p to ignore", ptr); |
1472 } else { | 1519 } else { |
1473 RAW_VLOG(10, "Going to ignore live object at %p of %"PRIuS" bytes", | 1520 RAW_VLOG(10, "Going to ignore live object at %p of %"PRIuS" bytes", |
1474 ptr, object_size); | 1521 ptr, object_size); |
1475 if (ignored_objects == NULL) { | 1522 if (ignored_objects == NULL) { |
1476 ignored_objects = new(Allocator::Allocate(sizeof(IgnoredObjectsMap))) | 1523 ignored_objects = new(Allocator::Allocate(sizeof(IgnoredObjectsMap))) |
1477 IgnoredObjectsMap; | 1524 IgnoredObjectsMap; |
1478 } | 1525 } |
1479 if (!ignored_objects->insert(make_pair(AsInt(ptr), object_size)).second) { | 1526 if (!ignored_objects->insert(make_pair(AsInt(ptr), object_size)).second) { |
1480 RAW_LOG(FATAL, "Object at %p is already being ignored", ptr); | 1527 RAW_LOG(WARNING, "Object at %p is already being ignored", ptr); |
1481 } | 1528 } |
1482 } | 1529 } |
1483 } | 1530 } |
1484 | 1531 |
1485 // static | 1532 // static |
1486 void HeapLeakChecker::UnIgnoreObject(const void* ptr) { | 1533 void HeapLeakChecker::UnIgnoreObject(const void* ptr) { |
1487 SpinLockHolder l(&heap_checker_lock); | 1534 SpinLockHolder l(&heap_checker_lock); |
1488 if (!heap_checker_on) return; | 1535 if (!heap_checker_on) return; |
1489 size_t object_size; | 1536 size_t object_size; |
1490 if (!HaveOnHeapLocked(&ptr, &object_size)) { | 1537 if (!HaveOnHeapLocked(&ptr, &object_size)) { |
(...skipping 369 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1860 if (!heap_cleanups_) | 1907 if (!heap_cleanups_) |
1861 return; | 1908 return; |
1862 for (int i = 0; i < heap_cleanups_->size(); i++) { | 1909 for (int i = 0; i < heap_cleanups_->size(); i++) { |
1863 void (*f)(void) = (*heap_cleanups_)[i]; | 1910 void (*f)(void) = (*heap_cleanups_)[i]; |
1864 f(); | 1911 f(); |
1865 } | 1912 } |
1866 delete heap_cleanups_; | 1913 delete heap_cleanups_; |
1867 heap_cleanups_ = NULL; | 1914 heap_cleanups_ = NULL; |
1868 } | 1915 } |
1869 | 1916 |
1870 // Program exit heap cleanup registered with atexit(). | 1917 // Program exit heap cleanup registered as a module object destructor. |
1871 // Will not get executed when we crash on a signal. | 1918 // Will not get executed when we crash on a signal. |
1872 // | 1919 // |
1873 /*static*/ void HeapLeakChecker::RunHeapCleanups() { | 1920 void HeapLeakChecker_RunHeapCleanups() { |
| 1921 if (FLAGS_heap_check == "local") // don't check heap in this mode |
| 1922 return; |
1874 { SpinLockHolder l(&heap_checker_lock); | 1923 { SpinLockHolder l(&heap_checker_lock); |
1875 // can get here (via forks?) with other pids | 1924 // can get here (via forks?) with other pids |
1876 if (heap_checker_pid != getpid()) return; | 1925 if (heap_checker_pid != getpid()) return; |
1877 } | 1926 } |
1878 HeapCleaner::RunHeapCleanups(); | 1927 HeapCleaner::RunHeapCleanups(); |
1879 if (!FLAGS_heap_check_after_destructors) DoMainHeapCheck(); | 1928 if (!FLAGS_heap_check_after_destructors) HeapLeakChecker::DoMainHeapCheck(); |
1880 } | 1929 } |
1881 | 1930 |
1882 static bool internal_init_start_has_run = false; | 1931 static bool internal_init_start_has_run = false; |
1883 | 1932 |
1884 // Called exactly once, before main() (but hopefully just before). | 1933 // Called exactly once, before main() (but hopefully just before). |
1885 // This picks a good unique name for the dumped leak checking heap profiles. | 1934 // This picks a good unique name for the dumped leak checking heap profiles. |
1886 // | 1935 // |
1887 // Because we crash when InternalInitStart is called more than once, | 1936 // Because we crash when InternalInitStart is called more than once, |
1888 // it's fine that we hold heap_checker_lock only around pieces of | 1937 // it's fine that we hold heap_checker_lock only around pieces of |
1889 // this function: this is still enough for thread-safety w.r.t. other functions | 1938 // this function: this is still enough for thread-safety w.r.t. other functions |
1890 // of this module. | 1939 // of this module. |
1891 // We can't hold heap_checker_lock throughout because it would deadlock | 1940 // We can't hold heap_checker_lock throughout because it would deadlock |
1892 // on a memory allocation since our new/delete hooks can be on. | 1941 // on a memory allocation since our new/delete hooks can be on. |
1893 // | 1942 // |
1894 /*static*/ void HeapLeakChecker::InternalInitStart() { | 1943 void HeapLeakChecker_InternalInitStart() { |
1895 { SpinLockHolder l(&heap_checker_lock); | 1944 { SpinLockHolder l(&heap_checker_lock); |
1896 RAW_CHECK(!internal_init_start_has_run, | 1945 RAW_CHECK(!internal_init_start_has_run, |
1897 "Heap-check constructor called twice. Perhaps you both linked" | 1946 "Heap-check constructor called twice. Perhaps you both linked" |
1898 " in the heap checker, and also used LD_PRELOAD to load it?"); | 1947 " in the heap checker, and also used LD_PRELOAD to load it?"); |
1899 internal_init_start_has_run = true; | 1948 internal_init_start_has_run = true; |
1900 | 1949 |
| 1950 #ifdef ADDRESS_SANITIZER |
| 1951 // AddressSanitizer's custom malloc conflicts with HeapChecker. |
| 1952 FLAGS_heap_check = ""; |
| 1953 #endif |
| 1954 |
1901 if (FLAGS_heap_check.empty()) { | 1955 if (FLAGS_heap_check.empty()) { |
1902 // turns out we do not need checking in the end; can stop profiling | 1956 // turns out we do not need checking in the end; can stop profiling |
1903 TurnItselfOffLocked(); | 1957 HeapLeakChecker::TurnItselfOffLocked(); |
1904 return; | 1958 return; |
1905 } else if (RunningOnValgrind()) { | 1959 } else if (RunningOnValgrind()) { |
1906 // There is no point in trying -- we'll just fail. | 1960 // There is no point in trying -- we'll just fail. |
1907 RAW_LOG(WARNING, "Can't run under Valgrind; will turn itself off"); | 1961 RAW_LOG(WARNING, "Can't run under Valgrind; will turn itself off"); |
1908 TurnItselfOffLocked(); | 1962 HeapLeakChecker::TurnItselfOffLocked(); |
1909 return; | 1963 return; |
1910 } | 1964 } |
1911 } | 1965 } |
1912 | 1966 |
1913 // Changing this to false can be useful when debugging heap-checker itself: | 1967 // Changing this to false can be useful when debugging heap-checker itself: |
1914 if (!FLAGS_heap_check_run_under_gdb && IsDebuggerAttached()) { | 1968 if (!FLAGS_heap_check_run_under_gdb && IsDebuggerAttached()) { |
1915 RAW_LOG(WARNING, "Someone is ptrace()ing us; will turn itself off"); | 1969 RAW_LOG(WARNING, "Someone is ptrace()ing us; will turn itself off"); |
1916 SpinLockHolder l(&heap_checker_lock); | 1970 SpinLockHolder l(&heap_checker_lock); |
1917 TurnItselfOffLocked(); | 1971 HeapLeakChecker::TurnItselfOffLocked(); |
1918 return; | 1972 return; |
1919 } | 1973 } |
1920 | 1974 |
1921 { SpinLockHolder l(&heap_checker_lock); | 1975 { SpinLockHolder l(&heap_checker_lock); |
1922 if (!constructor_heap_profiling) { | 1976 if (!constructor_heap_profiling) { |
1923 RAW_LOG(FATAL, "Can not start so late. You have to enable heap checking " | 1977 RAW_LOG(FATAL, "Can not start so late. You have to enable heap checking " |
1924 "with HEAPCHECK=<mode>."); | 1978 "with HEAPCHECK=<mode>."); |
1925 } | 1979 } |
1926 } | 1980 } |
1927 | 1981 |
(...skipping 30 matching lines...) Expand all Loading... |
1958 FLAGS_heap_check_ignore_thread_live = false; // no live flood (stricter) | 2012 FLAGS_heap_check_ignore_thread_live = false; // no live flood (stricter) |
1959 FLAGS_heap_check_ignore_global_live = false; // no live flood (stricter) | 2013 FLAGS_heap_check_ignore_global_live = false; // no live flood (stricter) |
1960 } else if (FLAGS_heap_check == "as-is") { | 2014 } else if (FLAGS_heap_check == "as-is") { |
1961 // do nothing: use other flags as is | 2015 // do nothing: use other flags as is |
1962 } else if (FLAGS_heap_check == "local") { | 2016 } else if (FLAGS_heap_check == "local") { |
1963 // do nothing | 2017 // do nothing |
1964 } else { | 2018 } else { |
1965 RAW_LOG(FATAL, "Unsupported heap_check flag: %s", | 2019 RAW_LOG(FATAL, "Unsupported heap_check flag: %s", |
1966 FLAGS_heap_check.c_str()); | 2020 FLAGS_heap_check.c_str()); |
1967 } | 2021 } |
| 2022 // FreeBSD doesn't seem to honor atexit execution order: |
| 2023 // http://code.google.com/p/gperftools/issues/detail?id=375 |
| 2024 // Since heap-checking before destructors depends on atexit running |
| 2025 // at the right time, on FreeBSD we always check after, even in the |
| 2026 // less strict modes. This just means FreeBSD is always a bit |
| 2027 // stricter in its checking than other OSes. |
| 2028 #ifdef __FreeBSD__ |
| 2029 FLAGS_heap_check_after_destructors = true; |
| 2030 #endif |
| 2031 |
1968 { SpinLockHolder l(&heap_checker_lock); | 2032 { SpinLockHolder l(&heap_checker_lock); |
1969 RAW_DCHECK(heap_checker_pid == getpid(), ""); | 2033 RAW_DCHECK(heap_checker_pid == getpid(), ""); |
1970 heap_checker_on = true; | 2034 heap_checker_on = true; |
1971 RAW_DCHECK(heap_profile, ""); | 2035 RAW_DCHECK(heap_profile, ""); |
1972 ProcMapsResult pm_result = UseProcMapsLocked(DISABLE_LIBRARY_ALLOCS); | 2036 HeapLeakChecker::ProcMapsResult pm_result = HeapLeakChecker::UseProcMapsLock
ed(HeapLeakChecker::DISABLE_LIBRARY_ALLOCS); |
1973 // might neeed to do this more than once | 2037 // might neeed to do this more than once |
1974 // if one later dynamically loads libraries that we want disabled | 2038 // if one later dynamically loads libraries that we want disabled |
1975 if (pm_result != PROC_MAPS_USED) { // can't function | 2039 if (pm_result != HeapLeakChecker::PROC_MAPS_USED) { // can't function |
1976 TurnItselfOffLocked(); | 2040 HeapLeakChecker::TurnItselfOffLocked(); |
1977 return; | 2041 return; |
1978 } | 2042 } |
1979 } | 2043 } |
1980 | 2044 |
1981 // make a good place and name for heap profile leak dumps | 2045 // make a good place and name for heap profile leak dumps |
1982 string* profile_prefix = | 2046 string* profile_prefix = |
1983 new string(FLAGS_heap_check_dump_directory + "/" + invocation_name()); | 2047 new string(FLAGS_heap_check_dump_directory + "/" + invocation_name()); |
1984 | 2048 |
1985 // Finalize prefix for dumping leak checking profiles. | 2049 // Finalize prefix for dumping leak checking profiles. |
1986 const int32 our_pid = getpid(); // safest to call getpid() outside lock | 2050 const int32 our_pid = getpid(); // safest to call getpid() outside lock |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2020 // "nm <this_binary> | grep new" will show that tcmalloc's new/delete | 2084 // "nm <this_binary> | grep new" will show that tcmalloc's new/delete |
2021 // implementation did not get linked-in into this binary | 2085 // implementation did not get linked-in into this binary |
2022 // (i.e. nm will list __builtin_new and __builtin_vec_new as undefined). | 2086 // (i.e. nm will list __builtin_new and __builtin_vec_new as undefined). |
2023 // If this happens, it is a BUILD bug to be fixed. | 2087 // If this happens, it is a BUILD bug to be fixed. |
2024 | 2088 |
2025 RAW_VLOG(heap_checker_info_level, | 2089 RAW_VLOG(heap_checker_info_level, |
2026 "WARNING: Perftools heap leak checker is active " | 2090 "WARNING: Perftools heap leak checker is active " |
2027 "-- Performance may suffer"); | 2091 "-- Performance may suffer"); |
2028 | 2092 |
2029 if (FLAGS_heap_check != "local") { | 2093 if (FLAGS_heap_check != "local") { |
2030 // Schedule registered heap cleanup | |
2031 atexit(RunHeapCleanups); | |
2032 HeapLeakChecker* main_hc = new HeapLeakChecker(); | 2094 HeapLeakChecker* main_hc = new HeapLeakChecker(); |
2033 SpinLockHolder l(&heap_checker_lock); | 2095 SpinLockHolder l(&heap_checker_lock); |
2034 RAW_DCHECK(main_heap_checker == NULL, | 2096 RAW_DCHECK(main_heap_checker == NULL, |
2035 "Repeated creation of main_heap_checker"); | 2097 "Repeated creation of main_heap_checker"); |
2036 main_heap_checker = main_hc; | 2098 main_heap_checker = main_hc; |
2037 do_main_heap_check = true; | 2099 do_main_heap_check = true; |
2038 } | 2100 } |
2039 | 2101 |
2040 { SpinLockHolder l(&heap_checker_lock); | 2102 { SpinLockHolder l(&heap_checker_lock); |
2041 RAW_CHECK(heap_checker_on && constructor_heap_profiling, | 2103 RAW_CHECK(heap_checker_on && constructor_heap_profiling, |
(...skipping 12 matching lines...) Expand all Loading... |
2054 // TODO(csilvers): support this in some manner. | 2116 // TODO(csilvers): support this in some manner. |
2055 #if 0 | 2117 #if 0 |
2056 SetCommandLineOptionWithMode("max_free_queue_size", "104857600", // 100M | 2118 SetCommandLineOptionWithMode("max_free_queue_size", "104857600", // 100M |
2057 SET_FLAG_IF_DEFAULT); | 2119 SET_FLAG_IF_DEFAULT); |
2058 #endif | 2120 #endif |
2059 } | 2121 } |
2060 | 2122 |
2061 // We want this to run early as well, but not so early as | 2123 // We want this to run early as well, but not so early as |
2062 // ::BeforeConstructors (we want flag assignments to have already | 2124 // ::BeforeConstructors (we want flag assignments to have already |
2063 // happened, for instance). Initializer-registration does the trick. | 2125 // happened, for instance). Initializer-registration does the trick. |
2064 REGISTER_MODULE_INITIALIZER(init_start, HeapLeakChecker::InternalInitStart()); | 2126 REGISTER_MODULE_INITIALIZER(init_start, HeapLeakChecker_InternalInitStart()); |
| 2127 REGISTER_MODULE_DESTRUCTOR(init_start, HeapLeakChecker_RunHeapCleanups()); |
| 2128 |
| 2129 // static |
| 2130 bool HeapLeakChecker::NoGlobalLeaksMaybeSymbolize( |
| 2131 ShouldSymbolize should_symbolize) { |
| 2132 // we never delete or change main_heap_checker once it's set: |
| 2133 HeapLeakChecker* main_hc = GlobalChecker(); |
| 2134 if (main_hc) { |
| 2135 RAW_VLOG(10, "Checking for whole-program memory leaks"); |
| 2136 return main_hc->DoNoLeaks(should_symbolize); |
| 2137 } |
| 2138 return true; |
| 2139 } |
2065 | 2140 |
2066 // static | 2141 // static |
2067 bool HeapLeakChecker::DoMainHeapCheck() { | 2142 bool HeapLeakChecker::DoMainHeapCheck() { |
2068 if (FLAGS_heap_check_delay_seconds > 0) { | 2143 if (FLAGS_heap_check_delay_seconds > 0) { |
2069 sleep(FLAGS_heap_check_delay_seconds); | 2144 sleep(FLAGS_heap_check_delay_seconds); |
2070 } | 2145 } |
2071 { SpinLockHolder l(&heap_checker_lock); | 2146 { SpinLockHolder l(&heap_checker_lock); |
2072 if (!do_main_heap_check) return false; | 2147 if (!do_main_heap_check) return false; |
2073 RAW_DCHECK(heap_checker_pid == getpid(), ""); | 2148 RAW_DCHECK(heap_checker_pid == getpid(), ""); |
2074 do_main_heap_check = false; // will do it now; no need to do it more | 2149 do_main_heap_check = false; // will do it now; no need to do it more |
2075 } | 2150 } |
2076 | 2151 |
2077 if (!NoGlobalLeaks()) { | 2152 // The program is over, so it's safe to symbolize addresses (which |
| 2153 // requires a fork) because no serious work is expected to be done |
| 2154 // after this. Symbolizing is really useful -- knowing what |
| 2155 // function has a leak is better than knowing just an address -- |
| 2156 // and while we can only safely symbolize once in a program run, |
| 2157 // now is the time (after all, there's no "later" that would be better). |
| 2158 if (!NoGlobalLeaksMaybeSymbolize(SYMBOLIZE)) { |
2078 if (FLAGS_heap_check_identify_leaks) { | 2159 if (FLAGS_heap_check_identify_leaks) { |
2079 RAW_LOG(FATAL, "Whole-program memory leaks found."); | 2160 RAW_LOG(FATAL, "Whole-program memory leaks found."); |
2080 } | 2161 } |
2081 RAW_LOG(ERROR, "Exiting with error code (instead of crashing) " | 2162 RAW_LOG(ERROR, "Exiting with error code (instead of crashing) " |
2082 "because of whole-program memory leaks"); | 2163 "because of whole-program memory leaks"); |
2083 // We don't want to call atexit() routines! | 2164 // We don't want to call atexit() routines! |
2084 _exit(FLAGS_heap_check_error_exit_code); | 2165 _exit(FLAGS_heap_check_error_exit_code); |
2085 } | 2166 } |
2086 return true; | 2167 return true; |
2087 } | 2168 } |
2088 | 2169 |
2089 // static | 2170 // static |
2090 HeapLeakChecker* HeapLeakChecker::GlobalChecker() { | 2171 HeapLeakChecker* HeapLeakChecker::GlobalChecker() { |
2091 SpinLockHolder l(&heap_checker_lock); | 2172 SpinLockHolder l(&heap_checker_lock); |
2092 return main_heap_checker; | 2173 return main_heap_checker; |
2093 } | 2174 } |
2094 | 2175 |
2095 // static | 2176 // static |
2096 bool HeapLeakChecker::NoGlobalLeaks() { | 2177 bool HeapLeakChecker::NoGlobalLeaks() { |
2097 // we never delete or change main_heap_checker once it's set: | 2178 // symbolizing requires a fork, which isn't safe to do in general. |
2098 HeapLeakChecker* main_hc = GlobalChecker(); | 2179 return NoGlobalLeaksMaybeSymbolize(DO_NOT_SYMBOLIZE); |
2099 if (main_hc) { | |
2100 RAW_VLOG(10, "Checking for whole-program memory leaks"); | |
2101 // The program is over, so it's safe to symbolize addresses (which | |
2102 // requires a fork) because no serious work is expected to be done | |
2103 // after this. Symbolizing is really useful -- knowing what | |
2104 // function has a leak is better than knowing just an address -- | |
2105 // and while we can only safely symbolize once in a program run, | |
2106 // now is the time (after all, there's no "later" that would be better). | |
2107 return main_hc->DoNoLeaks(SYMBOLIZE); | |
2108 } | |
2109 return true; | |
2110 } | 2180 } |
2111 | 2181 |
2112 // static | 2182 // static |
2113 void HeapLeakChecker::CancelGlobalCheck() { | 2183 void HeapLeakChecker::CancelGlobalCheck() { |
2114 SpinLockHolder l(&heap_checker_lock); | 2184 SpinLockHolder l(&heap_checker_lock); |
2115 if (do_main_heap_check) { | 2185 if (do_main_heap_check) { |
2116 RAW_VLOG(heap_checker_info_level, | 2186 RAW_VLOG(heap_checker_info_level, |
2117 "Canceling the automatic at-exit whole-program memory leak check"); | 2187 "Canceling the automatic at-exit whole-program memory leak check"); |
2118 do_main_heap_check = false; | 2188 do_main_heap_check = false; |
2119 } | 2189 } |
2120 } | 2190 } |
2121 | 2191 |
2122 // static | 2192 // static |
2123 void HeapLeakChecker::BeforeConstructorsLocked() { | 2193 void HeapLeakChecker::BeforeConstructorsLocked() { |
2124 RAW_DCHECK(heap_checker_lock.IsHeld(), ""); | 2194 RAW_DCHECK(heap_checker_lock.IsHeld(), ""); |
2125 RAW_CHECK(!constructor_heap_profiling, | 2195 RAW_CHECK(!constructor_heap_profiling, |
2126 "BeforeConstructorsLocked called multiple times"); | 2196 "BeforeConstructorsLocked called multiple times"); |
| 2197 #ifdef ADDRESS_SANITIZER |
| 2198 // AddressSanitizer's custom malloc conflicts with HeapChecker. |
| 2199 return; |
| 2200 #endif |
2127 // Set hooks early to crash if 'new' gets called before we make heap_profile, | 2201 // Set hooks early to crash if 'new' gets called before we make heap_profile, |
2128 // and make sure no other hooks existed: | 2202 // and make sure no other hooks existed: |
2129 RAW_CHECK(MallocHook::AddNewHook(&NewHook), ""); | 2203 RAW_CHECK(MallocHook::AddNewHook(&NewHook), ""); |
2130 RAW_CHECK(MallocHook::AddDeleteHook(&DeleteHook), ""); | 2204 RAW_CHECK(MallocHook::AddDeleteHook(&DeleteHook), ""); |
2131 constructor_heap_profiling = true; | 2205 constructor_heap_profiling = true; |
2132 MemoryRegionMap::Init(1); | 2206 MemoryRegionMap::Init(1); |
2133 // Set up MemoryRegionMap with (at least) one caller stack frame to record | 2207 // Set up MemoryRegionMap with (at least) one caller stack frame to record |
2134 // (important that it's done before HeapProfileTable creation below). | 2208 // (important that it's done before HeapProfileTable creation below). |
2135 Allocator::Init(); | 2209 Allocator::Init(); |
2136 RAW_CHECK(heap_profile == NULL, ""); | 2210 RAW_CHECK(heap_profile == NULL, ""); |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2294 // static | 2368 // static |
2295 const void* HeapLeakChecker::GetAllocCaller(void* ptr) { | 2369 const void* HeapLeakChecker::GetAllocCaller(void* ptr) { |
2296 // this is used only in the unittest, so the heavy checks are fine | 2370 // this is used only in the unittest, so the heavy checks are fine |
2297 HeapProfileTable::AllocInfo info; | 2371 HeapProfileTable::AllocInfo info; |
2298 { SpinLockHolder l(&heap_checker_lock); | 2372 { SpinLockHolder l(&heap_checker_lock); |
2299 RAW_CHECK(heap_profile->FindAllocDetails(ptr, &info), ""); | 2373 RAW_CHECK(heap_profile->FindAllocDetails(ptr, &info), ""); |
2300 } | 2374 } |
2301 RAW_CHECK(info.stack_depth >= 1, ""); | 2375 RAW_CHECK(info.stack_depth >= 1, ""); |
2302 return info.call_stack[0]; | 2376 return info.call_stack[0]; |
2303 } | 2377 } |
OLD | NEW |