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

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

Issue 9667026: Revert 126020 - Experiment for updating the tcmalloc chromium branch to r144 (gperftools 2.0). (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 9 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 side-by-side diff with in-line comments
Download patch
Index: third_party/tcmalloc/chromium/src/heap-checker.cc
===================================================================
--- third_party/tcmalloc/chromium/src/heap-checker.cc (revision 126022)
+++ third_party/tcmalloc/chromium/src/heap-checker.cc (working copy)
@@ -52,7 +52,7 @@
#include <time.h>
#include <assert.h>
-#if defined(HAVE_LINUX_PTRACE_H)
+#ifdef HAVE_LINUX_PTRACE_H
#include <linux/ptrace.h>
#endif
#ifdef HAVE_SYS_SYSCALL_H
@@ -73,20 +73,20 @@
#include <algorithm>
#include <functional>
-#include <gperftools/heap-checker.h>
+#include <google/heap-checker.h>
#include "base/basictypes.h"
#include "base/googleinit.h"
#include "base/logging.h"
-#include <gperftools/stacktrace.h>
+#include <google/stacktrace.h>
#include "base/commandlineflags.h"
#include "base/elfcore.h" // for i386_regs
#include "base/thread_lister.h"
#include "heap-profile-table.h"
#include "base/low_level_alloc.h"
#include "malloc_hook-inl.h"
-#include <gperftools/malloc_hook.h>
-#include <gperftools/malloc_extension.h>
+#include <google/malloc_hook.h>
+#include <google/malloc_extension.h>
#include "maybe_threads.h"
#include "memory_region_map.h"
#include "base/spinlock.h"
@@ -144,7 +144,7 @@
"\"minimal\", \"normal\", \"strict\", "
"\"draconian\", \"as-is\", and \"local\" "
" or the empty string are the supported choices. "
- "(See HeapLeakChecker_InternalInitStart for details.)");
+ "(See HeapLeakChecker::InternalInitStart for details.)");
DEFINE_bool(heap_check_report, true, "Obsolete");
@@ -282,6 +282,10 @@
static const int heap_checker_info_level = 0;
//----------------------------------------------------------------------
+// Cancel our InitialMallocHook_* if present.
+static void CancelInitialMallocHooks(); // defined below
+
+//----------------------------------------------------------------------
// HeapLeakChecker's own memory allocator that is
// independent of the normal program allocator.
//----------------------------------------------------------------------
@@ -549,23 +553,6 @@
//----------------------------------------------------------------------
-// We've seen reports that strstr causes heap-checker crashes in some
-// libc's (?):
-// http://code.google.com/p/gperftools/issues/detail?id=263
-// It's simple enough to use our own. This is not in time-critical code.
-static const char* hc_strstr(const char* s1, const char* s2) {
- const size_t len = strlen(s2);
- RAW_CHECK(len > 0, "Unexpected empty string passed to strstr()");
- for (const char* p = strchr(s1, *s2); p != NULL; p = strchr(p+1, *s2)) {
- if (strncmp(p, s2, len) == 0) {
- return p;
- }
- }
- return NULL;
-}
-
-//----------------------------------------------------------------------
-
// Our hooks for MallocHook
static void NewHook(const void* ptr, size_t size) {
if (ptr != NULL) {
@@ -573,11 +560,6 @@
const bool ignore = (counter > 0);
RAW_VLOG(16, "Recording Alloc: %p of %"PRIuS "; %d", ptr, size,
int(counter));
-
- // Fetch the caller's stack trace before acquiring heap_checker_lock.
- void* stack[HeapProfileTable::kMaxStackDepth];
- int depth = HeapProfileTable::GetCallerStackTrace(0, stack);
-
{ SpinLockHolder l(&heap_checker_lock);
if (size > max_heap_object_size) max_heap_object_size = size;
uintptr_t addr = AsInt(ptr);
@@ -585,7 +567,7 @@
addr += size;
if (addr > max_heap_address) max_heap_address = addr;
if (heap_checker_on) {
- heap_profile->RecordAlloc(ptr, size, depth, stack);
+ heap_profile->RecordAlloc(ptr, size, 0);
if (ignore) {
heap_profile->MarkAsIgnored(ptr);
}
@@ -788,8 +770,6 @@
}
}
-static const char kUnnamedProcSelfMapEntry[] = "UNNAMED";
-
// This function takes some fields from a /proc/self/maps line:
//
// start_address start address of a memory region.
@@ -807,9 +787,7 @@
RAW_DCHECK(heap_checker_lock.IsHeld(), "");
// Ignore non-writeable regions.
if (strchr(permissions, 'w') == NULL) return;
- if (filename == NULL || *filename == '\0') {
- filename = kUnnamedProcSelfMapEntry;
- }
+ if (filename == NULL || *filename == '\0') filename = "UNNAMED";
RAW_VLOG(11, "Looking into %s: 0x%" PRIxPTR "..0x%" PRIxPTR,
filename, start_address, end_address);
(*library_live_objects)[filename].
@@ -821,7 +799,7 @@
// See if 'library' from /proc/self/maps has base name 'library_base'
// i.e. contains it and has '.' or '-' after it.
static bool IsLibraryNamed(const char* library, const char* library_base) {
- const char* p = hc_strstr(library, library_base);
+ const char* p = strstr(library, library_base);
size_t sz = strlen(library_base);
return p != NULL && (p[sz] == '.' || p[sz] == '-');
}
@@ -933,11 +911,11 @@
if (inode != 0) {
saw_nonzero_inode = true;
}
- if ((hc_strstr(filename, "lib") && hc_strstr(filename, ".so")) ||
- hc_strstr(filename, ".dll") ||
+ if ((strstr(filename, "lib") && strstr(filename, ".so")) ||
+ strstr(filename, ".dll") ||
// not all .dylib filenames start with lib. .dylib is big enough
// that we are unlikely to get false matches just checking that.
- hc_strstr(filename, ".dylib") || hc_strstr(filename, ".bundle")) {
+ strstr(filename, ".dylib") || strstr(filename, ".bundle")) {
saw_shared_lib = true;
if (inode != 0) {
saw_shared_lib_with_nonzero_inode = true;
@@ -1413,31 +1391,6 @@
}
}
if (size < sizeof(void*)) continue;
-
-#ifdef NO_FRAME_POINTER
- // Frame pointer omission requires us to use libunwind, which uses direct
- // mmap and munmap system calls, and that needs special handling.
- if (name2 == kUnnamedProcSelfMapEntry) {
- static const uintptr_t page_mask = ~(getpagesize() - 1);
- const uintptr_t addr = reinterpret_cast<uintptr_t>(object);
- if ((addr & page_mask) == 0 && (size & page_mask) == 0) {
- // This is an object we slurped from /proc/self/maps.
- // It may or may not be readable at this point.
- //
- // In case all the above conditions made a mistake, and the object is
- // not related to libunwind, we also verify that it's not readable
- // before ignoring it.
- if (msync(const_cast<char*>(object), size, MS_ASYNC) != 0) {
- // Skip unreadable object, so we don't crash trying to sweep it.
- RAW_VLOG(0, "Ignoring inaccessible object [%p, %p) "
- "(msync error %d (%s))",
- object, object + size, errno, strerror(errno));
- continue;
- }
- }
- }
-#endif
-
const char* const max_object = object + size - sizeof(void*);
while (object <= max_object) {
// potentially unaligned load:
@@ -1510,7 +1463,7 @@
}
// static
-void HeapLeakChecker::DoIgnoreObject(const void* ptr) {
+void HeapLeakChecker::IgnoreObject(const void* ptr) {
SpinLockHolder l(&heap_checker_lock);
if (!heap_checker_on) return;
size_t object_size;
@@ -1524,7 +1477,7 @@
IgnoredObjectsMap;
}
if (!ignored_objects->insert(make_pair(AsInt(ptr), object_size)).second) {
- RAW_LOG(WARNING, "Object at %p is already being ignored", ptr);
+ RAW_LOG(FATAL, "Object at %p is already being ignored", ptr);
}
}
}
@@ -1914,18 +1867,16 @@
heap_cleanups_ = NULL;
}
-// Program exit heap cleanup registered as a module object destructor.
+// Program exit heap cleanup registered with atexit().
// Will not get executed when we crash on a signal.
//
-void HeapLeakChecker_RunHeapCleanups() {
- if (FLAGS_heap_check == "local") // don't check heap in this mode
- return;
+/*static*/ void HeapLeakChecker::RunHeapCleanups() {
{ SpinLockHolder l(&heap_checker_lock);
// can get here (via forks?) with other pids
if (heap_checker_pid != getpid()) return;
}
HeapCleaner::RunHeapCleanups();
- if (!FLAGS_heap_check_after_destructors) HeapLeakChecker::DoMainHeapCheck();
+ if (!FLAGS_heap_check_after_destructors) DoMainHeapCheck();
}
static bool internal_init_start_has_run = false;
@@ -1940,26 +1891,21 @@
// We can't hold heap_checker_lock throughout because it would deadlock
// on a memory allocation since our new/delete hooks can be on.
//
-void HeapLeakChecker_InternalInitStart() {
+/*static*/ void HeapLeakChecker::InternalInitStart() {
{ SpinLockHolder l(&heap_checker_lock);
RAW_CHECK(!internal_init_start_has_run,
"Heap-check constructor called twice. Perhaps you both linked"
" in the heap checker, and also used LD_PRELOAD to load it?");
internal_init_start_has_run = true;
-#ifdef ADDRESS_SANITIZER
- // AddressSanitizer's custom malloc conflicts with HeapChecker.
- FLAGS_heap_check = "";
-#endif
-
if (FLAGS_heap_check.empty()) {
// turns out we do not need checking in the end; can stop profiling
- HeapLeakChecker::TurnItselfOffLocked();
+ TurnItselfOffLocked();
return;
} else if (RunningOnValgrind()) {
// There is no point in trying -- we'll just fail.
RAW_LOG(WARNING, "Can't run under Valgrind; will turn itself off");
- HeapLeakChecker::TurnItselfOffLocked();
+ TurnItselfOffLocked();
return;
}
}
@@ -1968,7 +1914,7 @@
if (!FLAGS_heap_check_run_under_gdb && IsDebuggerAttached()) {
RAW_LOG(WARNING, "Someone is ptrace()ing us; will turn itself off");
SpinLockHolder l(&heap_checker_lock);
- HeapLeakChecker::TurnItselfOffLocked();
+ TurnItselfOffLocked();
return;
}
@@ -2019,25 +1965,15 @@
RAW_LOG(FATAL, "Unsupported heap_check flag: %s",
FLAGS_heap_check.c_str());
}
- // FreeBSD doesn't seem to honor atexit execution order:
- // http://code.google.com/p/gperftools/issues/detail?id=375
- // Since heap-checking before destructors depends on atexit running
- // at the right time, on FreeBSD we always check after, even in the
- // less strict modes. This just means FreeBSD is always a bit
- // stricter in its checking than other OSes.
-#ifdef __FreeBSD__
- FLAGS_heap_check_after_destructors = true;
-#endif
-
{ SpinLockHolder l(&heap_checker_lock);
RAW_DCHECK(heap_checker_pid == getpid(), "");
heap_checker_on = true;
RAW_DCHECK(heap_profile, "");
- HeapLeakChecker::ProcMapsResult pm_result = HeapLeakChecker::UseProcMapsLocked(HeapLeakChecker::DISABLE_LIBRARY_ALLOCS);
+ ProcMapsResult pm_result = UseProcMapsLocked(DISABLE_LIBRARY_ALLOCS);
// might neeed to do this more than once
// if one later dynamically loads libraries that we want disabled
- if (pm_result != HeapLeakChecker::PROC_MAPS_USED) { // can't function
- HeapLeakChecker::TurnItselfOffLocked();
+ if (pm_result != PROC_MAPS_USED) { // can't function
+ TurnItselfOffLocked();
return;
}
}
@@ -2091,6 +2027,8 @@
"-- Performance may suffer");
if (FLAGS_heap_check != "local") {
+ // Schedule registered heap cleanup
+ atexit(RunHeapCleanups);
HeapLeakChecker* main_hc = new HeapLeakChecker();
SpinLockHolder l(&heap_checker_lock);
RAW_DCHECK(main_heap_checker == NULL,
@@ -2123,22 +2061,9 @@
// We want this to run early as well, but not so early as
// ::BeforeConstructors (we want flag assignments to have already
// happened, for instance). Initializer-registration does the trick.
-REGISTER_MODULE_INITIALIZER(init_start, HeapLeakChecker_InternalInitStart());
-REGISTER_MODULE_DESTRUCTOR(init_start, HeapLeakChecker_RunHeapCleanups());
+REGISTER_MODULE_INITIALIZER(init_start, HeapLeakChecker::InternalInitStart());
// static
-bool HeapLeakChecker::NoGlobalLeaksMaybeSymbolize(
- ShouldSymbolize should_symbolize) {
- // we never delete or change main_heap_checker once it's set:
- HeapLeakChecker* main_hc = GlobalChecker();
- if (main_hc) {
- RAW_VLOG(10, "Checking for whole-program memory leaks");
- return main_hc->DoNoLeaks(should_symbolize);
- }
- return true;
-}
-
-// static
bool HeapLeakChecker::DoMainHeapCheck() {
if (FLAGS_heap_check_delay_seconds > 0) {
sleep(FLAGS_heap_check_delay_seconds);
@@ -2149,13 +2074,7 @@
do_main_heap_check = false; // will do it now; no need to do it more
}
- // The program is over, so it's safe to symbolize addresses (which
- // requires a fork) because no serious work is expected to be done
- // after this. Symbolizing is really useful -- knowing what
- // function has a leak is better than knowing just an address --
- // and while we can only safely symbolize once in a program run,
- // now is the time (after all, there's no "later" that would be better).
- if (!NoGlobalLeaksMaybeSymbolize(SYMBOLIZE)) {
+ if (!NoGlobalLeaks()) {
if (FLAGS_heap_check_identify_leaks) {
RAW_LOG(FATAL, "Whole-program memory leaks found.");
}
@@ -2175,8 +2094,19 @@
// static
bool HeapLeakChecker::NoGlobalLeaks() {
- // symbolizing requires a fork, which isn't safe to do in general.
- return NoGlobalLeaksMaybeSymbolize(DO_NOT_SYMBOLIZE);
+ // we never delete or change main_heap_checker once it's set:
+ HeapLeakChecker* main_hc = GlobalChecker();
+ if (main_hc) {
+ RAW_VLOG(10, "Checking for whole-program memory leaks");
+ // The program is over, so it's safe to symbolize addresses (which
+ // requires a fork) because no serious work is expected to be done
+ // after this. Symbolizing is really useful -- knowing what
+ // function has a leak is better than knowing just an address --
+ // and while we can only safely symbolize once in a program run,
+ // now is the time (after all, there's no "later" that would be better).
+ return main_hc->DoNoLeaks(SYMBOLIZE);
+ }
+ return true;
}
// static
@@ -2194,10 +2124,6 @@
RAW_DCHECK(heap_checker_lock.IsHeld(), "");
RAW_CHECK(!constructor_heap_profiling,
"BeforeConstructorsLocked called multiple times");
-#ifdef ADDRESS_SANITIZER
- // AddressSanitizer's custom malloc conflicts with HeapChecker.
- return;
-#endif
// Set hooks early to crash if 'new' gets called before we make heap_profile,
// and make sure no other hooks existed:
RAW_CHECK(MallocHook::AddNewHook(&NewHook), "");
« no previous file with comments | « third_party/tcmalloc/chromium/src/gperftools/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