| 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 |