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 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
115 #include <vector> // for vector | 115 #include <vector> // for vector |
116 | 116 |
117 #include <google/malloc_extension.h> | 117 #include <google/malloc_extension.h> |
118 #include <google/malloc_hook.h> // for MallocHook | 118 #include <google/malloc_hook.h> // for MallocHook |
119 #include "base/basictypes.h" // for int64 | 119 #include "base/basictypes.h" // for int64 |
120 #include "base/commandlineflags.h" // for RegisterFlagValidator, etc | 120 #include "base/commandlineflags.h" // for RegisterFlagValidator, etc |
121 #include "base/dynamic_annotations.h" // for RunningOnValgrind | 121 #include "base/dynamic_annotations.h" // for RunningOnValgrind |
122 #include "base/spinlock.h" // for SpinLockHolder | 122 #include "base/spinlock.h" // for SpinLockHolder |
123 #include "central_freelist.h" // for CentralFreeListPadded | 123 #include "central_freelist.h" // for CentralFreeListPadded |
124 #include "common.h" // for StackTrace, kPageShift, etc | 124 #include "common.h" // for StackTrace, kPageShift, etc |
| 125 #include "free_list.h" // for FL_Init |
125 #include "internal_logging.h" // for ASSERT, TCMalloc_Printer, etc | 126 #include "internal_logging.h" // for ASSERT, TCMalloc_Printer, etc |
126 #include "linked_list.h" // for SLL_SetNext | |
127 #include "malloc_hook-inl.h" // for MallocHook::InvokeNewHook, etc | 127 #include "malloc_hook-inl.h" // for MallocHook::InvokeNewHook, etc |
128 #include "page_heap.h" // for PageHeap, PageHeap::Stats | 128 #include "page_heap.h" // for PageHeap, PageHeap::Stats |
129 #include "page_heap_allocator.h" // for PageHeapAllocator | 129 #include "page_heap_allocator.h" // for PageHeapAllocator |
130 #include "span.h" // for Span, DLL_Prepend, etc | 130 #include "span.h" // for Span, DLL_Prepend, etc |
131 #include "stack_trace_table.h" // for StackTraceTable | 131 #include "stack_trace_table.h" // for StackTraceTable |
132 #include "static_vars.h" // for Static | 132 #include "static_vars.h" // for Static |
133 #include "system-alloc.h" // for DumpSystemAllocatorStats, etc | 133 #include "system-alloc.h" // for DumpSystemAllocatorStats, etc |
134 #include "tcmalloc_guard.h" // for TCMallocGuard | 134 #include "tcmalloc_guard.h" // for TCMallocGuard |
135 #include "thread_cache.h" // for ThreadCache | 135 #include "thread_cache.h" // for ThreadCache |
136 | 136 |
137 // We only need malloc.h for struct mallinfo. | 137 // We only need malloc.h for struct mallinfo. |
138 #ifdef HAVE_STRUCT_MALLINFO | 138 #ifdef HAVE_STRUCT_MALLINFO |
139 // Malloc can be in several places on older versions of OS X. | 139 // Malloc can be in several places on older versions of OS X. |
140 # if defined(HAVE_MALLOC_H) | 140 # if defined(HAVE_MALLOC_H) |
141 # include <malloc.h> | 141 # include <malloc.h> |
142 # elif defined(HAVE_SYS_MALLOC_H) | 142 # elif defined(HAVE_SYS_MALLOC_H) |
143 # include <sys/malloc.h> | 143 # include <sys/malloc.h> |
144 # elif defined(HAVE_MALLOC_MALLOC_H) | 144 # elif defined(HAVE_MALLOC_MALLOC_H) |
145 # include <malloc/malloc.h> | 145 # include <malloc/malloc.h> |
146 # endif | 146 # endif |
147 #endif | 147 #endif |
148 | 148 |
149 #if (defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)) && !defi
ned(WIN32_OVERRIDE_ALLOCATORS) | 149 #if (defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)) && !defi
ned(WIN32_OVERRIDE_ALLOCATORS) |
150 # define WIN32_DO_PATCHING 1 | 150 # define WIN32_DO_PATCHING 1 |
151 #endif | 151 #endif |
152 | 152 |
| 153 // GLibc 2.14+ requires the hook functions be declared volatile, based on the |
| 154 // value of the define __MALLOC_HOOK_VOLATILE. For compatibility with |
| 155 // older/non-GLibc implementations, provide an empty definition. |
| 156 #if !defined(__MALLOC_HOOK_VOLATILE) |
| 157 #define __MALLOC_HOOK_VOLATILE |
| 158 #endif |
| 159 |
153 using STL_NAMESPACE::max; | 160 using STL_NAMESPACE::max; |
154 using STL_NAMESPACE::numeric_limits; | 161 using STL_NAMESPACE::numeric_limits; |
155 using STL_NAMESPACE::vector; | 162 using STL_NAMESPACE::vector; |
156 using tcmalloc::AlignmentForSize; | 163 using tcmalloc::AlignmentForSize; |
157 using tcmalloc::PageHeap; | 164 using tcmalloc::PageHeap; |
158 using tcmalloc::PageHeapAllocator; | 165 using tcmalloc::PageHeapAllocator; |
159 using tcmalloc::SizeMap; | 166 using tcmalloc::SizeMap; |
160 using tcmalloc::Span; | 167 using tcmalloc::Span; |
161 using tcmalloc::StackTrace; | 168 using tcmalloc::StackTrace; |
162 using tcmalloc::Static; | 169 using tcmalloc::Static; |
163 using tcmalloc::ThreadCache; | 170 using tcmalloc::ThreadCache; |
164 | 171 |
165 // __THROW is defined in glibc systems. It means, counter-intuitively, | 172 // __THROW is defined in glibc systems. It means, counter-intuitively, |
166 // "This function will never throw an exception." It's an optional | 173 // "This function will never throw an exception." It's an optional |
167 // optimization tool, but we may need to use it to match glibc prototypes. | 174 // optimization tool, but we may need to use it to match glibc prototypes. |
168 #ifndef __THROW // I guess we're not on a glibc system | 175 #ifndef __THROW // I guess we're not on a glibc system |
169 # define __THROW // __THROW is just an optimization, so ok to make it "" | 176 # define __THROW // __THROW is just an optimization, so ok to make it "" |
170 #endif | 177 #endif |
171 | 178 |
| 179 // ---- Double free debug declarations |
| 180 static size_t ExcludeSpaceForMark(size_t size); |
| 181 static void AddRoomForMark(size_t* size); |
| 182 static void ExcludeMarkFromSize(size_t* new_size); |
| 183 static void MarkAllocatedRegion(void* ptr); |
| 184 static void ValidateAllocatedRegion(void* ptr, size_t cl); |
| 185 // ---- End Double free debug declarations |
| 186 |
172 DECLARE_int64(tcmalloc_sample_parameter); | 187 DECLARE_int64(tcmalloc_sample_parameter); |
173 DECLARE_double(tcmalloc_release_rate); | 188 DECLARE_double(tcmalloc_release_rate); |
174 | 189 |
175 // For windows, the printf we use to report large allocs is | 190 // For windows, the printf we use to report large allocs is |
176 // potentially dangerous: it could cause a malloc that would cause an | 191 // potentially dangerous: it could cause a malloc that would cause an |
177 // infinite loop. So by default we set the threshold to a huge number | 192 // infinite loop. So by default we set the threshold to a huge number |
178 // on windows, so this bad situation will never trigger. You can | 193 // on windows, so this bad situation will never trigger. You can |
179 // always set TCMALLOC_LARGE_ALLOC_REPORT_THRESHOLD manually if you | 194 // always set TCMALLOC_LARGE_ALLOC_REPORT_THRESHOLD manually if you |
180 // want this functionality. | 195 // want this functionality. |
181 #ifdef _WIN32 | 196 #ifdef _WIN32 |
(...skipping 14 matching lines...) Expand all Loading... |
196 "is very large and therefore you should see no extra " | 211 "is very large and therefore you should see no extra " |
197 "logging unless the flag is overridden. Set to 0 to " | 212 "logging unless the flag is overridden. Set to 0 to " |
198 "disable reporting entirely."); | 213 "disable reporting entirely."); |
199 | 214 |
200 | 215 |
201 // We already declared these functions in tcmalloc.h, but we have to | 216 // We already declared these functions in tcmalloc.h, but we have to |
202 // declare them again to give them an ATTRIBUTE_SECTION: we want to | 217 // declare them again to give them an ATTRIBUTE_SECTION: we want to |
203 // put all callers of MallocHook::Invoke* in this module into | 218 // put all callers of MallocHook::Invoke* in this module into |
204 // ATTRIBUTE_SECTION(google_malloc) section, so that | 219 // ATTRIBUTE_SECTION(google_malloc) section, so that |
205 // MallocHook::GetCallerStackTrace can function accurately. | 220 // MallocHook::GetCallerStackTrace can function accurately. |
206 #ifndef _WIN32 // windows doesn't have attribute_section, so don't bother | |
207 extern "C" { | 221 extern "C" { |
208 void* tc_malloc(size_t size) __THROW | 222 void* tc_malloc(size_t size) __THROW |
209 ATTRIBUTE_SECTION(google_malloc); | 223 ATTRIBUTE_SECTION(google_malloc); |
210 void tc_free(void* ptr) __THROW | 224 void tc_free(void* ptr) __THROW |
211 ATTRIBUTE_SECTION(google_malloc); | 225 ATTRIBUTE_SECTION(google_malloc); |
212 void* tc_realloc(void* ptr, size_t size) __THROW | 226 void* tc_realloc(void* ptr, size_t size) __THROW |
213 ATTRIBUTE_SECTION(google_malloc); | 227 ATTRIBUTE_SECTION(google_malloc); |
214 void* tc_calloc(size_t nmemb, size_t size) __THROW | 228 void* tc_calloc(size_t nmemb, size_t size) __THROW |
215 ATTRIBUTE_SECTION(google_malloc); | 229 ATTRIBUTE_SECTION(google_malloc); |
216 void tc_cfree(void* ptr) __THROW | 230 void tc_cfree(void* ptr) __THROW |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
258 | 272 |
259 // Some non-standard extensions that we support. | 273 // Some non-standard extensions that we support. |
260 | 274 |
261 // This is equivalent to | 275 // This is equivalent to |
262 // OS X: malloc_size() | 276 // OS X: malloc_size() |
263 // glibc: malloc_usable_size() | 277 // glibc: malloc_usable_size() |
264 // Windows: _msize() | 278 // Windows: _msize() |
265 size_t tc_malloc_size(void* p) __THROW | 279 size_t tc_malloc_size(void* p) __THROW |
266 ATTRIBUTE_SECTION(google_malloc); | 280 ATTRIBUTE_SECTION(google_malloc); |
267 } // extern "C" | 281 } // extern "C" |
268 #endif // #ifndef _WIN32 | |
269 | 282 |
270 // Override the libc functions to prefer our own instead. This comes | 283 // Override the libc functions to prefer our own instead. This comes |
271 // first so code in tcmalloc.cc can use the overridden versions. One | 284 // first so code in tcmalloc.cc can use the overridden versions. One |
272 // exception: in windows, by default, we patch our code into these | 285 // exception: in windows, by default, we patch our code into these |
273 // functions (via src/windows/patch_function.cc) rather than override | 286 // functions (via src/windows/patch_function.cc) rather than override |
274 // them. In that case, we don't want to do this overriding here. | 287 // them. In that case, we don't want to do this overriding here. |
275 #if !defined(WIN32_DO_PATCHING) | 288 #if !defined(WIN32_DO_PATCHING) |
276 | 289 |
| 290 // TODO(mbelshe): Turn off TCMalloc's symbols for libc. We do that |
| 291 // elsewhere. |
| 292 #ifndef _WIN32 |
| 293 |
277 #if defined(__GNUC__) && !defined(__MACH__) | 294 #if defined(__GNUC__) && !defined(__MACH__) |
278 // Potentially faster variants that use the gcc alias extension. | 295 // Potentially faster variants that use the gcc alias extension. |
279 // FreeBSD does support aliases, but apparently not correctly. :-( | 296 // FreeBSD does support aliases, but apparently not correctly. :-( |
280 // NOTE: we make many of these symbols weak, but do so in the makefile | 297 // NOTE: we make many of these symbols weak, but do so in the makefile |
281 // (via objcopy -W) and not here. That ends up being more portable. | 298 // (via objcopy -W) and not here. That ends up being more portable. |
282 # define ALIAS(x) __attribute__ ((alias (x))) | 299 # define ALIAS(x) __attribute__ ((alias (x))) |
283 void* operator new(size_t size) throw (std::bad_alloc) ALIAS("tc_new"); | 300 void* operator new(size_t size) throw (std::bad_alloc) ALIAS("tc_new"); |
284 void operator delete(void* p) __THROW ALIAS("tc_delete"); | 301 void operator delete(void* p) __THROW ALIAS("tc_delete"); |
285 void* operator new[](size_t size) throw (std::bad_alloc) ALIAS("tc_newarray"); | 302 void* operator new[](size_t size) throw (std::bad_alloc) ALIAS("tc_newarray"); |
286 void operator delete[](void* p) __THROW ALIAS("tc_deletearray"); | 303 void operator delete[](void* p) __THROW ALIAS("tc_deletearray"); |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
377 void* __libc_memalign(size_t align, size_t s) { return memalign(align, s); } | 394 void* __libc_memalign(size_t align, size_t s) { return memalign(align, s); } |
378 void* __libc_valloc(size_t size) { return valloc(size); } | 395 void* __libc_valloc(size_t size) { return valloc(size); } |
379 void* __libc_pvalloc(size_t size) { return pvalloc(size); } | 396 void* __libc_pvalloc(size_t size) { return pvalloc(size); } |
380 int __posix_memalign(void** r, size_t a, size_t s) { | 397 int __posix_memalign(void** r, size_t a, size_t s) { |
381 return posix_memalign(r, a, s); | 398 return posix_memalign(r, a, s); |
382 } | 399 } |
383 #endif // #ifdef ALIAS | 400 #endif // #ifdef ALIAS |
384 } // extern "C" | 401 } // extern "C" |
385 #endif // ifdef __GLIBC__ | 402 #endif // ifdef __GLIBC__ |
386 | 403 |
| 404 #if defined(__GLIBC__) && defined(HAVE_MALLOC_H) |
| 405 // If we're using glibc, then override glibc malloc hooks to make sure that even |
| 406 // if calls fall through to ptmalloc (due to dlopen() with RTLD_DEEPBIND or what |
| 407 // not), ptmalloc will use TCMalloc. |
| 408 |
| 409 static void* tc_ptmalloc_malloc_hook(size_t size, const void* caller) { |
| 410 return tc_malloc(size); |
| 411 } |
| 412 |
| 413 void* (*__MALLOC_HOOK_VOLATILE __malloc_hook)( |
| 414 size_t size, const void* caller) = tc_ptmalloc_malloc_hook; |
| 415 |
| 416 static void* tc_ptmalloc_realloc_hook( |
| 417 void* ptr, size_t size, const void* caller) { |
| 418 return tc_realloc(ptr, size); |
| 419 } |
| 420 |
| 421 void* (*__MALLOC_HOOK_VOLATILE __realloc_hook)( |
| 422 void* ptr, size_t size, const void* caller) = tc_ptmalloc_realloc_hook; |
| 423 |
| 424 static void tc_ptmalloc_free_hook(void* ptr, const void* caller) { |
| 425 tc_free(ptr); |
| 426 } |
| 427 |
| 428 void (*__MALLOC_HOOK_VOLATILE __free_hook)(void* ptr, const void* caller) = tc_p
tmalloc_free_hook; |
| 429 |
| 430 #endif |
| 431 |
| 432 #endif // #ifndef _WIN32 |
387 #undef ALIAS | 433 #undef ALIAS |
388 | 434 |
389 #endif // #ifndef(WIN32_DO_PATCHING) | 435 #endif // #ifndef(WIN32_DO_PATCHING) |
390 | 436 |
391 | 437 |
392 // ----------------------- IMPLEMENTATION ------------------------------- | 438 // ----------------------- IMPLEMENTATION ------------------------------- |
393 | 439 |
394 static int tc_new_mode = 0; // See tc_set_new_mode(). | 440 static int tc_new_mode = 0; // See tc_set_new_mode(). |
395 | 441 |
396 // Routines such as free() and realloc() catch some erroneous pointers | 442 // Routines such as free() and realloc() catch some erroneous pointers |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
459 + stats.metadata_bytes); | 505 + stats.metadata_bytes); |
460 const uint64_t physical_memory_used = (virtual_memory_used | 506 const uint64_t physical_memory_used = (virtual_memory_used |
461 - stats.pageheap.unmapped_bytes); | 507 - stats.pageheap.unmapped_bytes); |
462 const uint64_t bytes_in_use_by_app = (physical_memory_used | 508 const uint64_t bytes_in_use_by_app = (physical_memory_used |
463 - stats.metadata_bytes | 509 - stats.metadata_bytes |
464 - stats.pageheap.free_bytes | 510 - stats.pageheap.free_bytes |
465 - stats.central_bytes | 511 - stats.central_bytes |
466 - stats.transfer_bytes | 512 - stats.transfer_bytes |
467 - stats.thread_bytes); | 513 - stats.thread_bytes); |
468 | 514 |
| 515 out->printf( |
| 516 "WASTE: %7.1f MiB committed but not used\n" |
| 517 "WASTE: %7.1f MiB bytes committed, %7.1f MiB bytes in use\n" |
| 518 "WASTE: committed/used ratio of %f\n", |
| 519 (stats.pageheap.committed_bytes - bytes_in_use_by_app) / MiB, |
| 520 stats.pageheap.committed_bytes / MiB, |
| 521 bytes_in_use_by_app / MiB, |
| 522 stats.pageheap.committed_bytes / static_cast<double>(bytes_in_use_by_app) |
| 523 ); |
469 #ifdef TCMALLOC_SMALL_BUT_SLOW | 524 #ifdef TCMALLOC_SMALL_BUT_SLOW |
470 out->printf( | 525 out->printf( |
471 "NOTE: SMALL MEMORY MODEL IS IN USE, PERFORMANCE MAY SUFFER.\n"); | 526 "NOTE: SMALL MEMORY MODEL IS IN USE, PERFORMANCE MAY SUFFER.\n"); |
472 #endif | 527 #endif |
473 out->printf( | 528 out->printf( |
474 "------------------------------------------------\n" | 529 "------------------------------------------------\n" |
475 "MALLOC: %12" PRIu64 " (%7.1f MiB) Bytes in use by application\n" | 530 "MALLOC: %12" PRIu64 " (%7.1f MiB) Bytes in use by application\n" |
| 531 "MALLOC: %12" PRIu64 " (%7.1f MB) Bytes committed\n" |
476 "MALLOC: + %12" PRIu64 " (%7.1f MiB) Bytes in page heap freelist\n" | 532 "MALLOC: + %12" PRIu64 " (%7.1f MiB) Bytes in page heap freelist\n" |
477 "MALLOC: + %12" PRIu64 " (%7.1f MiB) Bytes in central cache freelist\n" | 533 "MALLOC: + %12" PRIu64 " (%7.1f MiB) Bytes in central cache freelist\n" |
478 "MALLOC: + %12" PRIu64 " (%7.1f MiB) Bytes in transfer cache freelist\n" | 534 "MALLOC: + %12" PRIu64 " (%7.1f MiB) Bytes in transfer cache freelist\n" |
479 "MALLOC: + %12" PRIu64 " (%7.1f MiB) Bytes in thread cache freelists\n" | 535 "MALLOC: + %12" PRIu64 " (%7.1f MiB) Bytes in thread cache freelists\n" |
480 "MALLOC: + %12" PRIu64 " (%7.1f MiB) Bytes in malloc metadata\n" | 536 "MALLOC: + %12" PRIu64 " (%7.1f MiB) Bytes in malloc metadata\n" |
481 "MALLOC: ------------\n" | 537 "MALLOC: ------------\n" |
482 "MALLOC: = %12" PRIu64 " (%7.1f MiB) Actual memory used (physical + swap)\
n" | 538 "MALLOC: = %12" PRIu64 " (%7.1f MiB) Actual memory used (physical + swap)\
n" |
483 "MALLOC: + %12" PRIu64 " (%7.1f MiB) Bytes released to OS (aka unmapped)\n
" | 539 "MALLOC: + %12" PRIu64 " (%7.1f MiB) Bytes released to OS (aka unmapped)\n
" |
484 "MALLOC: ------------\n" | 540 "MALLOC: ------------\n" |
485 "MALLOC: = %12" PRIu64 " (%7.1f MiB) Virtual address space used\n" | 541 "MALLOC: = %12" PRIu64 " (%7.1f MiB) Virtual address space used\n" |
486 "MALLOC:\n" | 542 "MALLOC:\n" |
487 "MALLOC: %12" PRIu64 " Spans in use\n" | 543 "MALLOC: %12" PRIu64 " Spans in use\n" |
488 "MALLOC: %12" PRIu64 " Thread heaps in use\n" | 544 "MALLOC: %12" PRIu64 " Thread heaps in use\n" |
489 "MALLOC: %12" PRIu64 " Tcmalloc page size\n" | 545 "MALLOC: %12" PRIu64 " Tcmalloc page size\n" |
490 "------------------------------------------------\n" | 546 "------------------------------------------------\n" |
491 "Call ReleaseFreeMemory() to release freelist memory to the OS" | 547 "Call ReleaseFreeMemory() to release freelist memory to the OS" |
492 " (via madvise()).\n" | 548 " (via madvise()).\n" |
493 "Bytes released to the OS take up virtual address space" | 549 "Bytes released to the OS take up virtual address space" |
494 " but no physical memory.\n", | 550 " but no physical memory.\n", |
495 bytes_in_use_by_app, bytes_in_use_by_app / MiB, | 551 bytes_in_use_by_app, bytes_in_use_by_app / MiB, |
| 552 stats.pageheap.committed_bytes, stats.pageheap.committed_bytes / MiB, |
496 stats.pageheap.free_bytes, stats.pageheap.free_bytes / MiB, | 553 stats.pageheap.free_bytes, stats.pageheap.free_bytes / MiB, |
497 stats.central_bytes, stats.central_bytes / MiB, | 554 stats.central_bytes, stats.central_bytes / MiB, |
498 stats.transfer_bytes, stats.transfer_bytes / MiB, | 555 stats.transfer_bytes, stats.transfer_bytes / MiB, |
499 stats.thread_bytes, stats.thread_bytes / MiB, | 556 stats.thread_bytes, stats.thread_bytes / MiB, |
500 stats.metadata_bytes, stats.metadata_bytes / MiB, | 557 stats.metadata_bytes, stats.metadata_bytes / MiB, |
501 physical_memory_used, physical_memory_used / MiB, | 558 physical_memory_used, physical_memory_used / MiB, |
502 stats.pageheap.unmapped_bytes, stats.pageheap.unmapped_bytes / MiB, | 559 stats.pageheap.unmapped_bytes, stats.pageheap.unmapped_bytes / MiB, |
503 virtual_memory_used, virtual_memory_used / MiB, | 560 virtual_memory_used, virtual_memory_used / MiB, |
504 uint64_t(Static::span_allocator()->inuse()), | 561 uint64_t(Static::span_allocator()->inuse()), |
505 uint64_t(ThreadCache::HeapsInUse()), | 562 uint64_t(ThreadCache::HeapsInUse()), |
(...skipping 459 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
965 | 1022 |
966 static inline bool CheckCachedSizeClass(void *ptr) { | 1023 static inline bool CheckCachedSizeClass(void *ptr) { |
967 PageID p = reinterpret_cast<uintptr_t>(ptr) >> kPageShift; | 1024 PageID p = reinterpret_cast<uintptr_t>(ptr) >> kPageShift; |
968 size_t cached_value = Static::pageheap()->GetSizeClassIfCached(p); | 1025 size_t cached_value = Static::pageheap()->GetSizeClassIfCached(p); |
969 return cached_value == 0 || | 1026 return cached_value == 0 || |
970 cached_value == Static::pageheap()->GetDescriptor(p)->sizeclass; | 1027 cached_value == Static::pageheap()->GetDescriptor(p)->sizeclass; |
971 } | 1028 } |
972 | 1029 |
973 static inline void* CheckedMallocResult(void *result) { | 1030 static inline void* CheckedMallocResult(void *result) { |
974 ASSERT(result == NULL || CheckCachedSizeClass(result)); | 1031 ASSERT(result == NULL || CheckCachedSizeClass(result)); |
| 1032 MarkAllocatedRegion(result); |
975 return result; | 1033 return result; |
976 } | 1034 } |
977 | 1035 |
978 static inline void* SpanToMallocResult(Span *span) { | 1036 static inline void* SpanToMallocResult(Span *span) { |
979 Static::pageheap()->CacheSizeClass(span->start, 0); | 1037 Static::pageheap()->CacheSizeClass(span->start, 0); |
980 return | 1038 return |
981 CheckedMallocResult(reinterpret_cast<void*>(span->start << kPageShift)); | 1039 CheckedMallocResult(reinterpret_cast<void*>(span->start << kPageShift)); |
982 } | 1040 } |
983 | 1041 |
984 static void* DoSampledAllocation(size_t size) { | 1042 static void* DoSampledAllocation(size_t size) { |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1029 for (int i = 0; i < stack.depth; i++) { | 1087 for (int i = 0; i < stack.depth; i++) { |
1030 printer.printf(" %p", stack.stack[i]); | 1088 printer.printf(" %p", stack.stack[i]); |
1031 } | 1089 } |
1032 printer.printf("\n"); | 1090 printer.printf("\n"); |
1033 write(STDERR_FILENO, buffer, strlen(buffer)); | 1091 write(STDERR_FILENO, buffer, strlen(buffer)); |
1034 } | 1092 } |
1035 | 1093 |
1036 inline void* cpp_alloc(size_t size, bool nothrow); | 1094 inline void* cpp_alloc(size_t size, bool nothrow); |
1037 inline void* do_malloc(size_t size); | 1095 inline void* do_malloc(size_t size); |
1038 | 1096 |
1039 // TODO(willchan): Investigate whether or not lining this much is harmful to | 1097 // TODO(willchan): Investigate whether or not inlining this much is harmful to |
1040 // performance. | 1098 // performance. |
1041 // This is equivalent to do_malloc() except when tc_new_mode is set to true. | 1099 // This is equivalent to do_malloc() except when tc_new_mode is set to true. |
1042 // Otherwise, it will run the std::new_handler if set. | 1100 // Otherwise, it will run the std::new_handler if set. |
1043 inline void* do_malloc_or_cpp_alloc(size_t size) { | 1101 inline void* do_malloc_or_cpp_alloc(size_t size) { |
1044 return tc_new_mode ? cpp_alloc(size, true) : do_malloc(size); | 1102 return tc_new_mode ? cpp_alloc(size, true) : do_malloc(size); |
1045 } | 1103 } |
1046 | 1104 |
1047 void* cpp_memalign(size_t align, size_t size); | 1105 void* cpp_memalign(size_t align, size_t size); |
1048 void* do_memalign(size_t align, size_t size); | 1106 void* do_memalign(size_t align, size_t size); |
1049 | 1107 |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1084 report_large = should_report_large(num_pages); | 1142 report_large = should_report_large(num_pages); |
1085 } | 1143 } |
1086 | 1144 |
1087 if (report_large) { | 1145 if (report_large) { |
1088 ReportLargeAlloc(num_pages, result); | 1146 ReportLargeAlloc(num_pages, result); |
1089 } | 1147 } |
1090 return result; | 1148 return result; |
1091 } | 1149 } |
1092 | 1150 |
1093 inline void* do_malloc(size_t size) { | 1151 inline void* do_malloc(size_t size) { |
| 1152 AddRoomForMark(&size); |
| 1153 |
1094 void* ret = NULL; | 1154 void* ret = NULL; |
1095 | 1155 |
1096 // The following call forces module initialization | 1156 // The following call forces module initialization |
1097 ThreadCache* heap = ThreadCache::GetCache(); | 1157 ThreadCache* heap = ThreadCache::GetCache(); |
1098 if (size <= kMaxSize) { | 1158 if (size <= kMaxSize) { |
1099 size_t cl = Static::sizemap()->SizeClass(size); | 1159 size_t cl = Static::sizemap()->SizeClass(size); |
1100 size = Static::sizemap()->class_to_size(cl); | 1160 size = Static::sizemap()->class_to_size(cl); |
1101 | 1161 |
1102 if ((FLAGS_tcmalloc_sample_parameter > 0) && heap->SampleAllocation(size)) { | 1162 if ((FLAGS_tcmalloc_sample_parameter > 0) && heap->SampleAllocation(size)) { |
1103 ret = DoSampledAllocation(size); | 1163 ret = DoSampledAllocation(size); |
| 1164 MarkAllocatedRegion(ret); |
1104 } else { | 1165 } else { |
1105 // The common case, and also the simplest. This just pops the | 1166 // The common case, and also the simplest. This just pops the |
1106 // size-appropriate freelist, after replenishing it if it's empty. | 1167 // size-appropriate freelist, after replenishing it if it's empty. |
1107 ret = CheckedMallocResult(heap->Allocate(size, cl)); | 1168 ret = CheckedMallocResult(heap->Allocate(size, cl)); |
1108 } | 1169 } |
1109 } else { | 1170 } else { |
1110 ret = do_malloc_pages(heap, size); | 1171 ret = do_malloc_pages(heap, size); |
| 1172 MarkAllocatedRegion(ret); |
1111 } | 1173 } |
1112 if (ret == NULL) errno = ENOMEM; | 1174 if (ret == NULL) errno = ENOMEM; |
1113 return ret; | 1175 return ret; |
1114 } | 1176 } |
1115 | 1177 |
1116 inline void* do_calloc(size_t n, size_t elem_size) { | 1178 inline void* do_calloc(size_t n, size_t elem_size) { |
1117 // Overflow check | 1179 // Overflow check |
1118 const size_t size = n * elem_size; | 1180 const size_t size = n * elem_size; |
1119 if (elem_size != 0 && size / elem_size != n) return NULL; | 1181 if (elem_size != 0 && size / elem_size != n) return NULL; |
1120 | 1182 |
(...skipping 27 matching lines...) Expand all Loading... |
1148 // tcmalloc. The latter can happen if tcmalloc is linked in via | 1210 // tcmalloc. The latter can happen if tcmalloc is linked in via |
1149 // a dynamic library, but is not listed last on the link line. | 1211 // a dynamic library, but is not listed last on the link line. |
1150 // In that case, libraries after it on the link line will | 1212 // In that case, libraries after it on the link line will |
1151 // allocate with libc malloc, but free with tcmalloc's free. | 1213 // allocate with libc malloc, but free with tcmalloc's free. |
1152 (*invalid_free_fn)(ptr); // Decide how to handle the bad free request | 1214 (*invalid_free_fn)(ptr); // Decide how to handle the bad free request |
1153 return; | 1215 return; |
1154 } | 1216 } |
1155 cl = span->sizeclass; | 1217 cl = span->sizeclass; |
1156 Static::pageheap()->CacheSizeClass(p, cl); | 1218 Static::pageheap()->CacheSizeClass(p, cl); |
1157 } | 1219 } |
| 1220 |
| 1221 ValidateAllocatedRegion(ptr, cl); |
| 1222 |
1158 if (cl != 0) { | 1223 if (cl != 0) { |
1159 ASSERT(!Static::pageheap()->GetDescriptor(p)->sample); | 1224 ASSERT(!Static::pageheap()->GetDescriptor(p)->sample); |
1160 ThreadCache* heap = GetCacheIfPresent(); | 1225 ThreadCache* heap = GetCacheIfPresent(); |
1161 if (heap != NULL) { | 1226 if (heap != NULL) { |
1162 heap->Deallocate(ptr, cl); | 1227 heap->Deallocate(ptr, cl); |
1163 } else { | 1228 } else { |
1164 // Delete directly into central cache | 1229 // Delete directly into central cache |
1165 tcmalloc::SLL_SetNext(ptr, NULL); | 1230 tcmalloc::FL_Init(ptr); |
1166 Static::central_cache()[cl].InsertRange(ptr, ptr, 1); | 1231 Static::central_cache()[cl].InsertRange(ptr, ptr, 1); |
1167 } | 1232 } |
1168 } else { | 1233 } else { |
1169 SpinLockHolder h(Static::pageheap_lock()); | 1234 SpinLockHolder h(Static::pageheap_lock()); |
1170 ASSERT(reinterpret_cast<uintptr_t>(ptr) % kPageSize == 0); | 1235 ASSERT(reinterpret_cast<uintptr_t>(ptr) % kPageSize == 0); |
1171 ASSERT(span != NULL && span->start == p); | 1236 ASSERT(span != NULL && span->start == p); |
1172 if (span->sample) { | 1237 if (span->sample) { |
1173 StackTrace* st = reinterpret_cast<StackTrace*>(span->objects); | 1238 StackTrace* st = reinterpret_cast<StackTrace*>(span->objects); |
1174 tcmalloc::DLL_Remove(span); | 1239 tcmalloc::DLL_Remove(span); |
1175 Static::stacktrace_allocator()->Delete(st); | 1240 Static::stacktrace_allocator()->Delete(st); |
(...skipping 28 matching lines...) Expand all Loading... |
1204 } | 1269 } |
1205 } | 1270 } |
1206 } | 1271 } |
1207 | 1272 |
1208 // This lets you call back to a given function pointer if ptr is invalid. | 1273 // This lets you call back to a given function pointer if ptr is invalid. |
1209 // It is used primarily by windows code which wants a specialized callback. | 1274 // It is used primarily by windows code which wants a specialized callback. |
1210 inline void* do_realloc_with_callback( | 1275 inline void* do_realloc_with_callback( |
1211 void* old_ptr, size_t new_size, | 1276 void* old_ptr, size_t new_size, |
1212 void (*invalid_free_fn)(void*), | 1277 void (*invalid_free_fn)(void*), |
1213 size_t (*invalid_get_size_fn)(void*)) { | 1278 size_t (*invalid_get_size_fn)(void*)) { |
| 1279 AddRoomForMark(&new_size); |
1214 // Get the size of the old entry | 1280 // Get the size of the old entry |
1215 const size_t old_size = GetSizeWithCallback(old_ptr, invalid_get_size_fn); | 1281 const size_t old_size = GetSizeWithCallback(old_ptr, invalid_get_size_fn); |
1216 | 1282 |
1217 // Reallocate if the new size is larger than the old size, | 1283 // Reallocate if the new size is larger than the old size, |
1218 // or if the new size is significantly smaller than the old size. | 1284 // or if the new size is significantly smaller than the old size. |
1219 // We do hysteresis to avoid resizing ping-pongs: | 1285 // We do hysteresis to avoid resizing ping-pongs: |
1220 // . If we need to grow, grow to max(new_size, old_size * 1.X) | 1286 // . If we need to grow, grow to max(new_size, old_size * 1.X) |
1221 // . Don't shrink unless new_size < old_size * 0.Y | 1287 // . Don't shrink unless new_size < old_size * 0.Y |
1222 // X and Y trade-off time for wasted space. For now we do 1.25 and 0.5. | 1288 // X and Y trade-off time for wasted space. For now we do 1.25 and 0.5. |
1223 const int lower_bound_to_grow = old_size + old_size / 4; | 1289 const int lower_bound_to_grow = old_size + old_size / 4; |
1224 const int upper_bound_to_shrink = old_size / 2; | 1290 const int upper_bound_to_shrink = old_size / 2; |
1225 if ((new_size > old_size) || (new_size < upper_bound_to_shrink)) { | 1291 if ((new_size > old_size) || (new_size < upper_bound_to_shrink)) { |
1226 // Need to reallocate. | 1292 // Need to reallocate. |
1227 void* new_ptr = NULL; | 1293 void* new_ptr = NULL; |
1228 | 1294 |
1229 if (new_size > old_size && new_size < lower_bound_to_grow) { | 1295 if (new_size > old_size && new_size < lower_bound_to_grow) { |
1230 new_ptr = do_malloc_or_cpp_alloc(lower_bound_to_grow); | 1296 new_ptr = do_malloc_or_cpp_alloc(lower_bound_to_grow); |
1231 } | 1297 } |
| 1298 ExcludeMarkFromSize(&new_size); // do_malloc will add space if needed. |
1232 if (new_ptr == NULL) { | 1299 if (new_ptr == NULL) { |
1233 // Either new_size is not a tiny increment, or last do_malloc failed. | 1300 // Either new_size is not a tiny increment, or last do_malloc failed. |
1234 new_ptr = do_malloc_or_cpp_alloc(new_size); | 1301 new_ptr = do_malloc_or_cpp_alloc(new_size); |
1235 } | 1302 } |
1236 if (new_ptr == NULL) { | 1303 if (new_ptr == NULL) { |
1237 return NULL; | 1304 return NULL; |
1238 } | 1305 } |
1239 MallocHook::InvokeNewHook(new_ptr, new_size); | 1306 MallocHook::InvokeNewHook(new_ptr, new_size); |
1240 memcpy(new_ptr, old_ptr, ((old_size < new_size) ? old_size : new_size)); | 1307 memcpy(new_ptr, old_ptr, ((old_size < new_size) ? old_size : new_size)); |
1241 MallocHook::InvokeDeleteHook(old_ptr); | 1308 MallocHook::InvokeDeleteHook(old_ptr); |
1242 // We could use a variant of do_free() that leverages the fact | 1309 // We could use a variant of do_free() that leverages the fact |
1243 // that we already know the sizeclass of old_ptr. The benefit | 1310 // that we already know the sizeclass of old_ptr. The benefit |
1244 // would be small, so don't bother. | 1311 // would be small, so don't bother. |
1245 do_free_with_callback(old_ptr, invalid_free_fn); | 1312 do_free_with_callback(old_ptr, invalid_free_fn); |
1246 return new_ptr; | 1313 return new_ptr; |
1247 } else { | 1314 } else { |
1248 // We still need to call hooks to report the updated size: | 1315 // We still need to call hooks to report the updated size: |
1249 MallocHook::InvokeDeleteHook(old_ptr); | 1316 MallocHook::InvokeDeleteHook(old_ptr); |
| 1317 ExcludeMarkFromSize(&new_size); |
1250 MallocHook::InvokeNewHook(old_ptr, new_size); | 1318 MallocHook::InvokeNewHook(old_ptr, new_size); |
1251 return old_ptr; | 1319 return old_ptr; |
1252 } | 1320 } |
1253 } | 1321 } |
1254 | 1322 |
1255 inline void* do_realloc(void* old_ptr, size_t new_size) { | 1323 inline void* do_realloc(void* old_ptr, size_t new_size) { |
1256 return do_realloc_with_callback(old_ptr, new_size, | 1324 return do_realloc_with_callback(old_ptr, new_size, |
1257 &InvalidFree, &InvalidGetSizeForRealloc); | 1325 &InvalidFree, &InvalidGetSizeForRealloc); |
1258 } | 1326 } |
1259 | 1327 |
1260 // For use by exported routines below that want specific alignments | 1328 // For use by exported routines below that want specific alignments |
1261 // | 1329 // |
1262 // Note: this code can be slow for alignments > 16, and can | 1330 // Note: this code can be slow for alignments > 16, and can |
1263 // significantly fragment memory. The expectation is that | 1331 // significantly fragment memory. The expectation is that |
1264 // memalign/posix_memalign/valloc/pvalloc will not be invoked very | 1332 // memalign/posix_memalign/valloc/pvalloc will not be invoked very |
1265 // often. This requirement simplifies our implementation and allows | 1333 // often. This requirement simplifies our implementation and allows |
1266 // us to tune for expected allocation patterns. | 1334 // us to tune for expected allocation patterns. |
1267 void* do_memalign(size_t align, size_t size) { | 1335 void* do_memalign(size_t align, size_t size) { |
1268 ASSERT((align & (align - 1)) == 0); | 1336 ASSERT((align & (align - 1)) == 0); |
1269 ASSERT(align > 0); | 1337 ASSERT(align > 0); |
| 1338 // Marked in CheckMallocResult(), which is also inside SpanToMallocResult(). |
| 1339 AddRoomForMark(&size); |
1270 if (size + align < size) return NULL; // Overflow | 1340 if (size + align < size) return NULL; // Overflow |
1271 | 1341 |
1272 // Fall back to malloc if we would already align this memory access properly. | 1342 // Fall back to malloc if we would already align this memory access properly. |
1273 if (align <= AlignmentForSize(size)) { | 1343 if (align <= AlignmentForSize(size)) { |
1274 void* p = do_malloc(size); | 1344 void* p = do_malloc(size); |
1275 ASSERT((reinterpret_cast<uintptr_t>(p) % align) == 0); | 1345 ASSERT((reinterpret_cast<uintptr_t>(p) % align) == 0); |
1276 return p; | 1346 return p; |
1277 } | 1347 } |
1278 | 1348 |
1279 if (Static::pageheap() == NULL) ThreadCache::InitModule(); | 1349 if (Static::pageheap() == NULL) ThreadCache::InitModule(); |
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1469 return p; | 1539 return p; |
1470 } | 1540 } |
1471 #endif // PREANSINEW | 1541 #endif // PREANSINEW |
1472 } | 1542 } |
1473 } | 1543 } |
1474 | 1544 |
1475 } // end unnamed namespace | 1545 } // end unnamed namespace |
1476 | 1546 |
1477 // As promised, the definition of this function, declared above. | 1547 // As promised, the definition of this function, declared above. |
1478 size_t TCMallocImplementation::GetAllocatedSize(void* ptr) { | 1548 size_t TCMallocImplementation::GetAllocatedSize(void* ptr) { |
1479 return GetSizeWithCallback(ptr, &InvalidGetAllocatedSize); | 1549 return ExcludeSpaceForMark( |
| 1550 GetSizeWithCallback(ptr, &InvalidGetAllocatedSize)); |
1480 } | 1551 } |
1481 | 1552 |
1482 void TCMallocImplementation::MarkThreadBusy() { | 1553 void TCMallocImplementation::MarkThreadBusy() { |
1483 // Allocate to force the creation of a thread cache, but avoid | 1554 // Allocate to force the creation of a thread cache, but avoid |
1484 // invoking any hooks. | 1555 // invoking any hooks. |
1485 do_free(do_malloc(0)); | 1556 do_free(do_malloc(0)); |
1486 } | 1557 } |
1487 | 1558 |
1488 //------------------------------------------------------------------- | 1559 //------------------------------------------------------------------- |
1489 // Exported routines | 1560 // Exported routines |
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1686 // heap-checker handles this special case explicitly. | 1757 // heap-checker handles this special case explicitly. |
1687 static void *MemalignOverride(size_t align, size_t size, const void *caller) | 1758 static void *MemalignOverride(size_t align, size_t size, const void *caller) |
1688 __THROW ATTRIBUTE_SECTION(google_malloc); | 1759 __THROW ATTRIBUTE_SECTION(google_malloc); |
1689 | 1760 |
1690 static void *MemalignOverride(size_t align, size_t size, const void *caller) | 1761 static void *MemalignOverride(size_t align, size_t size, const void *caller) |
1691 __THROW { | 1762 __THROW { |
1692 void* result = do_memalign_or_cpp_memalign(align, size); | 1763 void* result = do_memalign_or_cpp_memalign(align, size); |
1693 MallocHook::InvokeNewHook(result, size); | 1764 MallocHook::InvokeNewHook(result, size); |
1694 return result; | 1765 return result; |
1695 } | 1766 } |
1696 void *(*__memalign_hook)(size_t, size_t, const void *) = MemalignOverride; | 1767 void *(*__MALLOC_HOOK_VOLATILE __memalign_hook)(size_t, size_t, const void *) =
MemalignOverride; |
| 1768 #endif // TCMALLOC_USING_DEBUGALLOCATION |
1697 | 1769 |
1698 #endif // TCMALLOC_USING_DEBUGALLOCATION | 1770 // ---Double free() debugging implementation ----------------------------------- |
| 1771 // We will put a mark at the extreme end of each allocation block. We make |
| 1772 // sure that we always allocate enough "extra memory" that we can fit in the |
| 1773 // mark, and still provide the requested usable region. If ever that mark is |
| 1774 // not as expected, then we know that the user is corrupting memory beyond their |
| 1775 // request size, or that they have called free a second time without having |
| 1776 // the memory allocated (again). This allows us to spot most double free()s, |
| 1777 // but some can "slip by" or confuse our logic if the caller reallocates memory |
| 1778 // (for a second use) before performing an evil double-free of a first |
| 1779 // allocation |
| 1780 |
| 1781 // This code can be optimized, but for now, it is written to be most easily |
| 1782 // understood, and flexible (since it is evolving a bit). Potential |
| 1783 // optimizations include using other calculated data, such as class size, or |
| 1784 // allocation size, which is known in the code above, but then is recalculated |
| 1785 // below. Another potential optimization would be careful manual inlining of |
| 1786 // code, but I *think* that the compile will probably do this for me, and I've |
| 1787 // been careful to avoid aliasing issues that might make a compiler back-off. |
| 1788 |
| 1789 // Evolution includes experimenting with different marks, to minimize the chance |
| 1790 // that a mark would be misunderstood (missed corruption). The marks are meant |
| 1791 // to be hashed encoding of the location, so that they can't be copied over a |
| 1792 // different region (by accident) without being detected (most of the time). |
| 1793 |
| 1794 // Enable the following define to turn on all the TCMalloc checking. |
| 1795 // It will cost about 2% in performance, but it will catch double frees (most of |
| 1796 // the time), and will often catch allocated-buffer overrun errors. This |
| 1797 // validation is only active when TCMalloc is used as the allocator. |
| 1798 #ifndef NDEBUG |
| 1799 #define TCMALLOC_VALIDATION |
| 1800 #endif |
| 1801 |
| 1802 #if !defined(TCMALLOC_VALIDATION) |
| 1803 |
| 1804 static size_t ExcludeSpaceForMark(size_t size) { return size; } |
| 1805 static void AddRoomForMark(size_t* size) {} |
| 1806 static void ExcludeMarkFromSize(size_t* new_size) {} |
| 1807 static void MarkAllocatedRegion(void* ptr) {} |
| 1808 static void ValidateAllocatedRegion(void* ptr, size_t cl) {} |
| 1809 |
| 1810 #else // TCMALLOC_VALIDATION |
| 1811 |
| 1812 static void DieFromDoubleFree() { |
| 1813 char* p = NULL; |
| 1814 p++; |
| 1815 *p += 1; // Segv. |
| 1816 } |
| 1817 |
| 1818 static size_t DieFromBadFreePointer(void* unused) { |
| 1819 char* p = NULL; |
| 1820 p += 2; |
| 1821 *p += 2; // Segv. |
| 1822 return 0; |
| 1823 } |
| 1824 |
| 1825 static void DieFromMemoryCorruption() { |
| 1826 char* p = NULL; |
| 1827 p += 3; |
| 1828 *p += 3; // Segv. |
| 1829 } |
| 1830 |
| 1831 // We can either do byte marking, or whole word marking based on the following |
| 1832 // define. char is as small as we can get, and word marking probably provides |
| 1833 // more than enough bits that we won't miss a corruption. Any sized integral |
| 1834 // type can be used, but we just define two examples. |
| 1835 |
| 1836 // #define TCMALLOC_SMALL_VALIDATION |
| 1837 #if defined (TCMALLOC_SMALL_VALIDATION) |
| 1838 |
| 1839 typedef char MarkType; // char saves memory... int is more complete. |
| 1840 static const MarkType kAllocationMarkMask = static_cast<MarkType>(0x36); |
| 1841 |
| 1842 #else |
| 1843 |
| 1844 typedef int MarkType; // char saves memory... int is more complete. |
| 1845 static const MarkType kAllocationMarkMask = static_cast<MarkType>(0xE1AB9536); |
| 1846 |
| 1847 #endif |
| 1848 |
| 1849 // TODO(jar): See if use of reference rather than pointer gets better inlining, |
| 1850 // or if macro is needed. My fear is that taking address map preclude register |
| 1851 // allocation :-(. |
| 1852 inline static void AddRoomForMark(size_t* size) { |
| 1853 *size += sizeof(kAllocationMarkMask); |
| 1854 } |
| 1855 |
| 1856 inline static void ExcludeMarkFromSize(size_t* new_size) { |
| 1857 *new_size -= sizeof(kAllocationMarkMask); |
| 1858 } |
| 1859 |
| 1860 inline static size_t ExcludeSpaceForMark(size_t size) { |
| 1861 return size - sizeof(kAllocationMarkMask); // Lie about size when asked. |
| 1862 } |
| 1863 |
| 1864 inline static MarkType* GetMarkLocation(void* ptr) { |
| 1865 size_t class_size = GetSizeWithCallback(ptr, DieFromBadFreePointer); |
| 1866 ASSERT(class_size % sizeof(kAllocationMarkMask) == 0); |
| 1867 size_t last_index = (class_size / sizeof(kAllocationMarkMask)) - 1; |
| 1868 return static_cast<MarkType*>(ptr) + last_index; |
| 1869 } |
| 1870 |
| 1871 // We hash in the mark location plus the pointer so that we effectively mix in |
| 1872 // the size of the block. This means that if a span is used for different sizes |
| 1873 // that the mark will be different. It would be good to hash in the size (which |
| 1874 // we effectively get by using both mark location and pointer), but even better |
| 1875 // would be to also include the class, as it concisely contains the entropy |
| 1876 // found in the size (when we don't have large allocation), and there is less |
| 1877 // risk of losing those bits to truncation. It would probably be good to combine |
| 1878 // the high bits of size (capturing info about large blocks) with the class |
| 1879 // (which is a 6 bit number). |
| 1880 inline static MarkType GetMarkValue(void* ptr, MarkType* mark) { |
| 1881 void* ptr2 = static_cast<void*>(mark); |
| 1882 size_t offset1 = static_cast<char*>(ptr) - static_cast<char*>(NULL); |
| 1883 size_t offset2 = static_cast<char*>(ptr2) - static_cast<char*>(NULL); |
| 1884 static const int kInvariantBits = 2; |
| 1885 ASSERT((offset1 >> kInvariantBits) << kInvariantBits == offset1); |
| 1886 // Note: low bits of both offsets are invariants due to alignment. High bits |
| 1887 // of both offsets are the same (unless we have a large allocation). Avoid |
| 1888 // XORing high bits together, as they will cancel for most small allocations. |
| 1889 |
| 1890 MarkType ret = kAllocationMarkMask; |
| 1891 // Using a little shift, we can safely XOR together both offsets. |
| 1892 ret ^= static_cast<MarkType>(offset1 >> kInvariantBits) ^ |
| 1893 static_cast<MarkType>(offset2); |
| 1894 if (sizeof(ret) == 1) { |
| 1895 // Try to bring some high level bits into the mix. |
| 1896 ret += static_cast<MarkType>(offset1 >> 8) ^ |
| 1897 static_cast<MarkType>(offset1 >> 16) ^ |
| 1898 static_cast<MarkType>(offset1 >> 24) ; |
| 1899 } |
| 1900 // Hash in high bits on a 64 bit architecture. |
| 1901 if (sizeof(size_t) == 8 && sizeof(ret) == 4) |
| 1902 ret += offset1 >> 16; |
| 1903 if (ret == 0) |
| 1904 ret = kAllocationMarkMask; // Avoid common pattern of all zeros. |
| 1905 return ret; |
| 1906 } |
| 1907 |
| 1908 // TODO(jar): Use the passed in TCmalloc Class Index to calculate mark location |
| 1909 // faster. The current implementation calls general functions, which have to |
| 1910 // recalculate this in order to get the Class Size. This is a slow and wasteful |
| 1911 // recomputation... but it is much more readable this way (for now). |
| 1912 static void ValidateAllocatedRegion(void* ptr, size_t cl) { |
| 1913 if (ptr == NULL) return; |
| 1914 MarkType* mark = GetMarkLocation(ptr); |
| 1915 MarkType allocated_mark = GetMarkValue(ptr, mark); |
| 1916 MarkType current_mark = *mark; |
| 1917 |
| 1918 if (current_mark == ~allocated_mark) |
| 1919 DieFromDoubleFree(); |
| 1920 if (current_mark != allocated_mark) |
| 1921 DieFromMemoryCorruption(); |
| 1922 #ifndef NDEBUG |
| 1923 // In debug mode, copy the mark into all the free'd region. |
| 1924 size_t class_size = static_cast<size_t>(reinterpret_cast<char*>(mark) - |
| 1925 reinterpret_cast<char*>(ptr)); |
| 1926 memset(ptr, static_cast<char>(0x36), class_size); |
| 1927 #endif |
| 1928 *mark = ~allocated_mark; // Distinctively not allocated. |
| 1929 } |
| 1930 |
| 1931 static void MarkAllocatedRegion(void* ptr) { |
| 1932 if (ptr == NULL) return; |
| 1933 MarkType* mark = GetMarkLocation(ptr); |
| 1934 *mark = GetMarkValue(ptr, mark); |
| 1935 } |
| 1936 |
| 1937 #endif // TCMALLOC_VALIDATION |
OLD | NEW |