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

Unified Diff: third_party/tcmalloc/chromium/src/debugallocation.cc

Issue 9311003: Update the tcmalloc chromium branch to r144 (gperftools 2.0), and merge chromium-specific changes. (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Rebasec Created 8 years, 10 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
« no previous file with comments | « third_party/tcmalloc/chromium/src/config.h.in ('k') | third_party/tcmalloc/chromium/src/free_list.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/tcmalloc/chromium/src/debugallocation.cc
diff --git a/third_party/tcmalloc/chromium/src/debugallocation.cc b/third_party/tcmalloc/chromium/src/debugallocation.cc
index 9de927a79a424cdaa3b4ec2dbbf2ff739436bdd0..70ec162bc72121d432bbdf710250aa9a824c63a4 100644
--- a/third_party/tcmalloc/chromium/src/debugallocation.cc
+++ b/third_party/tcmalloc/chromium/src/debugallocation.cc
@@ -31,6 +31,13 @@
// Author: Urs Holzle <opensource@google.com>
#include "config.h"
+#include <errno.h>
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
// We only need malloc.h for struct mallinfo.
#ifdef HAVE_STRUCT_MALLINFO
// Malloc can be in several places on older versions of OS X.
@@ -42,34 +49,29 @@
# include <sys/malloc.h>
# endif
#endif
+#ifdef HAVE_PTHREAD
#include <pthread.h>
-#include <stdio.h>
-#ifdef HAVE_INTTYPES_H
-#include <inttypes.h>
#endif
#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
#ifdef HAVE_MMAP
#include <sys/mman.h>
#endif
-#include <sys/types.h>
#include <sys/stat.h>
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
+#include <sys/types.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
-#include <errno.h>
-#include <string.h>
-#include <google/malloc_extension.h>
-#include <google/malloc_hook.h>
-#include <google/stacktrace.h>
+#include <gperftools/malloc_extension.h>
+#include <gperftools/malloc_hook.h>
+#include <gperftools/stacktrace.h>
+#include "addressmap-inl.h"
#include "base/commandlineflags.h"
#include "base/googleinit.h"
#include "base/logging.h"
#include "base/spinlock.h"
-#include "addressmap-inl.h"
#include "malloc_hook-inl.h"
#include "symbolize.h"
@@ -124,6 +126,13 @@ DEFINE_bool(symbolize_stacktrace,
EnvToBool("TCMALLOC_SYMBOLIZE_STACKTRACE", true),
"Symbolize the stack trace when provided (on some error exits)");
+// If we are LD_PRELOAD-ed against a non-pthreads app, then
+// pthread_once won't be defined. We declare it here, for that
+// case (with weak linkage) which will cause the non-definition to
+// resolve to NULL. We can then check for NULL or not in Instance.
+extern "C" int pthread_once(pthread_once_t *, void (*)(void))
+ ATTRIBUTE_WEAK;
+
// ========================================================================= //
// A safe version of printf() that does not do any allocation and
@@ -134,13 +143,13 @@ static void TracePrintf(int fd, const char *fmt, ...)
// The do_* functions are defined in tcmalloc/tcmalloc.cc,
// which is included before this file
// when TCMALLOC_FOR_DEBUGALLOCATION is defined
-#define BASE_MALLOC_NEW(size) cpp_alloc(size, false)
+// TODO(csilvers): get rid of these now that we are tied to tcmalloc.
+#define BASE_MALLOC_NEW do_malloc
#define BASE_MALLOC do_malloc
#define BASE_FREE do_free
#define BASE_MALLOC_STATS do_malloc_stats
#define BASE_MALLOPT do_mallopt
#define BASE_MALLINFO do_mallinfo
-#define BASE_MALLOC_SIZE(ptr) GetSizeWithCallback(ptr, &InvalidGetAllocatedSize)
// ========================================================================= //
@@ -169,6 +178,7 @@ class FreeQueue {
}
QueueEntry Pop() {
+ RAW_CHECK(q_back_ != q_front_, "Queue is empty");
const QueueEntry& ret = q_[q_back_];
q_back_ = (q_back_ + 1) % kFreeQueueSize;
return ret;
@@ -191,7 +201,7 @@ struct MallocBlockQueueEntry {
MallocBlockQueueEntry() : block(NULL), size(0),
num_deleter_pcs(0), deleter_threadid(0) {}
MallocBlockQueueEntry(MallocBlock* b, size_t s) : block(b), size(s) {
- if (FLAGS_max_free_queue_size != 0) {
+ if (FLAGS_max_free_queue_size != 0 && b != NULL) {
// Adjust the number of frames to skip (4) if you change the
// location of this call.
num_deleter_pcs =
@@ -266,7 +276,8 @@ class MallocBlock {
// This array will be filled with 0xCD, for use with memcmp.
static unsigned char kMagicDeletedBuffer[1024];
- static bool deleted_buffer_initialized_;
+ static pthread_once_t deleted_buffer_initialized_;
+ static bool deleted_buffer_initialized_no_pthreads_;
private: // data layout
@@ -561,14 +572,18 @@ class MallocBlock {
static void ProcessFreeQueue(MallocBlock* b, size_t size,
int max_free_queue_size) {
- SpinLockHolder l(&free_queue_lock_);
+ // MallocBlockQueueEntry are about 144 in size, so we can only
+ // use a small array of them on the stack.
+ MallocBlockQueueEntry entries[4];
+ int num_entries = 0;
+ MallocBlockQueueEntry new_entry(b, size);
+ free_queue_lock_.Lock();
if (free_queue_ == NULL)
free_queue_ = new FreeQueue<MallocBlockQueueEntry>;
RAW_CHECK(!free_queue_->Full(), "Free queue mustn't be full!");
if (b != NULL) {
free_queue_size_ += size + sizeof(MallocBlockQueueEntry);
- MallocBlockQueueEntry new_entry(b, size);
free_queue_->Push(new_entry);
}
@@ -576,20 +591,46 @@ class MallocBlock {
// max_free_queue_size, and the free queue has at least one free
// space in it.
while (free_queue_size_ > max_free_queue_size || free_queue_->Full()) {
- MallocBlockQueueEntry cur = free_queue_->Pop();
- CheckForDanglingWrites(cur);
- free_queue_size_ -= cur.size + sizeof(MallocBlockQueueEntry);
- BASE_FREE(cur.block);
+ RAW_CHECK(num_entries < arraysize(entries), "entries array overflow");
+ entries[num_entries] = free_queue_->Pop();
+ free_queue_size_ -=
+ entries[num_entries].size + sizeof(MallocBlockQueueEntry);
+ num_entries++;
+ if (num_entries == arraysize(entries)) {
+ // The queue will not be full at this point, so it is ok to
+ // release the lock. The queue may still contain more than
+ // max_free_queue_size, but this is not a strict invariant.
+ free_queue_lock_.Unlock();
+ for (int i = 0; i < num_entries; i++) {
+ CheckForDanglingWrites(entries[i]);
+ BASE_FREE(entries[i].block);
+ }
+ num_entries = 0;
+ free_queue_lock_.Lock();
+ }
}
RAW_CHECK(free_queue_size_ >= 0, "Free queue size went negative!");
+ free_queue_lock_.Unlock();
+ for (int i = 0; i < num_entries; i++) {
+ CheckForDanglingWrites(entries[i]);
+ BASE_FREE(entries[i].block);
+ }
+ }
+
+ static void InitDeletedBuffer() {
+ memset(kMagicDeletedBuffer, kMagicDeletedByte, sizeof(kMagicDeletedBuffer));
+ deleted_buffer_initialized_no_pthreads_ = true;
}
static void CheckForDanglingWrites(const MallocBlockQueueEntry& queue_entry) {
// Initialize the buffer if necessary.
- if (!deleted_buffer_initialized_) {
- // This is threadsafe. We hold free_queue_lock_.
- memset(kMagicDeletedBuffer, 0xcd, sizeof(kMagicDeletedBuffer));
- deleted_buffer_initialized_ = true;
+ if (pthread_once)
+ pthread_once(&deleted_buffer_initialized_, &InitDeletedBuffer);
+ if (!deleted_buffer_initialized_no_pthreads_) {
+ // This will be the case on systems that don't link in pthreads,
+ // including on FreeBSD where pthread_once has a non-zero address
+ // (but doesn't do anything) even when pthreads isn't linked in.
+ InitDeletedBuffer();
}
const unsigned char* p =
@@ -625,9 +666,9 @@ class MallocBlock {
// lines we'll output:
if (size_of_buffer <= 1024) {
for (int i = 0; i < size_of_buffer; ++i) {
- if (buffer[i] != 0xcd) {
- RAW_LOG(ERROR, "Buffer byte %d is 0x%02x (should be 0xcd).",
- i, buffer[i]);
+ if (buffer[i] != kMagicDeletedByte) {
+ RAW_LOG(ERROR, "Buffer byte %d is 0x%02x (should be 0x%02x).",
+ i, buffer[i], kMagicDeletedByte);
}
}
} else {
@@ -671,8 +712,10 @@ class MallocBlock {
RAW_LOG(FATAL,
"Memory was written to after being freed. MallocBlock: %p, user "
"ptr: %p, size: %zd. If you can't find the source of the error, "
- "try using valgrind or purify, or study the output of the "
- "deleter's stack printed above.", b, b->data_addr(), size);
+ "try using ASan (http://code.google.com/p/address-sanitizer/), "
+ "Valgrind, or Purify, or study the "
+ "output of the deleter's stack printed above.",
+ b, b->data_addr(), size);
}
static MallocBlock* FromRawPointer(void* p) {
@@ -699,7 +742,7 @@ class MallocBlock {
return FromRawPointer(const_cast<void*>(p));
}
- void Check(int type) {
+ void Check(int type) const {
alloc_map_lock_.Lock();
CheckLocked(type);
alloc_map_lock_.Unlock();
@@ -777,7 +820,8 @@ size_t MallocBlock::free_queue_size_ = 0;
SpinLock MallocBlock::free_queue_lock_(SpinLock::LINKER_INITIALIZED);
unsigned char MallocBlock::kMagicDeletedBuffer[1024];
-bool MallocBlock::deleted_buffer_initialized_ = false;
+pthread_once_t MallocBlock::deleted_buffer_initialized_ = PTHREAD_ONCE_INIT;
+bool MallocBlock::deleted_buffer_initialized_no_pthreads_ = false;
const char* const MallocBlock::kAllocName[] = {
"malloc",
@@ -971,17 +1015,17 @@ class DebugMallocImplementation : public TCMallocImplementation {
return result;
}
- virtual bool VerifyNewMemory(void* p) {
+ virtual bool VerifyNewMemory(const void* p) {
if (p) MallocBlock::FromRawPointer(p)->Check(MallocBlock::kNewType);
return true;
}
- virtual bool VerifyArrayNewMemory(void* p) {
+ virtual bool VerifyArrayNewMemory(const void* p) {
if (p) MallocBlock::FromRawPointer(p)->Check(MallocBlock::kArrayNewType);
return true;
}
- virtual bool VerifyMallocMemory(void* p) {
+ virtual bool VerifyMallocMemory(const void* p) {
if (p) MallocBlock::FromRawPointer(p)->Check(MallocBlock::kMallocType);
return true;
}
@@ -995,14 +1039,25 @@ class DebugMallocImplementation : public TCMallocImplementation {
return MallocBlock::MemoryStats(blocks, total, histogram);
}
- virtual size_t GetAllocatedSize(void* p) {
+ virtual size_t GetEstimatedAllocatedSize(size_t size) {
+ return size;
+ }
+
+ virtual size_t GetAllocatedSize(const void* p) {
if (p) {
+ RAW_CHECK(GetOwnership(p) != MallocExtension::kNotOwned,
+ "ptr not allocated by tcmalloc");
return MallocBlock::FromRawPointer(p)->data_size();
}
return 0;
}
- virtual size_t GetEstimatedAllocatedSize(size_t size) {
- return size;
+
+ virtual MallocExtension::Ownership GetOwnership(const void* p) {
+ if (p) {
+ const MallocBlock* mb = MallocBlock::FromRawPointer(p);
+ return TCMallocImplementation::GetOwnership(mb);
+ }
+ return MallocExtension::kNotOwned; // nobody owns NULL
}
virtual void GetFreeListSizes(vector<MallocExtension::FreeListInfo>* v) {
@@ -1024,22 +1079,28 @@ static DebugMallocImplementation debug_malloc_implementation;
REGISTER_MODULE_INITIALIZER(debugallocation, {
// Either we or valgrind will control memory management. We
- // register our extension if we're the winner.
- if (RunningOnValgrind()) {
- // Let Valgrind uses its own malloc (so don't register our extension).
- } else {
+ // register our extension if we're the winner. Otherwise let
+ // Valgrind use its own malloc (so don't register our extension).
+ if (!RunningOnValgrind()) {
MallocExtension::Register(&debug_malloc_implementation);
+ }
+});
+
+REGISTER_MODULE_DESTRUCTOR(debugallocation, {
+ if (!RunningOnValgrind()) {
// When the program exits, check all blocks still in the free
// queue for corruption.
- atexit(DanglingWriteChecker);
+ DanglingWriteChecker();
}
});
// ========================================================================= //
// This is mostly the same a cpp_alloc in tcmalloc.cc.
-// TODO(csilvers): write a wrapper for new-handler so we don't have to
-// copy this code so much.
+// TODO(csilvers): change Allocate() above to call cpp_alloc, so we
+// don't have to reproduce the logic here. To make tc_new_mode work
+// properly, I think we'll need to separate out the logic of throwing
+// from the logic of calling the new-handler.
inline void* debug_cpp_alloc(size_t size, int new_type, bool nothrow) {
for (;;) {
void* p = DebugAllocate(size, new_type);
@@ -1355,29 +1416,5 @@ extern "C" PERFTOOLS_DLL_DECL struct mallinfo tc_mallinfo(void) __THROW {
#endif
extern "C" PERFTOOLS_DLL_DECL size_t tc_malloc_size(void* ptr) __THROW {
- if (!ptr) {
- return 0;
- }
- MallocBlock* mb = MallocBlock::FromRawPointer(ptr);
- // This is just to make sure we actually own mb (and ptr). We don't
- // use the actual value, just the 'exception' it raises on error.
- (void)BASE_MALLOC_SIZE(mb);
- return mb->data_size();
-}
-
-// Override __libc_memalign in libc on linux boxes.
-// They have a bug in libc that causes them (very rarely) to allocate
-// with __libc_memalign() yet deallocate with free().
-// This function is an exception to the rule of calling MallocHook method
-// from the stack frame of the allocation function;
-// heap-checker handles this special case explicitly.
-static void *MemalignOverride(size_t align, size_t size, const void *caller)
- __THROW ATTRIBUTE_SECTION(google_malloc);
-
-static void *MemalignOverride(size_t align, size_t size, const void *caller)
- __THROW {
- void *p = do_debug_memalign_or_debug_cpp_memalign(align, size);
- MallocHook::InvokeNewHook(p, size);
- return p;
+ return MallocExtension::instance()->GetAllocatedSize(ptr);
}
-void *(*__memalign_hook)(size_t, size_t, const void *) = MemalignOverride;
« no previous file with comments | « third_party/tcmalloc/chromium/src/config.h.in ('k') | third_party/tcmalloc/chromium/src/free_list.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698