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 #if defined(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 |
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 <gperftools/heap-checker.h> | 76 #include <google/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 <gperftools/stacktrace.h> | 81 #include <google/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 <gperftools/malloc_hook.h> | 88 #include <google/malloc_hook.h> |
89 #include <gperftools/malloc_extension.h> | 89 #include <google/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 380 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
538 template<typename T> | 538 template<typename T> |
539 inline static const void* AsPtr(T addr) { | 539 inline static const void* AsPtr(T addr) { |
540 return reinterpret_cast<void*>(addr); | 540 return reinterpret_cast<void*>(addr); |
541 } | 541 } |
542 inline static uintptr_t AsInt(const void* ptr) { | 542 inline static uintptr_t AsInt(const void* ptr) { |
543 return reinterpret_cast<uintptr_t>(ptr); | 543 return reinterpret_cast<uintptr_t>(ptr); |
544 } | 544 } |
545 | 545 |
546 //---------------------------------------------------------------------- | 546 //---------------------------------------------------------------------- |
547 | 547 |
548 // We've seen reports that strstr causes heap-checker crashes in some | |
549 // libc's (?): | |
550 // http://code.google.com/p/gperftools/issues/detail?id=263 | |
551 // It's simple enough to use our own. This is not in time-critical code. | |
552 static const char* hc_strstr(const char* s1, const char* s2) { | |
553 const size_t len = strlen(s2); | |
554 RAW_CHECK(len > 0, "Unexpected empty string passed to strstr()"); | |
555 for (const char* p = strchr(s1, *s2); p != NULL; p = strchr(p+1, *s2)) { | |
556 if (strncmp(p, s2, len) == 0) { | |
557 return p; | |
558 } | |
559 } | |
560 return NULL; | |
561 } | |
562 | |
563 //---------------------------------------------------------------------- | |
564 | |
565 // Our hooks for MallocHook | 548 // Our hooks for MallocHook |
566 static void NewHook(const void* ptr, size_t size) { | 549 static void NewHook(const void* ptr, size_t size) { |
567 if (ptr != NULL) { | 550 if (ptr != NULL) { |
568 const int counter = get_thread_disable_counter(); | 551 const int counter = get_thread_disable_counter(); |
569 const bool ignore = (counter > 0); | 552 const bool ignore = (counter > 0); |
570 RAW_VLOG(16, "Recording Alloc: %p of %"PRIuS "; %d", ptr, size, | 553 RAW_VLOG(16, "Recording Alloc: %p of %"PRIuS "; %d", ptr, size, |
571 int(counter)); | 554 int(counter)); |
572 | |
573 // Fetch the caller's stack trace before acquiring heap_checker_lock. | |
574 void* stack[HeapProfileTable::kMaxStackDepth]; | |
575 int depth = HeapProfileTable::GetCallerStackTrace(0, stack); | |
576 | |
577 { SpinLockHolder l(&heap_checker_lock); | 555 { SpinLockHolder l(&heap_checker_lock); |
578 if (size > max_heap_object_size) max_heap_object_size = size; | 556 if (size > max_heap_object_size) max_heap_object_size = size; |
579 uintptr_t addr = AsInt(ptr); | 557 uintptr_t addr = AsInt(ptr); |
580 if (addr < min_heap_address) min_heap_address = addr; | 558 if (addr < min_heap_address) min_heap_address = addr; |
581 addr += size; | 559 addr += size; |
582 if (addr > max_heap_address) max_heap_address = addr; | 560 if (addr > max_heap_address) max_heap_address = addr; |
583 if (heap_checker_on) { | 561 if (heap_checker_on) { |
584 heap_profile->RecordAlloc(ptr, size, depth, stack); | 562 heap_profile->RecordAlloc(ptr, size, 0); |
585 if (ignore) { | 563 if (ignore) { |
586 heap_profile->MarkAsIgnored(ptr); | 564 heap_profile->MarkAsIgnored(ptr); |
587 } | 565 } |
588 } | 566 } |
589 } | 567 } |
590 RAW_VLOG(17, "Alloc Recorded: %p of %"PRIuS"", ptr, size); | 568 RAW_VLOG(17, "Alloc Recorded: %p of %"PRIuS"", ptr, size); |
591 } | 569 } |
592 } | 570 } |
593 | 571 |
594 static void DeleteHook(const void* ptr) { | 572 static void DeleteHook(const void* ptr) { |
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
777 return; | 755 return; |
778 } | 756 } |
779 } | 757 } |
780 RAW_VLOG(11, "%s-disabling %"PRIuS" bytes at %p", | 758 RAW_VLOG(11, "%s-disabling %"PRIuS" bytes at %p", |
781 (stack_disable ? "Stack" : "Range"), info.object_size, ptr); | 759 (stack_disable ? "Stack" : "Range"), info.object_size, ptr); |
782 live_objects->push_back(AllocObject(ptr, info.object_size, | 760 live_objects->push_back(AllocObject(ptr, info.object_size, |
783 MUST_BE_ON_HEAP)); | 761 MUST_BE_ON_HEAP)); |
784 } | 762 } |
785 } | 763 } |
786 | 764 |
787 static const char kUnnamedProcSelfMapEntry[] = "UNNAMED"; | |
788 | |
789 // This function takes some fields from a /proc/self/maps line: | 765 // This function takes some fields from a /proc/self/maps line: |
790 // | 766 // |
791 // start_address start address of a memory region. | 767 // start_address start address of a memory region. |
792 // end_address end address of a memory region | 768 // end_address end address of a memory region |
793 // permissions rwx + private/shared bit | 769 // permissions rwx + private/shared bit |
794 // filename filename of the mapped file | 770 // filename filename of the mapped file |
795 // | 771 // |
796 // If the region is not writeable, then it cannot have any heap | 772 // If the region is not writeable, then it cannot have any heap |
797 // pointers in it, otherwise we record it as a candidate live region | 773 // pointers in it, otherwise we record it as a candidate live region |
798 // to get filtered later. | 774 // to get filtered later. |
799 static void RecordGlobalDataLocked(uintptr_t start_address, | 775 static void RecordGlobalDataLocked(uintptr_t start_address, |
800 uintptr_t end_address, | 776 uintptr_t end_address, |
801 const char* permissions, | 777 const char* permissions, |
802 const char* filename) { | 778 const char* filename) { |
803 RAW_DCHECK(heap_checker_lock.IsHeld(), ""); | 779 RAW_DCHECK(heap_checker_lock.IsHeld(), ""); |
804 // Ignore non-writeable regions. | 780 // Ignore non-writeable regions. |
805 if (strchr(permissions, 'w') == NULL) return; | 781 if (strchr(permissions, 'w') == NULL) return; |
806 if (filename == NULL || *filename == '\0') { | 782 if (filename == NULL || *filename == '\0') filename = "UNNAMED"; |
807 filename = kUnnamedProcSelfMapEntry; | |
808 } | |
809 RAW_VLOG(11, "Looking into %s: 0x%" PRIxPTR "..0x%" PRIxPTR, | 783 RAW_VLOG(11, "Looking into %s: 0x%" PRIxPTR "..0x%" PRIxPTR, |
810 filename, start_address, end_address); | 784 filename, start_address, end_address); |
811 (*library_live_objects)[filename]. | 785 (*library_live_objects)[filename]. |
812 push_back(AllocObject(AsPtr(start_address), | 786 push_back(AllocObject(AsPtr(start_address), |
813 end_address - start_address, | 787 end_address - start_address, |
814 MAYBE_LIVE)); | 788 MAYBE_LIVE)); |
815 } | 789 } |
816 | 790 |
817 // See if 'library' from /proc/self/maps has base name 'library_base' | 791 // See if 'library' from /proc/self/maps has base name 'library_base' |
818 // i.e. contains it and has '.' or '-' after it. | 792 // i.e. contains it and has '.' or '-' after it. |
819 static bool IsLibraryNamed(const char* library, const char* library_base) { | 793 static bool IsLibraryNamed(const char* library, const char* library_base) { |
820 const char* p = hc_strstr(library, library_base); | 794 const char* p = strstr(library, library_base); |
821 size_t sz = strlen(library_base); | 795 size_t sz = strlen(library_base); |
822 return p != NULL && (p[sz] == '.' || p[sz] == '-'); | 796 return p != NULL && (p[sz] == '.' || p[sz] == '-'); |
823 } | 797 } |
824 | 798 |
825 // static | 799 // static |
826 void HeapLeakChecker::DisableLibraryAllocsLocked(const char* library, | 800 void HeapLeakChecker::DisableLibraryAllocsLocked(const char* library, |
827 uintptr_t start_address, | 801 uintptr_t start_address, |
828 uintptr_t end_address) { | 802 uintptr_t end_address) { |
829 RAW_DCHECK(heap_checker_lock.IsHeld(), ""); | 803 RAW_DCHECK(heap_checker_lock.IsHeld(), ""); |
830 int depth = 0; | 804 int depth = 0; |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
922 continue; | 896 continue; |
923 } | 897 } |
924 // Determine if any shared libraries are present (this is the same | 898 // Determine if any shared libraries are present (this is the same |
925 // list of extensions as is found in pprof). We want to ignore | 899 // list of extensions as is found in pprof). We want to ignore |
926 // 'fake' libraries with inode 0 when determining. However, some | 900 // 'fake' libraries with inode 0 when determining. However, some |
927 // systems don't share inodes via /proc, so we turn off this check | 901 // systems don't share inodes via /proc, so we turn off this check |
928 // if we don't see any evidence that we're getting inode info. | 902 // if we don't see any evidence that we're getting inode info. |
929 if (inode != 0) { | 903 if (inode != 0) { |
930 saw_nonzero_inode = true; | 904 saw_nonzero_inode = true; |
931 } | 905 } |
932 if ((hc_strstr(filename, "lib") && hc_strstr(filename, ".so")) || | 906 if ((strstr(filename, "lib") && strstr(filename, ".so")) || |
933 hc_strstr(filename, ".dll") || | 907 strstr(filename, ".dll") || |
934 // not all .dylib filenames start with lib. .dylib is big enough | 908 // not all .dylib filenames start with lib. .dylib is big enough |
935 // that we are unlikely to get false matches just checking that. | 909 // that we are unlikely to get false matches just checking that. |
936 hc_strstr(filename, ".dylib") || hc_strstr(filename, ".bundle")) { | 910 strstr(filename, ".dylib") || strstr(filename, ".bundle")) { |
937 saw_shared_lib = true; | 911 saw_shared_lib = true; |
938 if (inode != 0) { | 912 if (inode != 0) { |
939 saw_shared_lib_with_nonzero_inode = true; | 913 saw_shared_lib_with_nonzero_inode = true; |
940 } | 914 } |
941 } | 915 } |
942 | 916 |
943 switch (proc_maps_task) { | 917 switch (proc_maps_task) { |
944 case DISABLE_LIBRARY_ALLOCS: | 918 case DISABLE_LIBRARY_ALLOCS: |
945 // All lines starting like | 919 // All lines starting like |
946 // "401dc000-4030f000 r??p 00132000 03:01 13991972 lib/bin" | 920 // "401dc000-4030f000 r??p 00132000 03:01 13991972 lib/bin" |
(...skipping 455 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1402 const size_t remainder = AsInt(object) % pointer_source_alignment; | 1376 const size_t remainder = AsInt(object) % pointer_source_alignment; |
1403 if (remainder) { | 1377 if (remainder) { |
1404 object += pointer_source_alignment - remainder; | 1378 object += pointer_source_alignment - remainder; |
1405 if (size >= pointer_source_alignment - remainder) { | 1379 if (size >= pointer_source_alignment - remainder) { |
1406 size -= pointer_source_alignment - remainder; | 1380 size -= pointer_source_alignment - remainder; |
1407 } else { | 1381 } else { |
1408 size = 0; | 1382 size = 0; |
1409 } | 1383 } |
1410 } | 1384 } |
1411 if (size < sizeof(void*)) continue; | 1385 if (size < sizeof(void*)) continue; |
1412 | |
1413 #ifdef NO_FRAME_POINTER | |
1414 // Frame pointer omission requires us to use libunwind, which uses direct | |
1415 // mmap and munmap system calls, and that needs special handling. | |
1416 if (name2 == kUnnamedProcSelfMapEntry) { | |
1417 static const uintptr_t page_mask = ~(getpagesize() - 1); | |
1418 const uintptr_t addr = reinterpret_cast<uintptr_t>(object); | |
1419 if ((addr & page_mask) == 0 && (size & page_mask) == 0) { | |
1420 // This is an object we slurped from /proc/self/maps. | |
1421 // It may or may not be readable at this point. | |
1422 // | |
1423 // In case all the above conditions made a mistake, and the object is | |
1424 // not related to libunwind, we also verify that it's not readable | |
1425 // before ignoring it. | |
1426 if (msync(const_cast<char*>(object), size, MS_ASYNC) != 0) { | |
1427 // Skip unreadable object, so we don't crash trying to sweep it. | |
1428 RAW_VLOG(0, "Ignoring inaccessible object [%p, %p) " | |
1429 "(msync error %d (%s))", | |
1430 object, object + size, errno, strerror(errno)); | |
1431 continue; | |
1432 } | |
1433 } | |
1434 } | |
1435 #endif | |
1436 | |
1437 const char* const max_object = object + size - sizeof(void*); | 1386 const char* const max_object = object + size - sizeof(void*); |
1438 while (object <= max_object) { | 1387 while (object <= max_object) { |
1439 // potentially unaligned load: | 1388 // potentially unaligned load: |
1440 const uintptr_t addr = *reinterpret_cast<const uintptr_t*>(object); | 1389 const uintptr_t addr = *reinterpret_cast<const uintptr_t*>(object); |
1441 // Do fast check before the more expensive HaveOnHeapLocked lookup: | 1390 // Do fast check before the more expensive HaveOnHeapLocked lookup: |
1442 // this code runs for all memory words that are potentially pointers: | 1391 // this code runs for all memory words that are potentially pointers: |
1443 const bool can_be_on_heap = | 1392 const bool can_be_on_heap = |
1444 // Order tests by the likelyhood of the test failing in 64/32 bit modes. | 1393 // Order tests by the likelyhood of the test failing in 64/32 bit modes. |
1445 // Yes, this matters: we either lose 5..6% speed in 32 bit mode | 1394 // Yes, this matters: we either lose 5..6% speed in 32 bit mode |
1446 // (which is already slower) or by a factor of 1.5..1.91 in 64 bit mode. | 1395 // (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... |
1499 //---------------------------------------------------------------------- | 1448 //---------------------------------------------------------------------- |
1500 // HeapLeakChecker leak check disabling components | 1449 // HeapLeakChecker leak check disabling components |
1501 //---------------------------------------------------------------------- | 1450 //---------------------------------------------------------------------- |
1502 | 1451 |
1503 // static | 1452 // static |
1504 void HeapLeakChecker::DisableChecksIn(const char* pattern) { | 1453 void HeapLeakChecker::DisableChecksIn(const char* pattern) { |
1505 RAW_LOG(WARNING, "DisableChecksIn(%s) is ignored", pattern); | 1454 RAW_LOG(WARNING, "DisableChecksIn(%s) is ignored", pattern); |
1506 } | 1455 } |
1507 | 1456 |
1508 // static | 1457 // static |
1509 void HeapLeakChecker::DoIgnoreObject(const void* ptr) { | 1458 void HeapLeakChecker::IgnoreObject(const void* ptr) { |
1510 SpinLockHolder l(&heap_checker_lock); | 1459 SpinLockHolder l(&heap_checker_lock); |
1511 if (!heap_checker_on) return; | 1460 if (!heap_checker_on) return; |
1512 size_t object_size; | 1461 size_t object_size; |
1513 if (!HaveOnHeapLocked(&ptr, &object_size)) { | 1462 if (!HaveOnHeapLocked(&ptr, &object_size)) { |
1514 RAW_LOG(ERROR, "No live heap object at %p to ignore", ptr); | 1463 RAW_LOG(ERROR, "No live heap object at %p to ignore", ptr); |
1515 } else { | 1464 } else { |
1516 RAW_VLOG(10, "Going to ignore live object at %p of %"PRIuS" bytes", | 1465 RAW_VLOG(10, "Going to ignore live object at %p of %"PRIuS" bytes", |
1517 ptr, object_size); | 1466 ptr, object_size); |
1518 if (ignored_objects == NULL) { | 1467 if (ignored_objects == NULL) { |
1519 ignored_objects = new(Allocator::Allocate(sizeof(IgnoredObjectsMap))) | 1468 ignored_objects = new(Allocator::Allocate(sizeof(IgnoredObjectsMap))) |
(...skipping 383 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1903 if (!heap_cleanups_) | 1852 if (!heap_cleanups_) |
1904 return; | 1853 return; |
1905 for (int i = 0; i < heap_cleanups_->size(); i++) { | 1854 for (int i = 0; i < heap_cleanups_->size(); i++) { |
1906 void (*f)(void) = (*heap_cleanups_)[i]; | 1855 void (*f)(void) = (*heap_cleanups_)[i]; |
1907 f(); | 1856 f(); |
1908 } | 1857 } |
1909 delete heap_cleanups_; | 1858 delete heap_cleanups_; |
1910 heap_cleanups_ = NULL; | 1859 heap_cleanups_ = NULL; |
1911 } | 1860 } |
1912 | 1861 |
1913 // Program exit heap cleanup registered as a module object destructor. | 1862 // Program exit heap cleanup registered with atexit(). |
1914 // Will not get executed when we crash on a signal. | 1863 // Will not get executed when we crash on a signal. |
1915 // | 1864 // |
1916 void HeapLeakChecker_RunHeapCleanups() { | 1865 /*static*/ void HeapLeakChecker::RunHeapCleanups() { |
1917 if (FLAGS_heap_check == "local") // don't check heap in this mode | |
1918 return; | |
1919 { SpinLockHolder l(&heap_checker_lock); | 1866 { SpinLockHolder l(&heap_checker_lock); |
1920 // can get here (via forks?) with other pids | 1867 // can get here (via forks?) with other pids |
1921 if (heap_checker_pid != getpid()) return; | 1868 if (heap_checker_pid != getpid()) return; |
1922 } | 1869 } |
1923 HeapCleaner::RunHeapCleanups(); | 1870 HeapCleaner::RunHeapCleanups(); |
1924 if (!FLAGS_heap_check_after_destructors) HeapLeakChecker::DoMainHeapCheck(); | 1871 if (!FLAGS_heap_check_after_destructors) DoMainHeapCheck(); |
1925 } | 1872 } |
1926 | 1873 |
1927 static bool internal_init_start_has_run = false; | 1874 static bool internal_init_start_has_run = false; |
1928 | 1875 |
1929 // Called exactly once, before main() (but hopefully just before). | 1876 // Called exactly once, before main() (but hopefully just before). |
1930 // This picks a good unique name for the dumped leak checking heap profiles. | 1877 // This picks a good unique name for the dumped leak checking heap profiles. |
1931 // | 1878 // |
1932 // Because we crash when InternalInitStart is called more than once, | 1879 // Because we crash when InternalInitStart is called more than once, |
1933 // it's fine that we hold heap_checker_lock only around pieces of | 1880 // it's fine that we hold heap_checker_lock only around pieces of |
1934 // this function: this is still enough for thread-safety w.r.t. other functions | 1881 // this function: this is still enough for thread-safety w.r.t. other functions |
1935 // of this module. | 1882 // of this module. |
1936 // We can't hold heap_checker_lock throughout because it would deadlock | 1883 // We can't hold heap_checker_lock throughout because it would deadlock |
1937 // on a memory allocation since our new/delete hooks can be on. | 1884 // on a memory allocation since our new/delete hooks can be on. |
1938 // | 1885 // |
1939 void HeapLeakChecker_InternalInitStart() { | 1886 /*static*/ void HeapLeakChecker::InternalInitStart() { |
1940 { SpinLockHolder l(&heap_checker_lock); | 1887 { SpinLockHolder l(&heap_checker_lock); |
1941 RAW_CHECK(!internal_init_start_has_run, | 1888 RAW_CHECK(!internal_init_start_has_run, |
1942 "Heap-check constructor called twice. Perhaps you both linked" | 1889 "Heap-check constructor called twice. Perhaps you both linked" |
1943 " in the heap checker, and also used LD_PRELOAD to load it?"); | 1890 " in the heap checker, and also used LD_PRELOAD to load it?"); |
1944 internal_init_start_has_run = true; | 1891 internal_init_start_has_run = true; |
1945 | 1892 |
1946 #ifdef ADDRESS_SANITIZER | |
1947 // AddressSanitizer's custom malloc conflicts with HeapChecker. | |
1948 FLAGS_heap_check = ""; | |
1949 #endif | |
1950 | |
1951 if (FLAGS_heap_check.empty()) { | 1893 if (FLAGS_heap_check.empty()) { |
1952 // turns out we do not need checking in the end; can stop profiling | 1894 // turns out we do not need checking in the end; can stop profiling |
1953 HeapLeakChecker::TurnItselfOffLocked(); | 1895 TurnItselfOffLocked(); |
1954 return; | 1896 return; |
1955 } else if (RunningOnValgrind()) { | 1897 } else if (RunningOnValgrind()) { |
1956 // There is no point in trying -- we'll just fail. | 1898 // There is no point in trying -- we'll just fail. |
1957 RAW_LOG(WARNING, "Can't run under Valgrind; will turn itself off"); | 1899 RAW_LOG(WARNING, "Can't run under Valgrind; will turn itself off"); |
1958 HeapLeakChecker::TurnItselfOffLocked(); | 1900 TurnItselfOffLocked(); |
1959 return; | 1901 return; |
1960 } | 1902 } |
1961 } | 1903 } |
1962 | 1904 |
1963 // Changing this to false can be useful when debugging heap-checker itself: | 1905 // Changing this to false can be useful when debugging heap-checker itself: |
1964 if (!FLAGS_heap_check_run_under_gdb && IsDebuggerAttached()) { | 1906 if (!FLAGS_heap_check_run_under_gdb && IsDebuggerAttached()) { |
1965 RAW_LOG(WARNING, "Someone is ptrace()ing us; will turn itself off"); | 1907 RAW_LOG(WARNING, "Someone is ptrace()ing us; will turn itself off"); |
1966 SpinLockHolder l(&heap_checker_lock); | 1908 SpinLockHolder l(&heap_checker_lock); |
1967 HeapLeakChecker::TurnItselfOffLocked(); | 1909 TurnItselfOffLocked(); |
1968 return; | 1910 return; |
1969 } | 1911 } |
1970 | 1912 |
1971 { SpinLockHolder l(&heap_checker_lock); | 1913 { SpinLockHolder l(&heap_checker_lock); |
1972 if (!constructor_heap_profiling) { | 1914 if (!constructor_heap_profiling) { |
1973 RAW_LOG(FATAL, "Can not start so late. You have to enable heap checking " | 1915 RAW_LOG(FATAL, "Can not start so late. You have to enable heap checking " |
1974 "with HEAPCHECK=<mode>."); | 1916 "with HEAPCHECK=<mode>."); |
1975 } | 1917 } |
1976 } | 1918 } |
1977 | 1919 |
(...skipping 30 matching lines...) Expand all Loading... |
2008 FLAGS_heap_check_ignore_thread_live = false; // no live flood (stricter) | 1950 FLAGS_heap_check_ignore_thread_live = false; // no live flood (stricter) |
2009 FLAGS_heap_check_ignore_global_live = false; // no live flood (stricter) | 1951 FLAGS_heap_check_ignore_global_live = false; // no live flood (stricter) |
2010 } else if (FLAGS_heap_check == "as-is") { | 1952 } else if (FLAGS_heap_check == "as-is") { |
2011 // do nothing: use other flags as is | 1953 // do nothing: use other flags as is |
2012 } else if (FLAGS_heap_check == "local") { | 1954 } else if (FLAGS_heap_check == "local") { |
2013 // do nothing | 1955 // do nothing |
2014 } else { | 1956 } else { |
2015 RAW_LOG(FATAL, "Unsupported heap_check flag: %s", | 1957 RAW_LOG(FATAL, "Unsupported heap_check flag: %s", |
2016 FLAGS_heap_check.c_str()); | 1958 FLAGS_heap_check.c_str()); |
2017 } | 1959 } |
2018 // FreeBSD doesn't seem to honor atexit execution order: | |
2019 // http://code.google.com/p/gperftools/issues/detail?id=375 | |
2020 // Since heap-checking before destructors depends on atexit running | |
2021 // at the right time, on FreeBSD we always check after, even in the | |
2022 // less strict modes. This just means FreeBSD is always a bit | |
2023 // stricter in its checking than other OSes. | |
2024 #ifdef __FreeBSD__ | |
2025 FLAGS_heap_check_after_destructors = true; | |
2026 #endif | |
2027 | |
2028 { SpinLockHolder l(&heap_checker_lock); | 1960 { SpinLockHolder l(&heap_checker_lock); |
2029 RAW_DCHECK(heap_checker_pid == getpid(), ""); | 1961 RAW_DCHECK(heap_checker_pid == getpid(), ""); |
2030 heap_checker_on = true; | 1962 heap_checker_on = true; |
2031 RAW_DCHECK(heap_profile, ""); | 1963 RAW_DCHECK(heap_profile, ""); |
2032 HeapLeakChecker::ProcMapsResult pm_result = HeapLeakChecker::UseProcMapsLock
ed(HeapLeakChecker::DISABLE_LIBRARY_ALLOCS); | 1964 ProcMapsResult pm_result = UseProcMapsLocked(DISABLE_LIBRARY_ALLOCS); |
2033 // might neeed to do this more than once | 1965 // might neeed to do this more than once |
2034 // if one later dynamically loads libraries that we want disabled | 1966 // if one later dynamically loads libraries that we want disabled |
2035 if (pm_result != HeapLeakChecker::PROC_MAPS_USED) { // can't function | 1967 if (pm_result != PROC_MAPS_USED) { // can't function |
2036 HeapLeakChecker::TurnItselfOffLocked(); | 1968 TurnItselfOffLocked(); |
2037 return; | 1969 return; |
2038 } | 1970 } |
2039 } | 1971 } |
2040 | 1972 |
2041 // make a good place and name for heap profile leak dumps | 1973 // make a good place and name for heap profile leak dumps |
2042 string* profile_prefix = | 1974 string* profile_prefix = |
2043 new string(FLAGS_heap_check_dump_directory + "/" + invocation_name()); | 1975 new string(FLAGS_heap_check_dump_directory + "/" + invocation_name()); |
2044 | 1976 |
2045 // Finalize prefix for dumping leak checking profiles. | 1977 // Finalize prefix for dumping leak checking profiles. |
2046 const int32 our_pid = getpid(); // safest to call getpid() outside lock | 1978 const int32 our_pid = getpid(); // safest to call getpid() outside lock |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2080 // "nm <this_binary> | grep new" will show that tcmalloc's new/delete | 2012 // "nm <this_binary> | grep new" will show that tcmalloc's new/delete |
2081 // implementation did not get linked-in into this binary | 2013 // implementation did not get linked-in into this binary |
2082 // (i.e. nm will list __builtin_new and __builtin_vec_new as undefined). | 2014 // (i.e. nm will list __builtin_new and __builtin_vec_new as undefined). |
2083 // If this happens, it is a BUILD bug to be fixed. | 2015 // If this happens, it is a BUILD bug to be fixed. |
2084 | 2016 |
2085 RAW_VLOG(heap_checker_info_level, | 2017 RAW_VLOG(heap_checker_info_level, |
2086 "WARNING: Perftools heap leak checker is active " | 2018 "WARNING: Perftools heap leak checker is active " |
2087 "-- Performance may suffer"); | 2019 "-- Performance may suffer"); |
2088 | 2020 |
2089 if (FLAGS_heap_check != "local") { | 2021 if (FLAGS_heap_check != "local") { |
| 2022 // Schedule registered heap cleanup |
| 2023 atexit(RunHeapCleanups); |
2090 HeapLeakChecker* main_hc = new HeapLeakChecker(); | 2024 HeapLeakChecker* main_hc = new HeapLeakChecker(); |
2091 SpinLockHolder l(&heap_checker_lock); | 2025 SpinLockHolder l(&heap_checker_lock); |
2092 RAW_DCHECK(main_heap_checker == NULL, | 2026 RAW_DCHECK(main_heap_checker == NULL, |
2093 "Repeated creation of main_heap_checker"); | 2027 "Repeated creation of main_heap_checker"); |
2094 main_heap_checker = main_hc; | 2028 main_heap_checker = main_hc; |
2095 do_main_heap_check = true; | 2029 do_main_heap_check = true; |
2096 } | 2030 } |
2097 | 2031 |
2098 { SpinLockHolder l(&heap_checker_lock); | 2032 { SpinLockHolder l(&heap_checker_lock); |
2099 RAW_CHECK(heap_checker_on && constructor_heap_profiling, | 2033 RAW_CHECK(heap_checker_on && constructor_heap_profiling, |
(...skipping 12 matching lines...) Expand all Loading... |
2112 // TODO(csilvers): support this in some manner. | 2046 // TODO(csilvers): support this in some manner. |
2113 #if 0 | 2047 #if 0 |
2114 SetCommandLineOptionWithMode("max_free_queue_size", "104857600", // 100M | 2048 SetCommandLineOptionWithMode("max_free_queue_size", "104857600", // 100M |
2115 SET_FLAG_IF_DEFAULT); | 2049 SET_FLAG_IF_DEFAULT); |
2116 #endif | 2050 #endif |
2117 } | 2051 } |
2118 | 2052 |
2119 // We want this to run early as well, but not so early as | 2053 // We want this to run early as well, but not so early as |
2120 // ::BeforeConstructors (we want flag assignments to have already | 2054 // ::BeforeConstructors (we want flag assignments to have already |
2121 // happened, for instance). Initializer-registration does the trick. | 2055 // happened, for instance). Initializer-registration does the trick. |
2122 REGISTER_MODULE_INITIALIZER(init_start, HeapLeakChecker_InternalInitStart()); | 2056 REGISTER_MODULE_INITIALIZER(init_start, HeapLeakChecker::InternalInitStart()); |
2123 REGISTER_MODULE_DESTRUCTOR(init_start, HeapLeakChecker_RunHeapCleanups()); | |
2124 | |
2125 // static | |
2126 bool HeapLeakChecker::NoGlobalLeaksMaybeSymbolize( | |
2127 ShouldSymbolize should_symbolize) { | |
2128 // we never delete or change main_heap_checker once it's set: | |
2129 HeapLeakChecker* main_hc = GlobalChecker(); | |
2130 if (main_hc) { | |
2131 RAW_VLOG(10, "Checking for whole-program memory leaks"); | |
2132 return main_hc->DoNoLeaks(should_symbolize); | |
2133 } | |
2134 return true; | |
2135 } | |
2136 | 2057 |
2137 // static | 2058 // static |
2138 bool HeapLeakChecker::DoMainHeapCheck() { | 2059 bool HeapLeakChecker::DoMainHeapCheck() { |
2139 if (FLAGS_heap_check_delay_seconds > 0) { | 2060 if (FLAGS_heap_check_delay_seconds > 0) { |
2140 sleep(FLAGS_heap_check_delay_seconds); | 2061 sleep(FLAGS_heap_check_delay_seconds); |
2141 } | 2062 } |
2142 { SpinLockHolder l(&heap_checker_lock); | 2063 { SpinLockHolder l(&heap_checker_lock); |
2143 if (!do_main_heap_check) return false; | 2064 if (!do_main_heap_check) return false; |
2144 RAW_DCHECK(heap_checker_pid == getpid(), ""); | 2065 RAW_DCHECK(heap_checker_pid == getpid(), ""); |
2145 do_main_heap_check = false; // will do it now; no need to do it more | 2066 do_main_heap_check = false; // will do it now; no need to do it more |
2146 } | 2067 } |
2147 | 2068 |
2148 // The program is over, so it's safe to symbolize addresses (which | 2069 if (!NoGlobalLeaks()) { |
2149 // requires a fork) because no serious work is expected to be done | |
2150 // after this. Symbolizing is really useful -- knowing what | |
2151 // function has a leak is better than knowing just an address -- | |
2152 // and while we can only safely symbolize once in a program run, | |
2153 // now is the time (after all, there's no "later" that would be better). | |
2154 if (!NoGlobalLeaksMaybeSymbolize(SYMBOLIZE)) { | |
2155 if (FLAGS_heap_check_identify_leaks) { | 2070 if (FLAGS_heap_check_identify_leaks) { |
2156 RAW_LOG(FATAL, "Whole-program memory leaks found."); | 2071 RAW_LOG(FATAL, "Whole-program memory leaks found."); |
2157 } | 2072 } |
2158 RAW_LOG(ERROR, "Exiting with error code (instead of crashing) " | 2073 RAW_LOG(ERROR, "Exiting with error code (instead of crashing) " |
2159 "because of whole-program memory leaks"); | 2074 "because of whole-program memory leaks"); |
2160 _exit(1); // we don't want to call atexit() routines! | 2075 _exit(1); // we don't want to call atexit() routines! |
2161 } | 2076 } |
2162 return true; | 2077 return true; |
2163 } | 2078 } |
2164 | 2079 |
2165 // static | 2080 // static |
2166 HeapLeakChecker* HeapLeakChecker::GlobalChecker() { | 2081 HeapLeakChecker* HeapLeakChecker::GlobalChecker() { |
2167 SpinLockHolder l(&heap_checker_lock); | 2082 SpinLockHolder l(&heap_checker_lock); |
2168 return main_heap_checker; | 2083 return main_heap_checker; |
2169 } | 2084 } |
2170 | 2085 |
2171 // static | 2086 // static |
2172 bool HeapLeakChecker::NoGlobalLeaks() { | 2087 bool HeapLeakChecker::NoGlobalLeaks() { |
2173 // symbolizing requires a fork, which isn't safe to do in general. | 2088 // we never delete or change main_heap_checker once it's set: |
2174 return NoGlobalLeaksMaybeSymbolize(DO_NOT_SYMBOLIZE); | 2089 HeapLeakChecker* main_hc = GlobalChecker(); |
| 2090 if (main_hc) { |
| 2091 RAW_VLOG(10, "Checking for whole-program memory leaks"); |
| 2092 // The program is over, so it's safe to symbolize addresses (which |
| 2093 // requires a fork) because no serious work is expected to be done |
| 2094 // after this. Symbolizing is really useful -- knowing what |
| 2095 // function has a leak is better than knowing just an address -- |
| 2096 // and while we can only safely symbolize once in a program run, |
| 2097 // now is the time (after all, there's no "later" that would be better). |
| 2098 return main_hc->DoNoLeaks(SYMBOLIZE); |
| 2099 } |
| 2100 return true; |
2175 } | 2101 } |
2176 | 2102 |
2177 // static | 2103 // static |
2178 void HeapLeakChecker::CancelGlobalCheck() { | 2104 void HeapLeakChecker::CancelGlobalCheck() { |
2179 SpinLockHolder l(&heap_checker_lock); | 2105 SpinLockHolder l(&heap_checker_lock); |
2180 if (do_main_heap_check) { | 2106 if (do_main_heap_check) { |
2181 RAW_VLOG(heap_checker_info_level, | 2107 RAW_VLOG(heap_checker_info_level, |
2182 "Canceling the automatic at-exit whole-program memory leak check"); | 2108 "Canceling the automatic at-exit whole-program memory leak check"); |
2183 do_main_heap_check = false; | 2109 do_main_heap_check = false; |
2184 } | 2110 } |
2185 } | 2111 } |
2186 | 2112 |
2187 // static | 2113 // static |
2188 void HeapLeakChecker::BeforeConstructorsLocked() { | 2114 void HeapLeakChecker::BeforeConstructorsLocked() { |
2189 RAW_DCHECK(heap_checker_lock.IsHeld(), ""); | 2115 RAW_DCHECK(heap_checker_lock.IsHeld(), ""); |
2190 RAW_CHECK(!constructor_heap_profiling, | 2116 RAW_CHECK(!constructor_heap_profiling, |
2191 "BeforeConstructorsLocked called multiple times"); | 2117 "BeforeConstructorsLocked called multiple times"); |
2192 #ifdef ADDRESS_SANITIZER | |
2193 // AddressSanitizer's custom malloc conflicts with HeapChecker. | |
2194 return; | |
2195 #endif | |
2196 // Set hooks early to crash if 'new' gets called before we make heap_profile, | 2118 // Set hooks early to crash if 'new' gets called before we make heap_profile, |
2197 // and make sure no other hooks existed: | 2119 // and make sure no other hooks existed: |
2198 RAW_CHECK(MallocHook::AddNewHook(&NewHook), ""); | 2120 RAW_CHECK(MallocHook::AddNewHook(&NewHook), ""); |
2199 RAW_CHECK(MallocHook::AddDeleteHook(&DeleteHook), ""); | 2121 RAW_CHECK(MallocHook::AddDeleteHook(&DeleteHook), ""); |
2200 constructor_heap_profiling = true; | 2122 constructor_heap_profiling = true; |
2201 MemoryRegionMap::Init(1); | 2123 MemoryRegionMap::Init(1); |
2202 // Set up MemoryRegionMap with (at least) one caller stack frame to record | 2124 // Set up MemoryRegionMap with (at least) one caller stack frame to record |
2203 // (important that it's done before HeapProfileTable creation below). | 2125 // (important that it's done before HeapProfileTable creation below). |
2204 Allocator::Init(); | 2126 Allocator::Init(); |
2205 RAW_CHECK(heap_profile == NULL, ""); | 2127 RAW_CHECK(heap_profile == NULL, ""); |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2363 // static | 2285 // static |
2364 const void* HeapLeakChecker::GetAllocCaller(void* ptr) { | 2286 const void* HeapLeakChecker::GetAllocCaller(void* ptr) { |
2365 // this is used only in the unittest, so the heavy checks are fine | 2287 // this is used only in the unittest, so the heavy checks are fine |
2366 HeapProfileTable::AllocInfo info; | 2288 HeapProfileTable::AllocInfo info; |
2367 { SpinLockHolder l(&heap_checker_lock); | 2289 { SpinLockHolder l(&heap_checker_lock); |
2368 RAW_CHECK(heap_profile->FindAllocDetails(ptr, &info), ""); | 2290 RAW_CHECK(heap_profile->FindAllocDetails(ptr, &info), ""); |
2369 } | 2291 } |
2370 RAW_CHECK(info.stack_depth >= 1, ""); | 2292 RAW_CHECK(info.stack_depth >= 1, ""); |
2371 return info.call_stack[0]; | 2293 return info.call_stack[0]; |
2372 } | 2294 } |
OLD | NEW |