summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAliaksey Kandratsenka <alkondratenko@gmail.com>2017-05-21 22:24:19 -0700
committerAliaksey Kandratsenka <alkondratenko@gmail.com>2017-05-22 01:54:56 -0700
commitbddf862b189c4508d5212f6e0e8ea81c4dd18811 (patch)
treeac82646fa103c7b7e33d2c52515e5cfe0fdb3ce2
parent07a124d8c16bc7d52524ceb9f50d7a65b868e129 (diff)
downloadgperftools-bddf862b189c4508d5212f6e0e8ea81c4dd18811.tar.gz
actually support very early freeing of NULL
This was caught by unit tests on centos 5. Apparently some early thingy is trying to do vprintf which calls free(0). Which used to crash since before size class cache is initialized it'll report hit (with size class 0) for NULL pointer, so we'd miss the case of checking NULL pointer free and crash. The fix is to check for IsInited in the case when thread cache is null, and if so then we escalte to free_null_or_invalid.
-rw-r--r--src/tcmalloc.cc13
-rw-r--r--src/thread_cache.cc5
2 files changed, 16 insertions, 2 deletions
diff --git a/src/tcmalloc.cc b/src/tcmalloc.cc
index 9d718f1..fde8a8a 100644
--- a/src/tcmalloc.cc
+++ b/src/tcmalloc.cc
@@ -999,8 +999,6 @@ size_t TCMallocImplementation::GetEstimatedAllocatedSize(size_t size) {
static int tcmallocguard_refcount = 0; // no lock needed: runs before main()
TCMallocGuard::TCMallocGuard() {
if (tcmallocguard_refcount++ == 0) {
- if (PREDICT_FALSE(!Static::IsInited())) ThreadCache::InitModule();
-
ReplaceSystemAlloc(); // defined in libc_override_*.h
tc_free(tc_malloc(1));
ThreadCache::InitTSD();
@@ -1390,6 +1388,17 @@ void do_free_with_callback(void* ptr,
return;
}
+ if (PREDICT_FALSE(!Static::IsInited())) {
+ // if free was called very early we've could have missed the case
+ // of invalid or nullptr free. I.e. because probing size classes
+ // cache could return bogus result (cl = 0 as of this
+ // writing). But since there is no way we could be dealing with
+ // ptr we've allocated, since successfull malloc implies IsInited,
+ // we can just call invalid_free_fn here.
+ free_null_or_invalid(ptr, invalid_free_fn);
+ return;
+ }
+
// Otherwise, delete directly into central cache
tcmalloc::SLL_SetNext(ptr, NULL);
Static::central_cache()[cl].InsertRange(ptr, ptr, 1);
diff --git a/src/thread_cache.cc b/src/thread_cache.cc
index 7208d35..b31dc96 100644
--- a/src/thread_cache.cc
+++ b/src/thread_cache.cc
@@ -308,6 +308,11 @@ void ThreadCache::InitTSD() {
ThreadCache* ThreadCache::CreateCacheIfNecessary() {
if (!tsd_inited_) {
+#ifndef NDEBUG
+ // tests that freeing nullptr very early is working
+ free(NULL);
+#endif
+
InitModule();
}