Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(111)

Side by Side Diff: third_party/tcmalloc/chromium/src/heap-checker.cc

Issue 7050034: Merge google-perftools r109 (the current contents of third_party/tcmalloc/vendor) (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
99 using std::map; 99 using std::map;
100 using std::set; 100 using std::set;
101 using std::vector; 101 using std::vector;
102 using std::swap; 102 using std::swap;
103 using std::make_pair; 103 using std::make_pair;
104 using std::min; 104 using std::min;
105 using std::max; 105 using std::max;
106 using std::less; 106 using std::less;
107 using std::char_traits; 107 using std::char_traits;
108 108
109 // If current process is being ptrace()d, 'TracerPid' in /proc/self/status
110 // will be non-zero.
111 static bool IsDebuggerAttached(void) { // only works under linux, probably
112 char buf[256]; // TracerPid comes relatively earlier in status output
113 int fd = open("/proc/self/status", O_RDONLY);
114 if (fd == -1) {
115 return false; // Can't tell for sure.
116 }
117 const int len = read(fd, buf, sizeof(buf));
118 bool rc = false;
119 if (len > 0) {
120 const char *const kTracerPid = "TracerPid:\t";
121 buf[len - 1] = '\0';
122 const char *p = strstr(buf, kTracerPid);
123 if (p != NULL) {
124 rc = (strncmp(p + strlen(kTracerPid), "0\n", 2) != 0);
125 }
126 }
127 close(fd);
128 return rc;
129 }
130
109 // This is the default if you don't link in -lprofiler 131 // This is the default if you don't link in -lprofiler
110 extern "C" { 132 extern "C" {
111 ATTRIBUTE_WEAK PERFTOOLS_DLL_DECL bool ProfilingIsEnabledForAllThreads(); 133 ATTRIBUTE_WEAK PERFTOOLS_DLL_DECL bool ProfilingIsEnabledForAllThreads();
112 bool ProfilingIsEnabledForAllThreads() { return false; } 134 bool ProfilingIsEnabledForAllThreads() { return false; }
113 } 135 }
114 136
115 //---------------------------------------------------------------------- 137 //----------------------------------------------------------------------
116 // Flags that control heap-checking 138 // Flags that control heap-checking
117 //---------------------------------------------------------------------- 139 //----------------------------------------------------------------------
118 140
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
156 178
157 DEFINE_bool(heap_check_test_pointer_alignment, 179 DEFINE_bool(heap_check_test_pointer_alignment,
158 EnvToBool("HEAP_CHECK_TEST_POINTER_ALIGNMENT", false), 180 EnvToBool("HEAP_CHECK_TEST_POINTER_ALIGNMENT", false),
159 "Set to true to check if the found leak can be due to " 181 "Set to true to check if the found leak can be due to "
160 "use of unaligned pointers"); 182 "use of unaligned pointers");
161 183
162 // Alignment at which all pointers in memory are supposed to be located; 184 // Alignment at which all pointers in memory are supposed to be located;
163 // use 1 if any alignment is ok. 185 // use 1 if any alignment is ok.
164 // heap_check_test_pointer_alignment flag guides if we try the value of 1. 186 // heap_check_test_pointer_alignment flag guides if we try the value of 1.
165 // The larger it can be, the lesser is the chance of missing real leaks. 187 // The larger it can be, the lesser is the chance of missing real leaks.
166 //
167 // sizeof(void)* is correct. However gold (the new linker) has a bug where it
168 // sometimes places global pointers on 4-byte boundaries, even when pointers
169 // are 8 bytes long. While we are fixing the linker, degrade to 4-byte
170 // alignment on all targets. http://b/1226481
171 //
172 static const size_t kPointerSourceAlignment = sizeof(void*); 188 static const size_t kPointerSourceAlignment = sizeof(void*);
173 DEFINE_int32(heap_check_pointer_source_alignment, 189 DEFINE_int32(heap_check_pointer_source_alignment,
174 EnvToInt("HEAP_CHECK_POINTER_SOURCE_ALIGNMENT", 190 EnvToInt("HEAP_CHECK_POINTER_SOURCE_ALIGNMENT",
175 kPointerSourceAlignment), 191 kPointerSourceAlignment),
176 "Alignment at which all pointers in memory are supposed to be " 192 "Alignment at which all pointers in memory are supposed to be "
177 "located. Use 1 if any alignment is ok."); 193 "located. Use 1 if any alignment is ok.");
178 194
179 // A reasonable default to handle pointers inside of typical class objects: 195 // A reasonable default to handle pointers inside of typical class objects:
180 // Too low and we won't be able to traverse pointers to normally-used 196 // Too low and we won't be able to traverse pointers to normally-used
181 // nested objects and base parts of multiple-inherited objects. 197 // nested objects and base parts of multiple-inherited objects.
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
297 RAW_DCHECK(arena_ && heap_checker_lock.IsHeld(), ""); 313 RAW_DCHECK(arena_ && heap_checker_lock.IsHeld(), "");
298 void* p = LowLevelAlloc::AllocWithArena(n, arena_); 314 void* p = LowLevelAlloc::AllocWithArena(n, arena_);
299 if (p) alloc_count_ += 1; 315 if (p) alloc_count_ += 1;
300 return p; 316 return p;
301 } 317 }
302 static void Free(void* p) { 318 static void Free(void* p) {
303 RAW_DCHECK(heap_checker_lock.IsHeld(), ""); 319 RAW_DCHECK(heap_checker_lock.IsHeld(), "");
304 if (p) alloc_count_ -= 1; 320 if (p) alloc_count_ -= 1;
305 LowLevelAlloc::Free(p); 321 LowLevelAlloc::Free(p);
306 } 322 }
323 static void Free(void* p, size_t /* n */) {
324 Free(p);
325 }
307 // destruct, free, and make *p to be NULL 326 // destruct, free, and make *p to be NULL
308 template<typename T> static void DeleteAndNull(T** p) { 327 template<typename T> static void DeleteAndNull(T** p) {
309 (*p)->~T(); 328 (*p)->~T();
310 Free(*p); 329 Free(*p);
311 *p = NULL; 330 *p = NULL;
312 } 331 }
313 template<typename T> static void DeleteAndNullIfNot(T** p) { 332 template<typename T> static void DeleteAndNullIfNot(T** p) {
314 if (*p != NULL) DeleteAndNull(p); 333 if (*p != NULL) DeleteAndNull(p);
315 } 334 }
316 private: 335 private:
(...skipping 471 matching lines...) Expand 10 before | Expand all | Expand 10 after
788 RAW_DCHECK(heap_checker_lock.IsHeld(), ""); 807 RAW_DCHECK(heap_checker_lock.IsHeld(), "");
789 int depth = 0; 808 int depth = 0;
790 // TODO(maxim): maybe this should be extended to also use objdump 809 // TODO(maxim): maybe this should be extended to also use objdump
791 // and pick the text portion of the library more precisely. 810 // and pick the text portion of the library more precisely.
792 if (IsLibraryNamed(library, "/libpthread") || 811 if (IsLibraryNamed(library, "/libpthread") ||
793 // libpthread has a lot of small "system" leaks we don't care about. 812 // libpthread has a lot of small "system" leaks we don't care about.
794 // In particular it allocates memory to store data supplied via 813 // In particular it allocates memory to store data supplied via
795 // pthread_setspecific (which can be the only pointer to a heap object). 814 // pthread_setspecific (which can be the only pointer to a heap object).
796 IsLibraryNamed(library, "/libdl") || 815 IsLibraryNamed(library, "/libdl") ||
797 // library loaders leak some "system" heap that we don't care about 816 // library loaders leak some "system" heap that we don't care about
798 IsLibraryNamed(library, "/libcrypto") 817 IsLibraryNamed(library, "/libcrypto") ||
799 // Sometimes libcrypto of OpenSSH is compiled with -fomit-frame-pointer 818 // Sometimes libcrypto of OpenSSH is compiled with -fomit-frame-pointer
800 // (any library can be, of course, but this one often is because speed 819 // (any library can be, of course, but this one often is because speed
801 // is so important for making crypto usable). We ignore all its 820 // is so important for making crypto usable). We ignore all its
802 // allocations because we can't see the call stacks. We'd prefer 821 // allocations because we can't see the call stacks. We'd prefer
803 // to ignore allocations done in files/symbols that match 822 // to ignore allocations done in files/symbols that match
804 // "default_malloc_ex|default_realloc_ex" 823 // "default_malloc_ex|default_realloc_ex"
805 // but that doesn't work when the end-result binary is stripped. 824 // but that doesn't work when the end-result binary is stripped.
825 IsLibraryNamed(library, "/libjvm") ||
826 // JVM has a lot of leaks we don't care about.
827 IsLibraryNamed(library, "/libzip")
828 // The JVM leaks java.util.zip.Inflater after loading classes.
806 ) { 829 ) {
807 depth = 1; // only disable allocation calls directly from the library code 830 depth = 1; // only disable allocation calls directly from the library code
808 } else if (IsLibraryNamed(library, "/ld") 831 } else if (IsLibraryNamed(library, "/ld")
809 // library loader leaks some "system" heap 832 // library loader leaks some "system" heap
810 // (e.g. thread-local storage) that we don't care about 833 // (e.g. thread-local storage) that we don't care about
811 ) { 834 ) {
812 depth = 2; // disable allocation calls directly from the library code 835 depth = 2; // disable allocation calls directly from the library code
813 // and at depth 2 from it. 836 // and at depth 2 from it.
814 // We need depth 2 here solely because of a libc bug that 837 // We need depth 2 here solely because of a libc bug that
815 // forces us to jump through __memalign_hook and MemalignOverride hoops 838 // forces us to jump through __memalign_hook and MemalignOverride hoops
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
852 if (!it.Valid()) { 875 if (!it.Valid()) {
853 int errsv = errno; 876 int errsv = errno;
854 RAW_LOG(ERROR, "Could not open /proc/self/maps: errno=%d. " 877 RAW_LOG(ERROR, "Could not open /proc/self/maps: errno=%d. "
855 "Libraries will not be handled correctly.", errsv); 878 "Libraries will not be handled correctly.", errsv);
856 return CANT_OPEN_PROC_MAPS; 879 return CANT_OPEN_PROC_MAPS;
857 } 880 }
858 uint64 start_address, end_address, file_offset; 881 uint64 start_address, end_address, file_offset;
859 int64 inode; 882 int64 inode;
860 char *permissions, *filename; 883 char *permissions, *filename;
861 bool saw_shared_lib = false; 884 bool saw_shared_lib = false;
885 bool saw_nonzero_inode = false;
886 bool saw_shared_lib_with_nonzero_inode = false;
862 while (it.Next(&start_address, &end_address, &permissions, 887 while (it.Next(&start_address, &end_address, &permissions,
863 &file_offset, &inode, &filename)) { 888 &file_offset, &inode, &filename)) {
864 if (start_address >= end_address) { 889 if (start_address >= end_address) {
865 // Warn if a line we can be interested in is ill-formed: 890 // Warn if a line we can be interested in is ill-formed:
866 if (inode != 0) { 891 if (inode != 0) {
867 RAW_LOG(ERROR, "Errors reading /proc/self/maps. " 892 RAW_LOG(ERROR, "Errors reading /proc/self/maps. "
868 "Some global memory regions will not " 893 "Some global memory regions will not "
869 "be handled correctly."); 894 "be handled correctly.");
870 } 895 }
871 // Silently skip other ill-formed lines: some are possible 896 // Silently skip other ill-formed lines: some are possible
872 // probably due to the interplay of how /proc/self/maps is updated 897 // probably due to the interplay of how /proc/self/maps is updated
873 // while we read it in chunks in ProcMapsIterator and 898 // while we read it in chunks in ProcMapsIterator and
874 // do things in this loop. 899 // do things in this loop.
875 continue; 900 continue;
876 } 901 }
877 // Determine if any shared libraries are present. 902 // Determine if any shared libraries are present (this is the same
878 if (inode != 0 && strstr(filename, "lib") && strstr(filename, ".so")) { 903 // list of extensions as is found in pprof). We want to ignore
904 // 'fake' libraries with inode 0 when determining. However, some
905 // systems don't share inodes via /proc, so we turn off this check
906 // if we don't see any evidence that we're getting inode info.
907 if (inode != 0) {
908 saw_nonzero_inode = true;
909 }
910 if ((strstr(filename, "lib") && strstr(filename, ".so")) ||
911 strstr(filename, ".dll") ||
912 // not all .dylib filenames start with lib. .dylib is big enough
913 // that we are unlikely to get false matches just checking that.
914 strstr(filename, ".dylib") || strstr(filename, ".bundle")) {
879 saw_shared_lib = true; 915 saw_shared_lib = true;
916 if (inode != 0) {
917 saw_shared_lib_with_nonzero_inode = true;
918 }
880 } 919 }
920
881 switch (proc_maps_task) { 921 switch (proc_maps_task) {
882 case DISABLE_LIBRARY_ALLOCS: 922 case DISABLE_LIBRARY_ALLOCS:
883 // All lines starting like 923 // All lines starting like
884 // "401dc000-4030f000 r??p 00132000 03:01 13991972 lib/bin" 924 // "401dc000-4030f000 r??p 00132000 03:01 13991972 lib/bin"
885 // identify a data and code sections of a shared library or our binary 925 // identify a data and code sections of a shared library or our binary
886 if (inode != 0 && strncmp(permissions, "r-xp", 4) == 0) { 926 if (inode != 0 && strncmp(permissions, "r-xp", 4) == 0) {
887 DisableLibraryAllocsLocked(filename, start_address, end_address); 927 DisableLibraryAllocsLocked(filename, start_address, end_address);
888 } 928 }
889 break; 929 break;
890 case RECORD_GLOBAL_DATA: 930 case RECORD_GLOBAL_DATA:
891 RecordGlobalDataLocked(start_address, end_address, 931 RecordGlobalDataLocked(start_address, end_address,
892 permissions, filename); 932 permissions, filename);
893 break; 933 break;
894 default: 934 default:
895 RAW_CHECK(0, ""); 935 RAW_CHECK(0, "");
896 } 936 }
897 } 937 }
938 // If /proc/self/maps is reporting inodes properly (we saw a
939 // non-zero inode), then we only say we saw a shared lib if we saw a
940 // 'real' one, with a non-zero inode.
941 if (saw_nonzero_inode) {
942 saw_shared_lib = saw_shared_lib_with_nonzero_inode;
943 }
898 if (!saw_shared_lib) { 944 if (!saw_shared_lib) {
899 RAW_LOG(ERROR, "No shared libs detected. Will likely report false leak " 945 RAW_LOG(ERROR, "No shared libs detected. Will likely report false leak "
900 "positives for statically linked executables."); 946 "positives for statically linked executables.");
901 return NO_SHARED_LIBS_IN_PROC_MAPS; 947 return NO_SHARED_LIBS_IN_PROC_MAPS;
902 } 948 }
903 return PROC_MAPS_USED; 949 return PROC_MAPS_USED;
904 } 950 }
905 951
906 // Total number and size of live objects dropped from the profile; 952 // Total number and size of live objects dropped from the profile;
907 // (re)initialized in IgnoreAllLiveObjectsLocked. 953 // (re)initialized in IgnoreAllLiveObjectsLocked.
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
955 // We put the registers from other threads here 1001 // We put the registers from other threads here
956 // to make pointers stored in them live. 1002 // to make pointers stored in them live.
957 vector<void*, STL_Allocator<void*, Allocator> > thread_registers; 1003 vector<void*, STL_Allocator<void*, Allocator> > thread_registers;
958 1004
959 int failures = 0; 1005 int failures = 0;
960 for (int i = 0; i < num_threads; ++i) { 1006 for (int i = 0; i < num_threads; ++i) {
961 // the leak checking thread itself is handled 1007 // the leak checking thread itself is handled
962 // specially via self_thread_stack, not here: 1008 // specially via self_thread_stack, not here:
963 if (thread_pids[i] == self_thread_pid) continue; 1009 if (thread_pids[i] == self_thread_pid) continue;
964 RAW_VLOG(11, "Handling thread with pid %d", thread_pids[i]); 1010 RAW_VLOG(11, "Handling thread with pid %d", thread_pids[i]);
965 #if defined(HAVE_LINUX_PTRACE_H) && defined(HAVE_SYS_SYSCALL_H) && defined(DUMPE R) 1011 #if (defined(__i386__) || defined(__x86_64)) && \
1012 defined(HAVE_LINUX_PTRACE_H) && defined(HAVE_SYS_SYSCALL_H) && defined(DUMPE R)
966 i386_regs thread_regs; 1013 i386_regs thread_regs;
967 #define sys_ptrace(r, p, a, d) syscall(SYS_ptrace, (r), (p), (a), (d)) 1014 #define sys_ptrace(r, p, a, d) syscall(SYS_ptrace, (r), (p), (a), (d))
968 // We use sys_ptrace to avoid thread locking 1015 // We use sys_ptrace to avoid thread locking
969 // because this is called from ListAllProcessThreads 1016 // because this is called from ListAllProcessThreads
970 // when all but this thread are suspended. 1017 // when all but this thread are suspended.
971 if (sys_ptrace(PTRACE_GETREGS, thread_pids[i], NULL, &thread_regs) == 0) { 1018 if (sys_ptrace(PTRACE_GETREGS, thread_pids[i], NULL, &thread_regs) == 0) {
972 // Need to use SP to get all the data from the very last stack frame: 1019 // Need to use SP to get all the data from the very last stack frame:
973 COMPILE_ASSERT(sizeof(thread_regs.SP) == sizeof(void*), 1020 COMPILE_ASSERT(sizeof(thread_regs.SP) == sizeof(void*),
974 SP_register_does_not_look_like_a_pointer); 1021 SP_register_does_not_look_like_a_pointer);
975 RegisterStackLocked(reinterpret_cast<void*>(thread_regs.SP)); 1022 RegisterStackLocked(reinterpret_cast<void*>(thread_regs.SP));
(...skipping 650 matching lines...) Expand 10 before | Expand all | Expand 10 after
1626 SpinLockHolder hl(&heap_checker_lock); 1673 SpinLockHolder hl(&heap_checker_lock);
1627 if (heap_checker_on == false) { 1674 if (heap_checker_on == false) {
1628 if (name_ != NULL) { // leak checking enabled when created the checker 1675 if (name_ != NULL) { // leak checking enabled when created the checker
1629 RAW_LOG(WARNING, "Heap leak checker got turned off after checker " 1676 RAW_LOG(WARNING, "Heap leak checker got turned off after checker "
1630 "\"%s\" has been created, no leak check is being done for it!", 1677 "\"%s\" has been created, no leak check is being done for it!",
1631 name_); 1678 name_);
1632 } 1679 }
1633 return true; 1680 return true;
1634 } 1681 }
1635 1682
1683 // Update global_region_caller_ranges. They may need to change since
1684 // e.g. initialization because shared libraries might have been loaded or
1685 // unloaded.
1686 Allocator::DeleteAndNullIfNot(&global_region_caller_ranges);
1687 ProcMapsResult pm_result = UseProcMapsLocked(DISABLE_LIBRARY_ALLOCS);
1688 RAW_CHECK(pm_result == PROC_MAPS_USED, "");
1689
1636 // Keep track of number of internally allocated objects so we 1690 // Keep track of number of internally allocated objects so we
1637 // can detect leaks in the heap-leak-checket itself 1691 // can detect leaks in the heap-leak-checket itself
1638 const int initial_allocs = Allocator::alloc_count(); 1692 const int initial_allocs = Allocator::alloc_count();
1639 1693
1640 if (name_ == NULL) { 1694 if (name_ == NULL) {
1641 RAW_LOG(FATAL, "Heap leak checker must not be turned on " 1695 RAW_LOG(FATAL, "Heap leak checker must not be turned on "
1642 "after construction of a HeapLeakChecker"); 1696 "after construction of a HeapLeakChecker");
1643 } 1697 }
1644 1698
1645 MemoryRegionMap::LockHolder ml; 1699 MemoryRegionMap::LockHolder ml;
1646 int a_local_var; // Use our stack ptr to make stack data live: 1700 int a_local_var; // Use our stack ptr to make stack data live:
1647 1701
1648 // Sanity check that nobody is messing with the hooks we need:
1649 // Important to have it here: else we can misteriously SIGSEGV
1650 // in IgnoreLiveObjectsLocked inside ListAllProcessThreads's callback
1651 // by looking into a region that got unmapped w/o our knowledge.
1652 MemoryRegionMap::CheckMallocHooks();
1653 if (MallocHook::GetNewHook() != NewHook ||
1654 MallocHook::GetDeleteHook() != DeleteHook) {
1655 RAW_LOG(FATAL, "Had our new/delete MallocHook-s replaced. "
1656 "Are you using another MallocHook client? "
1657 "Use --heap_check=\"\" to avoid this conflict.");
1658 }
1659
1660 // Make the heap profile, other threads are locked out. 1702 // Make the heap profile, other threads are locked out.
1661 HeapProfileTable::Snapshot* base = 1703 HeapProfileTable::Snapshot* base =
1662 reinterpret_cast<HeapProfileTable::Snapshot*>(start_snapshot_); 1704 reinterpret_cast<HeapProfileTable::Snapshot*>(start_snapshot_);
1663 RAW_DCHECK(FLAGS_heap_check_pointer_source_alignment > 0, ""); 1705 RAW_DCHECK(FLAGS_heap_check_pointer_source_alignment > 0, "");
1664 pointer_source_alignment = FLAGS_heap_check_pointer_source_alignment; 1706 pointer_source_alignment = FLAGS_heap_check_pointer_source_alignment;
1665 IgnoreAllLiveObjectsLocked(&a_local_var); 1707 IgnoreAllLiveObjectsLocked(&a_local_var);
1666 leaks = heap_profile->NonLiveSnapshot(base); 1708 leaks = heap_profile->NonLiveSnapshot(base);
1667 1709
1668 inuse_bytes_increase_ = static_cast<ssize_t>(leaks->total().alloc_size); 1710 inuse_bytes_increase_ = static_cast<ssize_t>(leaks->total().alloc_size);
1669 inuse_allocs_increase_ = static_cast<ssize_t>(leaks->total().allocs); 1711 inuse_allocs_increase_ = static_cast<ssize_t>(leaks->total().allocs);
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after
1826 // 1868 //
1827 /*static*/ void HeapLeakChecker::RunHeapCleanups() { 1869 /*static*/ void HeapLeakChecker::RunHeapCleanups() {
1828 { SpinLockHolder l(&heap_checker_lock); 1870 { SpinLockHolder l(&heap_checker_lock);
1829 // can get here (via forks?) with other pids 1871 // can get here (via forks?) with other pids
1830 if (heap_checker_pid != getpid()) return; 1872 if (heap_checker_pid != getpid()) return;
1831 } 1873 }
1832 HeapCleaner::RunHeapCleanups(); 1874 HeapCleaner::RunHeapCleanups();
1833 if (!FLAGS_heap_check_after_destructors) DoMainHeapCheck(); 1875 if (!FLAGS_heap_check_after_destructors) DoMainHeapCheck();
1834 } 1876 }
1835 1877
1836 // defined below
1837 static int GetCommandLineFrom(const char* file, char* cmdline, int size);
1838
1839 static bool internal_init_start_has_run = false; 1878 static bool internal_init_start_has_run = false;
1840 1879
1841 // Called exactly once, before main() (but hopefully just before). 1880 // Called exactly once, before main() (but hopefully just before).
1842 // This picks a good unique name for the dumped leak checking heap profiles. 1881 // This picks a good unique name for the dumped leak checking heap profiles.
1843 // 1882 //
1844 // Because we crash when InternalInitStart is called more than once, 1883 // Because we crash when InternalInitStart is called more than once,
1845 // it's fine that we hold heap_checker_lock only around pieces of 1884 // it's fine that we hold heap_checker_lock only around pieces of
1846 // this function: this is still enough for thread-safety w.r.t. other functions 1885 // this function: this is still enough for thread-safety w.r.t. other functions
1847 // of this module. 1886 // of this module.
1848 // We can't hold heap_checker_lock throughout because it would deadlock 1887 // We can't hold heap_checker_lock throughout because it would deadlock
1849 // on a memory allocation since our new/delete hooks can be on. 1888 // on a memory allocation since our new/delete hooks can be on.
1850 // 1889 //
1851 /*static*/ void HeapLeakChecker::InternalInitStart() { 1890 /*static*/ void HeapLeakChecker::InternalInitStart() {
1852 { SpinLockHolder l(&heap_checker_lock); 1891 { SpinLockHolder l(&heap_checker_lock);
1853 RAW_CHECK(!internal_init_start_has_run, 1892 RAW_CHECK(!internal_init_start_has_run,
1854 "Heap-check constructor called twice. Perhaps you both linked" 1893 "Heap-check constructor called twice. Perhaps you both linked"
1855 " in the heap checker, and also used LD_PRELOAD to load it?"); 1894 " in the heap checker, and also used LD_PRELOAD to load it?");
1856 internal_init_start_has_run = true; 1895 internal_init_start_has_run = true;
1857 1896
1858 if (FLAGS_heap_check.empty()) { 1897 if (FLAGS_heap_check.empty()) {
1859 // turns out we do not need checking in the end; can stop profiling 1898 // turns out we do not need checking in the end; can stop profiling
1860 TurnItselfOffLocked(); 1899 TurnItselfOffLocked();
1861 return; 1900 return;
1901 } else if (RunningOnValgrind()) {
1902 // There is no point in trying -- we'll just fail.
1903 RAW_LOG(WARNING, "Can't run under Valgrind; will turn itself off");
1904 TurnItselfOffLocked();
1905 return;
1862 } 1906 }
1863 } 1907 }
1864 1908
1865 // Changing this to false can be useful when debugging heap-checker itself: 1909 // Changing this to false can be useful when debugging heap-checker itself:
1866 if (!FLAGS_heap_check_run_under_gdb) { 1910 if (!FLAGS_heap_check_run_under_gdb && IsDebuggerAttached()) {
1867 // See if heap checker should turn itself off because we are 1911 RAW_LOG(WARNING, "Someone is ptrace()ing us; will turn itself off");
1868 // running under gdb (to avoid conflicts over ptrace-ing rights): 1912 SpinLockHolder l(&heap_checker_lock);
1869 char name_buf[15+15]; 1913 TurnItselfOffLocked();
1870 snprintf(name_buf, sizeof(name_buf), 1914 return;
1871 "/proc/%d/cmdline", static_cast<int>(getppid()));
1872 char cmdline[1024*8]; // /proc/*/cmdline is at most 4Kb anyway usually
1873 int size = GetCommandLineFrom(name_buf, cmdline, sizeof(cmdline)-1);
1874 cmdline[size] = '\0';
1875 // look for "gdb" in the executable's name:
1876 const char* last = strrchr(cmdline, '/');
1877 if (last) last += 1;
1878 else last = cmdline;
1879 if (strncmp(last, "gdb", 3) == 0) {
1880 RAW_LOG(WARNING, "We seem to be running under gdb; will turn itself off");
1881 SpinLockHolder l(&heap_checker_lock);
1882 TurnItselfOffLocked();
1883 return;
1884 }
1885 } 1915 }
1886 1916
1887 { SpinLockHolder l(&heap_checker_lock); 1917 { SpinLockHolder l(&heap_checker_lock);
1888 if (!constructor_heap_profiling) { 1918 if (!constructor_heap_profiling) {
1889 RAW_LOG(FATAL, "Can not start so late. You have to enable heap checking " 1919 RAW_LOG(FATAL, "Can not start so late. You have to enable heap checking "
1890 "with HEAPCHECK=<mode>."); 1920 "with HEAPCHECK=<mode>.");
1891 } 1921 }
1892 } 1922 }
1893 1923
1894 // Set all flags 1924 // Set all flags
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
2077 // static 2107 // static
2078 void HeapLeakChecker::CancelGlobalCheck() { 2108 void HeapLeakChecker::CancelGlobalCheck() {
2079 SpinLockHolder l(&heap_checker_lock); 2109 SpinLockHolder l(&heap_checker_lock);
2080 if (do_main_heap_check) { 2110 if (do_main_heap_check) {
2081 RAW_VLOG(heap_checker_info_level, 2111 RAW_VLOG(heap_checker_info_level,
2082 "Canceling the automatic at-exit whole-program memory leak check"); 2112 "Canceling the automatic at-exit whole-program memory leak check");
2083 do_main_heap_check = false; 2113 do_main_heap_check = false;
2084 } 2114 }
2085 } 2115 }
2086 2116
2087 //----------------------------------------------------------------------
2088 // HeapLeakChecker global constructor/destructor ordering components
2089 //----------------------------------------------------------------------
2090
2091 static bool in_initial_malloc_hook = false;
2092
2093 #ifdef HAVE___ATTRIBUTE__ // we need __attribute__((weak)) for this to work
2094 #define INSTALLED_INITIAL_MALLOC_HOOKS
2095
2096 void HeapLeakChecker_BeforeConstructors(); // below
2097
2098 // Helper for InitialMallocHook_* below
2099 static inline void InitHeapLeakCheckerFromMallocHook() {
2100 { SpinLockHolder l(&heap_checker_lock);
2101 RAW_CHECK(!in_initial_malloc_hook,
2102 "Something did not reset initial MallocHook-s");
2103 in_initial_malloc_hook = true;
2104 }
2105 // Initialize heap checker on the very first allocation/mmap/sbrk call:
2106 HeapLeakChecker_BeforeConstructors();
2107 { SpinLockHolder l(&heap_checker_lock);
2108 in_initial_malloc_hook = false;
2109 }
2110 }
2111
2112 // These will owerwrite the weak definitions in malloc_hook.cc:
2113
2114 // Important to have this to catch the first allocation call from the binary:
2115 extern void InitialMallocHook_New(const void* ptr, size_t size) {
2116 InitHeapLeakCheckerFromMallocHook();
2117 // record this first allocation as well (if we need to):
2118 MallocHook::InvokeNewHook(ptr, size);
2119 }
2120
2121 // Important to have this to catch the first mmap call (say from tcmalloc):
2122 extern void InitialMallocHook_MMap(const void* result,
2123 const void* start,
2124 size_t size,
2125 int protection,
2126 int flags,
2127 int fd,
2128 off_t offset) {
2129 InitHeapLeakCheckerFromMallocHook();
2130 // record this first mmap as well (if we need to):
2131 MallocHook::InvokeMmapHook(
2132 result, start, size, protection, flags, fd, offset);
2133 }
2134
2135 // Important to have this to catch the first sbrk call (say from tcmalloc):
2136 extern void InitialMallocHook_Sbrk(const void* result, std::ptrdiff_t increment) {
2137 InitHeapLeakCheckerFromMallocHook();
2138 // record this first sbrk as well (if we need to):
2139 MallocHook::InvokeSbrkHook(result, increment);
2140 }
2141
2142 // static
2143 void CancelInitialMallocHooks() {
2144 if (MallocHook::GetNewHook() == InitialMallocHook_New) {
2145 MallocHook::SetNewHook(NULL);
2146 }
2147 RAW_DCHECK(MallocHook::GetNewHook() == NULL, "");
2148 if (MallocHook::GetMmapHook() == InitialMallocHook_MMap) {
2149 MallocHook::SetMmapHook(NULL);
2150 }
2151 RAW_DCHECK(MallocHook::GetMmapHook() == NULL, "");
2152 if (MallocHook::GetSbrkHook() == InitialMallocHook_Sbrk) {
2153 MallocHook::SetSbrkHook(NULL);
2154 }
2155 RAW_DCHECK(MallocHook::GetSbrkHook() == NULL, "");
2156 }
2157
2158 #else
2159
2160 // static
2161 void CancelInitialMallocHooks() {}
2162
2163 #endif
2164
2165 // static 2117 // static
2166 void HeapLeakChecker::BeforeConstructorsLocked() { 2118 void HeapLeakChecker::BeforeConstructorsLocked() {
2167 RAW_DCHECK(heap_checker_lock.IsHeld(), ""); 2119 RAW_DCHECK(heap_checker_lock.IsHeld(), "");
2168 RAW_CHECK(!constructor_heap_profiling, 2120 RAW_CHECK(!constructor_heap_profiling,
2169 "BeforeConstructorsLocked called multiple times"); 2121 "BeforeConstructorsLocked called multiple times");
2170 CancelInitialMallocHooks();
2171 // Set hooks early to crash if 'new' gets called before we make heap_profile, 2122 // Set hooks early to crash if 'new' gets called before we make heap_profile,
2172 // and make sure no other hooks existed: 2123 // and make sure no other hooks existed:
2173 if (MallocHook::SetNewHook(NewHook) != NULL || 2124 RAW_CHECK(MallocHook::AddNewHook(&NewHook), "");
2174 MallocHook::SetDeleteHook(DeleteHook) != NULL) { 2125 RAW_CHECK(MallocHook::AddDeleteHook(&DeleteHook), "");
2175 RAW_LOG(FATAL, "Had other new/delete MallocHook-s set. "
2176 "Somehow leak checker got activated "
2177 "after something else have set up these hooks.");
2178 }
2179 constructor_heap_profiling = true; 2126 constructor_heap_profiling = true;
2180 MemoryRegionMap::Init(1); 2127 MemoryRegionMap::Init(1);
2181 // Set up MemoryRegionMap with (at least) one caller stack frame to record 2128 // Set up MemoryRegionMap with (at least) one caller stack frame to record
2182 // (important that it's done before HeapProfileTable creation below). 2129 // (important that it's done before HeapProfileTable creation below).
2183 Allocator::Init(); 2130 Allocator::Init();
2184 RAW_CHECK(heap_profile == NULL, ""); 2131 RAW_CHECK(heap_profile == NULL, "");
2185 heap_profile = new(Allocator::Allocate(sizeof(HeapProfileTable))) 2132 heap_profile = new(Allocator::Allocate(sizeof(HeapProfileTable)))
2186 HeapProfileTable(&Allocator::Allocate, &Allocator::Free); 2133 HeapProfileTable(&Allocator::Allocate, &Allocator::Free);
2187 RAW_VLOG(10, "Starting tracking the heap"); 2134 RAW_VLOG(10, "Starting tracking the heap");
2188 heap_checker_on = true; 2135 heap_checker_on = true;
2189 } 2136 }
2190 2137
2191 // static 2138 // static
2192 void HeapLeakChecker::TurnItselfOffLocked() { 2139 void HeapLeakChecker::TurnItselfOffLocked() {
2193 RAW_DCHECK(heap_checker_lock.IsHeld(), ""); 2140 RAW_DCHECK(heap_checker_lock.IsHeld(), "");
2194 // Set FLAGS_heap_check to "", for users who test for it 2141 // Set FLAGS_heap_check to "", for users who test for it
2195 if (!FLAGS_heap_check.empty()) // be a noop in the common case 2142 if (!FLAGS_heap_check.empty()) // be a noop in the common case
2196 FLAGS_heap_check.clear(); // because clear() could allocate memory 2143 FLAGS_heap_check.clear(); // because clear() could allocate memory
2197 if (constructor_heap_profiling) { 2144 if (constructor_heap_profiling) {
2198 RAW_CHECK(heap_checker_on, ""); 2145 RAW_CHECK(heap_checker_on, "");
2199 RAW_VLOG(heap_checker_info_level, "Turning perftools heap leak checking off" ); 2146 RAW_VLOG(heap_checker_info_level, "Turning perftools heap leak checking off" );
2200 heap_checker_on = false; 2147 heap_checker_on = false;
2201 // Unset our hooks checking they were the ones set: 2148 // Unset our hooks checking they were set:
2202 if (MallocHook::SetNewHook(NULL) != NewHook || 2149 RAW_CHECK(MallocHook::RemoveNewHook(&NewHook), "");
2203 MallocHook::SetDeleteHook(NULL) != DeleteHook) { 2150 RAW_CHECK(MallocHook::RemoveDeleteHook(&DeleteHook), "");
2204 RAW_LOG(FATAL, "Had our new/delete MallocHook-s replaced. "
2205 "Are you using another MallocHook client?");
2206 }
2207 Allocator::DeleteAndNull(&heap_profile); 2151 Allocator::DeleteAndNull(&heap_profile);
2208 // free our optional global data: 2152 // free our optional global data:
2209 Allocator::DeleteAndNullIfNot(&ignored_objects); 2153 Allocator::DeleteAndNullIfNot(&ignored_objects);
2210 Allocator::DeleteAndNullIfNot(&disabled_ranges); 2154 Allocator::DeleteAndNullIfNot(&disabled_ranges);
2211 Allocator::DeleteAndNullIfNot(&global_region_caller_ranges); 2155 Allocator::DeleteAndNullIfNot(&global_region_caller_ranges);
2212 Allocator::Shutdown(); 2156 Allocator::Shutdown();
2213 MemoryRegionMap::Shutdown(); 2157 MemoryRegionMap::Shutdown();
2214 } 2158 }
2215 RAW_CHECK(!heap_checker_on, ""); 2159 RAW_CHECK(!heap_checker_on, "");
2216 } 2160 }
2217 2161
2218 // Read in the command line from 'file' into 'cmdline' and return the size read
2219 // 'size' is the space available in 'cmdline'.
2220 // We need this because we don't yet have argv/argc.
2221 // CAVEAT: 'file' (some /proc/*/cmdline) usually contains the command line
2222 // already truncated (to 4K on Linux).
2223 // Arguments in cmdline will be '\0'-terminated,
2224 // the first one will be the binary's name.
2225 static int GetCommandLineFrom(const char* file, char* cmdline, int size) {
2226 // This routine is only used to check if we're running under gdb, so
2227 // it's ok if this #if fails and the routine is a no-op.
2228 //
2229 // This function is called before memory allocation hooks are set up
2230 // so we must not have any memory allocations in it. We use syscall
2231 // versions of open/read/close here because we don't trust the non-syscall
2232 // versions: they might 'accidentally' cause a memory allocation.
2233 // Here's a real-life problem scenario we had:
2234 // 1) A program LD_PRELOADed a library called list_file_used.a
2235 // 2) list_file_used intercepted open/read/close and called dlsym()
2236 // 3) dlsym() called pthread_setspecific() which called malloc().
2237 // This malloced memory is 'hidden' from the heap-checker. By
2238 // definition, this thread-local data is live, and everything it points
2239 // to is live (not a memory leak) as well. But because this memory
2240 // was hidden from the heap-checker, everything it points to was
2241 // taken to be orphaned, and therefore, a memory leak.
2242 #if defined(_WIN32) || defined(__CYGWIN__) || defined(__CYGWIN32__) || defined(_ _MINGW32__)
2243 // Use a win32 call to get the command line.
2244 const char* command_line = ::GetCommandLine();
2245 strncpy(cmdline, command_line, size);
2246 cmdline[size - 1] = '\0';
2247 return strlen(cmdline);
2248 #elif defined(HAVE_SYS_SYSCALL_H)
2249 int fd = syscall(SYS_open, file, O_RDONLY);
2250 int result = 0;
2251 if (fd >= 0) {
2252 ssize_t r;
2253 while ((r = syscall(SYS_read, fd, cmdline + result, size)) > 0) {
2254 result += r;
2255 size -= r;
2256 }
2257 syscall(SYS_close, fd);
2258 }
2259 return result;
2260 #else
2261 return 0;
2262 #endif
2263 }
2264
2265 extern bool heap_leak_checker_bcad_variable; // in heap-checker-bcad.cc 2162 extern bool heap_leak_checker_bcad_variable; // in heap-checker-bcad.cc
2266 2163
2267 static bool has_called_before_constructors = false; 2164 static bool has_called_before_constructors = false;
2268 2165
2166 // TODO(maxim): inline this function with
2167 // MallocHook_InitAtFirstAllocation_HeapLeakChecker, and also rename
2168 // HeapLeakChecker::BeforeConstructorsLocked.
2269 void HeapLeakChecker_BeforeConstructors() { 2169 void HeapLeakChecker_BeforeConstructors() {
2270 SpinLockHolder l(&heap_checker_lock); 2170 SpinLockHolder l(&heap_checker_lock);
2271 // We can be called from several places: the first mmap/sbrk/alloc call 2171 // We can be called from several places: the first mmap/sbrk/alloc call
2272 // or the first global c-tor from heap-checker-bcad.cc: 2172 // or the first global c-tor from heap-checker-bcad.cc:
2273 // Do not re-execute initialization: 2173 // Do not re-execute initialization:
2274 if (has_called_before_constructors) return; 2174 if (has_called_before_constructors) return;
2275 has_called_before_constructors = true; 2175 has_called_before_constructors = true;
2276 2176
2277 heap_checker_pid = getpid(); // set it always 2177 heap_checker_pid = getpid(); // set it always
2278 heap_leak_checker_bcad_variable = true; 2178 heap_leak_checker_bcad_variable = true;
(...skipping 18 matching lines...) Expand all
2297 if (need_heap_check && getuid() != geteuid()) { 2197 if (need_heap_check && getuid() != geteuid()) {
2298 // heap-checker writes out files. Thus, for security reasons, we don't 2198 // heap-checker writes out files. Thus, for security reasons, we don't
2299 // recognize the env. var. to turn on heap-checking if we're setuid. 2199 // recognize the env. var. to turn on heap-checking if we're setuid.
2300 RAW_LOG(WARNING, ("HeapChecker: ignoring HEAPCHECK because " 2200 RAW_LOG(WARNING, ("HeapChecker: ignoring HEAPCHECK because "
2301 "program seems to be setuid\n")); 2201 "program seems to be setuid\n"));
2302 need_heap_check = false; 2202 need_heap_check = false;
2303 } 2203 }
2304 #endif 2204 #endif
2305 if (need_heap_check) { 2205 if (need_heap_check) {
2306 HeapLeakChecker::BeforeConstructorsLocked(); 2206 HeapLeakChecker::BeforeConstructorsLocked();
2307 } else { // cancel our initial hooks
2308 CancelInitialMallocHooks();
2309 } 2207 }
2310 } 2208 }
2311 2209
2210 // This function overrides the weak function defined in malloc_hook.cc and
2211 // called by one of the initial malloc hooks (malloc_hook.cc) when the very
2212 // first memory allocation or an mmap/sbrk happens. This ensures that
2213 // HeapLeakChecker is initialized and installs all its hooks early enough to
2214 // track absolutely all memory allocations and all memory region acquisitions
2215 // via mmap and sbrk.
2216 extern "C" void MallocHook_InitAtFirstAllocation_HeapLeakChecker() {
2217 HeapLeakChecker_BeforeConstructors();
2218 }
2219
2312 // This function is executed after all global object destructors run. 2220 // This function is executed after all global object destructors run.
2313 void HeapLeakChecker_AfterDestructors() { 2221 void HeapLeakChecker_AfterDestructors() {
2314 { SpinLockHolder l(&heap_checker_lock); 2222 { SpinLockHolder l(&heap_checker_lock);
2315 // can get here (via forks?) with other pids 2223 // can get here (via forks?) with other pids
2316 if (heap_checker_pid != getpid()) return; 2224 if (heap_checker_pid != getpid()) return;
2317 } 2225 }
2318 if (FLAGS_heap_check_after_destructors) { 2226 if (FLAGS_heap_check_after_destructors) {
2319 if (HeapLeakChecker::DoMainHeapCheck()) { 2227 if (HeapLeakChecker::DoMainHeapCheck()) {
2320 const struct timespec sleep_time = { 0, 500000000 }; // 500 ms 2228 const struct timespec sleep_time = { 0, 500000000 }; // 500 ms
2321 nanosleep(&sleep_time, NULL); 2229 nanosleep(&sleep_time, NULL);
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
2381 // static 2289 // static
2382 const void* HeapLeakChecker::GetAllocCaller(void* ptr) { 2290 const void* HeapLeakChecker::GetAllocCaller(void* ptr) {
2383 // this is used only in the unittest, so the heavy checks are fine 2291 // this is used only in the unittest, so the heavy checks are fine
2384 HeapProfileTable::AllocInfo info; 2292 HeapProfileTable::AllocInfo info;
2385 { SpinLockHolder l(&heap_checker_lock); 2293 { SpinLockHolder l(&heap_checker_lock);
2386 RAW_CHECK(heap_profile->FindAllocDetails(ptr, &info), ""); 2294 RAW_CHECK(heap_profile->FindAllocDetails(ptr, &info), "");
2387 } 2295 }
2388 RAW_CHECK(info.stack_depth >= 1, ""); 2296 RAW_CHECK(info.stack_depth >= 1, "");
2389 return info.call_stack[0]; 2297 return info.call_stack[0];
2390 } 2298 }
OLDNEW
« no previous file with comments | « third_party/tcmalloc/chromium/src/google/tcmalloc.h.in ('k') | third_party/tcmalloc/chromium/src/heap-checker-bcad.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698