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 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 } |
OLD | NEW |