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.
This commit is contained in:
Aliaksey Kandratsenka 2017-05-21 22:24:19 -07:00
parent 07a124d8c1
commit bddf862b18
2 changed files with 16 additions and 2 deletions

View File

@ -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);

View File

@ -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();
}