1 //===-- sanitizer_allocator_test.cc ---------------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file is a part of ThreadSanitizer/AddressSanitizer runtime. 11 // Tests for sanitizer_allocator.h. 12 // 13 //===----------------------------------------------------------------------===// 14 #include "sanitizer_common/sanitizer_allocator.h" 15 #include "sanitizer_common/sanitizer_allocator_internal.h" 16 #include "sanitizer_common/sanitizer_common.h" 17 #include "sanitizer_common/sanitizer_flags.h" 18 19 #include "sanitizer_test_utils.h" 20 #include "sanitizer_pthread_wrappers.h" 21 22 #include "gtest/gtest.h" 23 24 #include <stdlib.h> 25 #include <algorithm> 26 #include <vector> 27 #include <set> 28 29 // Too slow for debug build 30 #if TSAN_DEBUG == 0 31 32 #if SANITIZER_WORDSIZE == 64 33 static const uptr kAllocatorSpace = 0x700000000000ULL; 34 static const uptr kAllocatorSize = 0x010000000000ULL; // 1T. 35 static const u64 kAddressSpaceSize = 1ULL << 47; 36 37 typedef SizeClassAllocator64< 38 kAllocatorSpace, kAllocatorSize, 16, DefaultSizeClassMap> Allocator64; 39 40 typedef SizeClassAllocator64< 41 kAllocatorSpace, kAllocatorSize, 16, CompactSizeClassMap> Allocator64Compact; 42 #else 43 static const u64 kAddressSpaceSize = 1ULL << 32; 44 #endif 45 46 static const uptr kRegionSizeLog = FIRST_32_SECOND_64(20, 24); 47 static const uptr kFlatByteMapSize = kAddressSpaceSize >> kRegionSizeLog; 48 49 typedef SizeClassAllocator32< 50 0, kAddressSpaceSize, 51 /*kMetadataSize*/16, 52 CompactSizeClassMap, 53 kRegionSizeLog, 54 FlatByteMap<kFlatByteMapSize> > 55 Allocator32Compact; 56 57 template <class SizeClassMap> 58 void TestSizeClassMap() { 59 typedef SizeClassMap SCMap; 60 // SCMap::Print(); 61 SCMap::Validate(); 62 } 63 64 TEST(SanitizerCommon, DefaultSizeClassMap) { 65 TestSizeClassMap<DefaultSizeClassMap>(); 66 } 67 68 TEST(SanitizerCommon, CompactSizeClassMap) { 69 TestSizeClassMap<CompactSizeClassMap>(); 70 } 71 72 TEST(SanitizerCommon, InternalSizeClassMap) { 73 TestSizeClassMap<InternalSizeClassMap>(); 74 } 75 76 template <class Allocator> 77 void TestSizeClassAllocator() { 78 Allocator *a = new Allocator; 79 a->Init(); 80 SizeClassAllocatorLocalCache<Allocator> cache; 81 memset(&cache, 0, sizeof(cache)); 82 cache.Init(0); 83 84 static const uptr sizes[] = {1, 16, 30, 40, 100, 1000, 10000, 85 50000, 60000, 100000, 120000, 300000, 500000, 1000000, 2000000}; 86 87 std::vector<void *> allocated; 88 89 uptr last_total_allocated = 0; 90 for (int i = 0; i < 3; i++) { 91 // Allocate a bunch of chunks. 92 for (uptr s = 0; s < ARRAY_SIZE(sizes); s++) { 93 uptr size = sizes[s]; 94 if (!a->CanAllocate(size, 1)) continue; 95 // printf("s = %ld\n", size); 96 uptr n_iter = std::max((uptr)6, 8000000 / size); 97 // fprintf(stderr, "size: %ld iter: %ld\n", size, n_iter); 98 for (uptr i = 0; i < n_iter; i++) { 99 uptr class_id0 = Allocator::SizeClassMapT::ClassID(size); 100 char *x = (char*)cache.Allocate(a, class_id0); 101 x[0] = 0; 102 x[size - 1] = 0; 103 x[size / 2] = 0; 104 allocated.push_back(x); 105 CHECK_EQ(x, a->GetBlockBegin(x)); 106 CHECK_EQ(x, a->GetBlockBegin(x + size - 1)); 107 CHECK(a->PointerIsMine(x)); 108 CHECK(a->PointerIsMine(x + size - 1)); 109 CHECK(a->PointerIsMine(x + size / 2)); 110 CHECK_GE(a->GetActuallyAllocatedSize(x), size); 111 uptr class_id = a->GetSizeClass(x); 112 CHECK_EQ(class_id, Allocator::SizeClassMapT::ClassID(size)); 113 uptr *metadata = reinterpret_cast<uptr*>(a->GetMetaData(x)); 114 metadata[0] = reinterpret_cast<uptr>(x) + 1; 115 metadata[1] = 0xABCD; 116 } 117 } 118 // Deallocate all. 119 for (uptr i = 0; i < allocated.size(); i++) { 120 void *x = allocated[i]; 121 uptr *metadata = reinterpret_cast<uptr*>(a->GetMetaData(x)); 122 CHECK_EQ(metadata[0], reinterpret_cast<uptr>(x) + 1); 123 CHECK_EQ(metadata[1], 0xABCD); 124 cache.Deallocate(a, a->GetSizeClass(x), x); 125 } 126 allocated.clear(); 127 uptr total_allocated = a->TotalMemoryUsed(); 128 if (last_total_allocated == 0) 129 last_total_allocated = total_allocated; 130 CHECK_EQ(last_total_allocated, total_allocated); 131 } 132 133 // Check that GetBlockBegin never crashes. 134 for (uptr x = 0, step = kAddressSpaceSize / 100000; 135 x < kAddressSpaceSize - step; x += step) 136 if (a->PointerIsMine(reinterpret_cast<void *>(x))) 137 Ident(a->GetBlockBegin(reinterpret_cast<void *>(x))); 138 139 a->TestOnlyUnmap(); 140 delete a; 141 } 142 143 #if SANITIZER_WORDSIZE == 64 144 TEST(SanitizerCommon, SizeClassAllocator64) { 145 TestSizeClassAllocator<Allocator64>(); 146 } 147 148 TEST(SanitizerCommon, SizeClassAllocator64Compact) { 149 TestSizeClassAllocator<Allocator64Compact>(); 150 } 151 #endif 152 153 TEST(SanitizerCommon, SizeClassAllocator32Compact) { 154 TestSizeClassAllocator<Allocator32Compact>(); 155 } 156 157 template <class Allocator> 158 void SizeClassAllocatorMetadataStress() { 159 Allocator *a = new Allocator; 160 a->Init(); 161 SizeClassAllocatorLocalCache<Allocator> cache; 162 memset(&cache, 0, sizeof(cache)); 163 cache.Init(0); 164 165 const uptr kNumAllocs = 1 << 13; 166 void *allocated[kNumAllocs]; 167 void *meta[kNumAllocs]; 168 for (uptr i = 0; i < kNumAllocs; i++) { 169 void *x = cache.Allocate(a, 1 + i % 50); 170 allocated[i] = x; 171 meta[i] = a->GetMetaData(x); 172 } 173 // Get Metadata kNumAllocs^2 times. 174 for (uptr i = 0; i < kNumAllocs * kNumAllocs; i++) { 175 uptr idx = i % kNumAllocs; 176 void *m = a->GetMetaData(allocated[idx]); 177 EXPECT_EQ(m, meta[idx]); 178 } 179 for (uptr i = 0; i < kNumAllocs; i++) { 180 cache.Deallocate(a, 1 + i % 50, allocated[i]); 181 } 182 183 a->TestOnlyUnmap(); 184 delete a; 185 } 186 187 #if SANITIZER_WORDSIZE == 64 188 TEST(SanitizerCommon, SizeClassAllocator64MetadataStress) { 189 SizeClassAllocatorMetadataStress<Allocator64>(); 190 } 191 192 TEST(SanitizerCommon, SizeClassAllocator64CompactMetadataStress) { 193 SizeClassAllocatorMetadataStress<Allocator64Compact>(); 194 } 195 #endif // SANITIZER_WORDSIZE == 64 196 TEST(SanitizerCommon, SizeClassAllocator32CompactMetadataStress) { 197 SizeClassAllocatorMetadataStress<Allocator32Compact>(); 198 } 199 200 template <class Allocator> 201 void SizeClassAllocatorGetBlockBeginStress() { 202 Allocator *a = new Allocator; 203 a->Init(); 204 SizeClassAllocatorLocalCache<Allocator> cache; 205 memset(&cache, 0, sizeof(cache)); 206 cache.Init(0); 207 208 uptr max_size_class = Allocator::kNumClasses - 1; 209 uptr size = Allocator::SizeClassMapT::Size(max_size_class); 210 u64 G8 = 1ULL << 33; 211 // Make sure we correctly compute GetBlockBegin() w/o overflow. 212 for (size_t i = 0; i <= G8 / size; i++) { 213 void *x = cache.Allocate(a, max_size_class); 214 void *beg = a->GetBlockBegin(x); 215 // if ((i & (i - 1)) == 0) 216 // fprintf(stderr, "[%zd] %p %p\n", i, x, beg); 217 EXPECT_EQ(x, beg); 218 } 219 220 a->TestOnlyUnmap(); 221 delete a; 222 } 223 224 #if SANITIZER_WORDSIZE == 64 225 TEST(SanitizerCommon, SizeClassAllocator64GetBlockBegin) { 226 SizeClassAllocatorGetBlockBeginStress<Allocator64>(); 227 } 228 TEST(SanitizerCommon, SizeClassAllocator64CompactGetBlockBegin) { 229 SizeClassAllocatorGetBlockBeginStress<Allocator64Compact>(); 230 } 231 TEST(SanitizerCommon, SizeClassAllocator32CompactGetBlockBegin) { 232 SizeClassAllocatorGetBlockBeginStress<Allocator32Compact>(); 233 } 234 #endif // SANITIZER_WORDSIZE == 64 235 236 struct TestMapUnmapCallback { 237 static int map_count, unmap_count; 238 void OnMap(uptr p, uptr size) const { map_count++; } 239 void OnUnmap(uptr p, uptr size) const { unmap_count++; } 240 }; 241 int TestMapUnmapCallback::map_count; 242 int TestMapUnmapCallback::unmap_count; 243 244 #if SANITIZER_WORDSIZE == 64 245 TEST(SanitizerCommon, SizeClassAllocator64MapUnmapCallback) { 246 TestMapUnmapCallback::map_count = 0; 247 TestMapUnmapCallback::unmap_count = 0; 248 typedef SizeClassAllocator64< 249 kAllocatorSpace, kAllocatorSize, 16, DefaultSizeClassMap, 250 TestMapUnmapCallback> Allocator64WithCallBack; 251 Allocator64WithCallBack *a = new Allocator64WithCallBack; 252 a->Init(); 253 EXPECT_EQ(TestMapUnmapCallback::map_count, 1); // Allocator state. 254 SizeClassAllocatorLocalCache<Allocator64WithCallBack> cache; 255 memset(&cache, 0, sizeof(cache)); 256 cache.Init(0); 257 AllocatorStats stats; 258 stats.Init(); 259 a->AllocateBatch(&stats, &cache, 32); 260 EXPECT_EQ(TestMapUnmapCallback::map_count, 3); // State + alloc + metadata. 261 a->TestOnlyUnmap(); 262 EXPECT_EQ(TestMapUnmapCallback::unmap_count, 1); // The whole thing. 263 delete a; 264 } 265 #endif 266 267 TEST(SanitizerCommon, SizeClassAllocator32MapUnmapCallback) { 268 TestMapUnmapCallback::map_count = 0; 269 TestMapUnmapCallback::unmap_count = 0; 270 typedef SizeClassAllocator32< 271 0, kAddressSpaceSize, 272 /*kMetadataSize*/16, 273 CompactSizeClassMap, 274 kRegionSizeLog, 275 FlatByteMap<kFlatByteMapSize>, 276 TestMapUnmapCallback> 277 Allocator32WithCallBack; 278 Allocator32WithCallBack *a = new Allocator32WithCallBack; 279 a->Init(); 280 EXPECT_EQ(TestMapUnmapCallback::map_count, 0); 281 SizeClassAllocatorLocalCache<Allocator32WithCallBack> cache; 282 memset(&cache, 0, sizeof(cache)); 283 cache.Init(0); 284 AllocatorStats stats; 285 stats.Init(); 286 a->AllocateBatch(&stats, &cache, 32); 287 EXPECT_EQ(TestMapUnmapCallback::map_count, 1); 288 a->TestOnlyUnmap(); 289 EXPECT_EQ(TestMapUnmapCallback::unmap_count, 1); 290 delete a; 291 // fprintf(stderr, "Map: %d Unmap: %d\n", 292 // TestMapUnmapCallback::map_count, 293 // TestMapUnmapCallback::unmap_count); 294 } 295 296 TEST(SanitizerCommon, LargeMmapAllocatorMapUnmapCallback) { 297 TestMapUnmapCallback::map_count = 0; 298 TestMapUnmapCallback::unmap_count = 0; 299 LargeMmapAllocator<TestMapUnmapCallback> a; 300 a.Init(); 301 AllocatorStats stats; 302 stats.Init(); 303 void *x = a.Allocate(&stats, 1 << 20, 1); 304 EXPECT_EQ(TestMapUnmapCallback::map_count, 1); 305 a.Deallocate(&stats, x); 306 EXPECT_EQ(TestMapUnmapCallback::unmap_count, 1); 307 } 308 309 template<class Allocator> 310 void FailInAssertionOnOOM() { 311 Allocator a; 312 a.Init(); 313 SizeClassAllocatorLocalCache<Allocator> cache; 314 memset(&cache, 0, sizeof(cache)); 315 cache.Init(0); 316 AllocatorStats stats; 317 stats.Init(); 318 for (int i = 0; i < 1000000; i++) { 319 a.AllocateBatch(&stats, &cache, 52); 320 } 321 322 a.TestOnlyUnmap(); 323 } 324 325 #if SANITIZER_WORDSIZE == 64 326 TEST(SanitizerCommon, SizeClassAllocator64Overflow) { 327 EXPECT_DEATH(FailInAssertionOnOOM<Allocator64>(), "Out of memory"); 328 } 329 #endif 330 331 #if !defined(_WIN32) // FIXME: This currently fails on Windows. 332 TEST(SanitizerCommon, LargeMmapAllocator) { 333 LargeMmapAllocator<> a; 334 a.Init(); 335 AllocatorStats stats; 336 stats.Init(); 337 338 static const int kNumAllocs = 1000; 339 char *allocated[kNumAllocs]; 340 static const uptr size = 4000; 341 // Allocate some. 342 for (int i = 0; i < kNumAllocs; i++) { 343 allocated[i] = (char *)a.Allocate(&stats, size, 1); 344 CHECK(a.PointerIsMine(allocated[i])); 345 } 346 // Deallocate all. 347 CHECK_GT(a.TotalMemoryUsed(), size * kNumAllocs); 348 for (int i = 0; i < kNumAllocs; i++) { 349 char *p = allocated[i]; 350 CHECK(a.PointerIsMine(p)); 351 a.Deallocate(&stats, p); 352 } 353 // Check that non left. 354 CHECK_EQ(a.TotalMemoryUsed(), 0); 355 356 // Allocate some more, also add metadata. 357 for (int i = 0; i < kNumAllocs; i++) { 358 char *x = (char *)a.Allocate(&stats, size, 1); 359 CHECK_GE(a.GetActuallyAllocatedSize(x), size); 360 uptr *meta = reinterpret_cast<uptr*>(a.GetMetaData(x)); 361 *meta = i; 362 allocated[i] = x; 363 } 364 for (int i = 0; i < kNumAllocs * kNumAllocs; i++) { 365 char *p = allocated[i % kNumAllocs]; 366 CHECK(a.PointerIsMine(p)); 367 CHECK(a.PointerIsMine(p + 2000)); 368 } 369 CHECK_GT(a.TotalMemoryUsed(), size * kNumAllocs); 370 // Deallocate all in reverse order. 371 for (int i = 0; i < kNumAllocs; i++) { 372 int idx = kNumAllocs - i - 1; 373 char *p = allocated[idx]; 374 uptr *meta = reinterpret_cast<uptr*>(a.GetMetaData(p)); 375 CHECK_EQ(*meta, idx); 376 CHECK(a.PointerIsMine(p)); 377 a.Deallocate(&stats, p); 378 } 379 CHECK_EQ(a.TotalMemoryUsed(), 0); 380 381 // Test alignments. 382 uptr max_alignment = SANITIZER_WORDSIZE == 64 ? (1 << 28) : (1 << 24); 383 for (uptr alignment = 8; alignment <= max_alignment; alignment *= 2) { 384 const uptr kNumAlignedAllocs = 100; 385 for (uptr i = 0; i < kNumAlignedAllocs; i++) { 386 uptr size = ((i % 10) + 1) * 4096; 387 char *p = allocated[i] = (char *)a.Allocate(&stats, size, alignment); 388 CHECK_EQ(p, a.GetBlockBegin(p)); 389 CHECK_EQ(p, a.GetBlockBegin(p + size - 1)); 390 CHECK_EQ(p, a.GetBlockBegin(p + size / 2)); 391 CHECK_EQ(0, (uptr)allocated[i] % alignment); 392 p[0] = p[size - 1] = 0; 393 } 394 for (uptr i = 0; i < kNumAlignedAllocs; i++) { 395 a.Deallocate(&stats, allocated[i]); 396 } 397 } 398 399 // Regression test for boundary condition in GetBlockBegin(). 400 uptr page_size = GetPageSizeCached(); 401 char *p = (char *)a.Allocate(&stats, page_size, 1); 402 CHECK_EQ(p, a.GetBlockBegin(p)); 403 CHECK_EQ(p, (char *)a.GetBlockBegin(p + page_size - 1)); 404 CHECK_NE(p, (char *)a.GetBlockBegin(p + page_size)); 405 a.Deallocate(&stats, p); 406 } 407 #endif 408 409 template 410 <class PrimaryAllocator, class SecondaryAllocator, class AllocatorCache> 411 void TestCombinedAllocator() { 412 typedef 413 CombinedAllocator<PrimaryAllocator, AllocatorCache, SecondaryAllocator> 414 Allocator; 415 Allocator *a = new Allocator; 416 a->Init(); 417 418 AllocatorCache cache; 419 memset(&cache, 0, sizeof(cache)); 420 a->InitCache(&cache); 421 422 bool allocator_may_return_null = common_flags()->allocator_may_return_null; 423 common_flags()->allocator_may_return_null = true; 424 EXPECT_EQ(a->Allocate(&cache, -1, 1), (void*)0); 425 EXPECT_EQ(a->Allocate(&cache, -1, 1024), (void*)0); 426 EXPECT_EQ(a->Allocate(&cache, (uptr)-1 - 1024, 1), (void*)0); 427 EXPECT_EQ(a->Allocate(&cache, (uptr)-1 - 1024, 1024), (void*)0); 428 EXPECT_EQ(a->Allocate(&cache, (uptr)-1 - 1023, 1024), (void*)0); 429 430 common_flags()->allocator_may_return_null = false; 431 EXPECT_DEATH(a->Allocate(&cache, -1, 1), 432 "allocator is terminating the process"); 433 // Restore the original value. 434 common_flags()->allocator_may_return_null = allocator_may_return_null; 435 436 const uptr kNumAllocs = 100000; 437 const uptr kNumIter = 10; 438 for (uptr iter = 0; iter < kNumIter; iter++) { 439 std::vector<void*> allocated; 440 for (uptr i = 0; i < kNumAllocs; i++) { 441 uptr size = (i % (1 << 14)) + 1; 442 if ((i % 1024) == 0) 443 size = 1 << (10 + (i % 14)); 444 void *x = a->Allocate(&cache, size, 1); 445 uptr *meta = reinterpret_cast<uptr*>(a->GetMetaData(x)); 446 CHECK_EQ(*meta, 0); 447 *meta = size; 448 allocated.push_back(x); 449 } 450 451 random_shuffle(allocated.begin(), allocated.end()); 452 453 for (uptr i = 0; i < kNumAllocs; i++) { 454 void *x = allocated[i]; 455 uptr *meta = reinterpret_cast<uptr*>(a->GetMetaData(x)); 456 CHECK_NE(*meta, 0); 457 CHECK(a->PointerIsMine(x)); 458 *meta = 0; 459 a->Deallocate(&cache, x); 460 } 461 allocated.clear(); 462 a->SwallowCache(&cache); 463 } 464 a->DestroyCache(&cache); 465 a->TestOnlyUnmap(); 466 } 467 468 #if SANITIZER_WORDSIZE == 64 469 TEST(SanitizerCommon, CombinedAllocator64) { 470 TestCombinedAllocator<Allocator64, 471 LargeMmapAllocator<>, 472 SizeClassAllocatorLocalCache<Allocator64> > (); 473 } 474 475 TEST(SanitizerCommon, CombinedAllocator64Compact) { 476 TestCombinedAllocator<Allocator64Compact, 477 LargeMmapAllocator<>, 478 SizeClassAllocatorLocalCache<Allocator64Compact> > (); 479 } 480 #endif 481 482 #if !defined(_WIN32) // FIXME: This currently fails on Windows. 483 TEST(SanitizerCommon, CombinedAllocator32Compact) { 484 TestCombinedAllocator<Allocator32Compact, 485 LargeMmapAllocator<>, 486 SizeClassAllocatorLocalCache<Allocator32Compact> > (); 487 } 488 #endif 489 490 template <class AllocatorCache> 491 void TestSizeClassAllocatorLocalCache() { 492 AllocatorCache cache; 493 typedef typename AllocatorCache::Allocator Allocator; 494 Allocator *a = new Allocator(); 495 496 a->Init(); 497 memset(&cache, 0, sizeof(cache)); 498 cache.Init(0); 499 500 const uptr kNumAllocs = 10000; 501 const int kNumIter = 100; 502 uptr saved_total = 0; 503 for (int class_id = 1; class_id <= 5; class_id++) { 504 for (int it = 0; it < kNumIter; it++) { 505 void *allocated[kNumAllocs]; 506 for (uptr i = 0; i < kNumAllocs; i++) { 507 allocated[i] = cache.Allocate(a, class_id); 508 } 509 for (uptr i = 0; i < kNumAllocs; i++) { 510 cache.Deallocate(a, class_id, allocated[i]); 511 } 512 cache.Drain(a); 513 uptr total_allocated = a->TotalMemoryUsed(); 514 if (it) 515 CHECK_EQ(saved_total, total_allocated); 516 saved_total = total_allocated; 517 } 518 } 519 520 a->TestOnlyUnmap(); 521 delete a; 522 } 523 524 #if SANITIZER_WORDSIZE == 64 525 TEST(SanitizerCommon, SizeClassAllocator64LocalCache) { 526 TestSizeClassAllocatorLocalCache< 527 SizeClassAllocatorLocalCache<Allocator64> >(); 528 } 529 530 TEST(SanitizerCommon, SizeClassAllocator64CompactLocalCache) { 531 TestSizeClassAllocatorLocalCache< 532 SizeClassAllocatorLocalCache<Allocator64Compact> >(); 533 } 534 #endif 535 536 TEST(SanitizerCommon, SizeClassAllocator32CompactLocalCache) { 537 TestSizeClassAllocatorLocalCache< 538 SizeClassAllocatorLocalCache<Allocator32Compact> >(); 539 } 540 541 #if SANITIZER_WORDSIZE == 64 542 typedef SizeClassAllocatorLocalCache<Allocator64> AllocatorCache; 543 static AllocatorCache static_allocator_cache; 544 545 void *AllocatorLeakTestWorker(void *arg) { 546 typedef AllocatorCache::Allocator Allocator; 547 Allocator *a = (Allocator*)(arg); 548 static_allocator_cache.Allocate(a, 10); 549 static_allocator_cache.Drain(a); 550 return 0; 551 } 552 553 TEST(SanitizerCommon, AllocatorLeakTest) { 554 typedef AllocatorCache::Allocator Allocator; 555 Allocator a; 556 a.Init(); 557 uptr total_used_memory = 0; 558 for (int i = 0; i < 100; i++) { 559 pthread_t t; 560 PTHREAD_CREATE(&t, 0, AllocatorLeakTestWorker, &a); 561 PTHREAD_JOIN(t, 0); 562 if (i == 0) 563 total_used_memory = a.TotalMemoryUsed(); 564 EXPECT_EQ(a.TotalMemoryUsed(), total_used_memory); 565 } 566 567 a.TestOnlyUnmap(); 568 } 569 570 // Struct which is allocated to pass info to new threads. The new thread frees 571 // it. 572 struct NewThreadParams { 573 AllocatorCache *thread_cache; 574 AllocatorCache::Allocator *allocator; 575 uptr class_id; 576 }; 577 578 // Called in a new thread. Just frees its argument. 579 static void *DeallocNewThreadWorker(void *arg) { 580 NewThreadParams *params = reinterpret_cast<NewThreadParams*>(arg); 581 params->thread_cache->Deallocate(params->allocator, params->class_id, params); 582 return NULL; 583 } 584 585 // The allocator cache is supposed to be POD and zero initialized. We should be 586 // able to call Deallocate on a zeroed cache, and it will self-initialize. 587 TEST(Allocator, AllocatorCacheDeallocNewThread) { 588 AllocatorCache::Allocator allocator; 589 allocator.Init(); 590 AllocatorCache main_cache; 591 AllocatorCache child_cache; 592 memset(&main_cache, 0, sizeof(main_cache)); 593 memset(&child_cache, 0, sizeof(child_cache)); 594 595 uptr class_id = DefaultSizeClassMap::ClassID(sizeof(NewThreadParams)); 596 NewThreadParams *params = reinterpret_cast<NewThreadParams*>( 597 main_cache.Allocate(&allocator, class_id)); 598 params->thread_cache = &child_cache; 599 params->allocator = &allocator; 600 params->class_id = class_id; 601 pthread_t t; 602 PTHREAD_CREATE(&t, 0, DeallocNewThreadWorker, params); 603 PTHREAD_JOIN(t, 0); 604 } 605 #endif 606 607 TEST(Allocator, Basic) { 608 char *p = (char*)InternalAlloc(10); 609 EXPECT_NE(p, (char*)0); 610 char *p2 = (char*)InternalAlloc(20); 611 EXPECT_NE(p2, (char*)0); 612 EXPECT_NE(p2, p); 613 InternalFree(p); 614 InternalFree(p2); 615 } 616 617 TEST(Allocator, Stress) { 618 const int kCount = 1000; 619 char *ptrs[kCount]; 620 unsigned rnd = 42; 621 for (int i = 0; i < kCount; i++) { 622 uptr sz = my_rand_r(&rnd) % 1000; 623 char *p = (char*)InternalAlloc(sz); 624 EXPECT_NE(p, (char*)0); 625 ptrs[i] = p; 626 } 627 for (int i = 0; i < kCount; i++) { 628 InternalFree(ptrs[i]); 629 } 630 } 631 632 TEST(Allocator, InternalAllocFailure) { 633 EXPECT_DEATH(Ident(InternalAlloc(10 << 20)), 634 "Unexpected mmap in InternalAllocator!"); 635 } 636 637 TEST(Allocator, ScopedBuffer) { 638 const int kSize = 512; 639 { 640 InternalScopedBuffer<int> int_buf(kSize); 641 EXPECT_EQ(sizeof(int) * kSize, int_buf.size()); // NOLINT 642 } 643 InternalScopedBuffer<char> char_buf(kSize); 644 EXPECT_EQ(sizeof(char) * kSize, char_buf.size()); // NOLINT 645 internal_memset(char_buf.data(), 'c', kSize); 646 for (int i = 0; i < kSize; i++) { 647 EXPECT_EQ('c', char_buf[i]); 648 } 649 } 650 651 void IterationTestCallback(uptr chunk, void *arg) { 652 reinterpret_cast<std::set<uptr> *>(arg)->insert(chunk); 653 } 654 655 template <class Allocator> 656 void TestSizeClassAllocatorIteration() { 657 Allocator *a = new Allocator; 658 a->Init(); 659 SizeClassAllocatorLocalCache<Allocator> cache; 660 memset(&cache, 0, sizeof(cache)); 661 cache.Init(0); 662 663 static const uptr sizes[] = {1, 16, 30, 40, 100, 1000, 10000, 664 50000, 60000, 100000, 120000, 300000, 500000, 1000000, 2000000}; 665 666 std::vector<void *> allocated; 667 668 // Allocate a bunch of chunks. 669 for (uptr s = 0; s < ARRAY_SIZE(sizes); s++) { 670 uptr size = sizes[s]; 671 if (!a->CanAllocate(size, 1)) continue; 672 // printf("s = %ld\n", size); 673 uptr n_iter = std::max((uptr)6, 80000 / size); 674 // fprintf(stderr, "size: %ld iter: %ld\n", size, n_iter); 675 for (uptr j = 0; j < n_iter; j++) { 676 uptr class_id0 = Allocator::SizeClassMapT::ClassID(size); 677 void *x = cache.Allocate(a, class_id0); 678 allocated.push_back(x); 679 } 680 } 681 682 std::set<uptr> reported_chunks; 683 a->ForceLock(); 684 a->ForEachChunk(IterationTestCallback, &reported_chunks); 685 a->ForceUnlock(); 686 687 for (uptr i = 0; i < allocated.size(); i++) { 688 // Don't use EXPECT_NE. Reporting the first mismatch is enough. 689 ASSERT_NE(reported_chunks.find(reinterpret_cast<uptr>(allocated[i])), 690 reported_chunks.end()); 691 } 692 693 a->TestOnlyUnmap(); 694 delete a; 695 } 696 697 #if SANITIZER_WORDSIZE == 64 698 TEST(SanitizerCommon, SizeClassAllocator64Iteration) { 699 TestSizeClassAllocatorIteration<Allocator64>(); 700 } 701 #endif 702 703 TEST(SanitizerCommon, SizeClassAllocator32Iteration) { 704 TestSizeClassAllocatorIteration<Allocator32Compact>(); 705 } 706 707 TEST(SanitizerCommon, LargeMmapAllocatorIteration) { 708 LargeMmapAllocator<> a; 709 a.Init(); 710 AllocatorStats stats; 711 stats.Init(); 712 713 static const uptr kNumAllocs = 1000; 714 char *allocated[kNumAllocs]; 715 static const uptr size = 40; 716 // Allocate some. 717 for (uptr i = 0; i < kNumAllocs; i++) 718 allocated[i] = (char *)a.Allocate(&stats, size, 1); 719 720 std::set<uptr> reported_chunks; 721 a.ForceLock(); 722 a.ForEachChunk(IterationTestCallback, &reported_chunks); 723 a.ForceUnlock(); 724 725 for (uptr i = 0; i < kNumAllocs; i++) { 726 // Don't use EXPECT_NE. Reporting the first mismatch is enough. 727 ASSERT_NE(reported_chunks.find(reinterpret_cast<uptr>(allocated[i])), 728 reported_chunks.end()); 729 } 730 for (uptr i = 0; i < kNumAllocs; i++) 731 a.Deallocate(&stats, allocated[i]); 732 } 733 734 TEST(SanitizerCommon, LargeMmapAllocatorBlockBegin) { 735 LargeMmapAllocator<> a; 736 a.Init(); 737 AllocatorStats stats; 738 stats.Init(); 739 740 static const uptr kNumAllocs = 1024; 741 static const uptr kNumExpectedFalseLookups = 10000000; 742 char *allocated[kNumAllocs]; 743 static const uptr size = 4096; 744 // Allocate some. 745 for (uptr i = 0; i < kNumAllocs; i++) { 746 allocated[i] = (char *)a.Allocate(&stats, size, 1); 747 } 748 749 a.ForceLock(); 750 for (uptr i = 0; i < kNumAllocs * kNumAllocs; i++) { 751 // if ((i & (i - 1)) == 0) fprintf(stderr, "[%zd]\n", i); 752 char *p1 = allocated[i % kNumAllocs]; 753 EXPECT_EQ(p1, a.GetBlockBeginFastLocked(p1)); 754 EXPECT_EQ(p1, a.GetBlockBeginFastLocked(p1 + size / 2)); 755 EXPECT_EQ(p1, a.GetBlockBeginFastLocked(p1 + size - 1)); 756 EXPECT_EQ(p1, a.GetBlockBeginFastLocked(p1 - 100)); 757 } 758 759 for (uptr i = 0; i < kNumExpectedFalseLookups; i++) { 760 void *p = reinterpret_cast<void *>(i % 1024); 761 EXPECT_EQ((void *)0, a.GetBlockBeginFastLocked(p)); 762 p = reinterpret_cast<void *>(~0L - (i % 1024)); 763 EXPECT_EQ((void *)0, a.GetBlockBeginFastLocked(p)); 764 } 765 a.ForceUnlock(); 766 767 for (uptr i = 0; i < kNumAllocs; i++) 768 a.Deallocate(&stats, allocated[i]); 769 } 770 771 772 #if SANITIZER_WORDSIZE == 64 773 // Regression test for out-of-memory condition in PopulateFreeList(). 774 TEST(SanitizerCommon, SizeClassAllocator64PopulateFreeListOOM) { 775 // In a world where regions are small and chunks are huge... 776 typedef SizeClassMap<63, 128, 16> SpecialSizeClassMap; 777 typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, 0, 778 SpecialSizeClassMap> SpecialAllocator64; 779 const uptr kRegionSize = 780 kAllocatorSize / SpecialSizeClassMap::kNumClassesRounded; 781 SpecialAllocator64 *a = new SpecialAllocator64; 782 a->Init(); 783 SizeClassAllocatorLocalCache<SpecialAllocator64> cache; 784 memset(&cache, 0, sizeof(cache)); 785 cache.Init(0); 786 787 // ...one man is on a mission to overflow a region with a series of 788 // successive allocations. 789 const uptr kClassID = 107; 790 const uptr kAllocationSize = DefaultSizeClassMap::Size(kClassID); 791 ASSERT_LT(2 * kAllocationSize, kRegionSize); 792 ASSERT_GT(3 * kAllocationSize, kRegionSize); 793 cache.Allocate(a, kClassID); 794 EXPECT_DEATH(cache.Allocate(a, kClassID) && cache.Allocate(a, kClassID), 795 "The process has exhausted"); 796 a->TestOnlyUnmap(); 797 delete a; 798 } 799 #endif 800 801 TEST(SanitizerCommon, TwoLevelByteMap) { 802 const u64 kSize1 = 1 << 6, kSize2 = 1 << 12; 803 const u64 n = kSize1 * kSize2; 804 TwoLevelByteMap<kSize1, kSize2> m; 805 m.TestOnlyInit(); 806 for (u64 i = 0; i < n; i += 7) { 807 m.set(i, (i % 100) + 1); 808 } 809 for (u64 j = 0; j < n; j++) { 810 if (j % 7) 811 EXPECT_EQ(m[j], 0); 812 else 813 EXPECT_EQ(m[j], (j % 100) + 1); 814 } 815 816 m.TestOnlyUnmap(); 817 } 818 819 820 typedef TwoLevelByteMap<1 << 12, 1 << 13, TestMapUnmapCallback> TestByteMap; 821 822 struct TestByteMapParam { 823 TestByteMap *m; 824 size_t shard; 825 size_t num_shards; 826 }; 827 828 void *TwoLevelByteMapUserThread(void *param) { 829 TestByteMapParam *p = (TestByteMapParam*)param; 830 for (size_t i = p->shard; i < p->m->size(); i += p->num_shards) { 831 size_t val = (i % 100) + 1; 832 p->m->set(i, val); 833 EXPECT_EQ((*p->m)[i], val); 834 } 835 return 0; 836 } 837 838 TEST(SanitizerCommon, ThreadedTwoLevelByteMap) { 839 TestByteMap m; 840 m.TestOnlyInit(); 841 TestMapUnmapCallback::map_count = 0; 842 TestMapUnmapCallback::unmap_count = 0; 843 static const int kNumThreads = 4; 844 pthread_t t[kNumThreads]; 845 TestByteMapParam p[kNumThreads]; 846 for (int i = 0; i < kNumThreads; i++) { 847 p[i].m = &m; 848 p[i].shard = i; 849 p[i].num_shards = kNumThreads; 850 PTHREAD_CREATE(&t[i], 0, TwoLevelByteMapUserThread, &p[i]); 851 } 852 for (int i = 0; i < kNumThreads; i++) { 853 PTHREAD_JOIN(t[i], 0); 854 } 855 EXPECT_EQ((uptr)TestMapUnmapCallback::map_count, m.size1()); 856 EXPECT_EQ((uptr)TestMapUnmapCallback::unmap_count, 0UL); 857 m.TestOnlyUnmap(); 858 EXPECT_EQ((uptr)TestMapUnmapCallback::map_count, m.size1()); 859 EXPECT_EQ((uptr)TestMapUnmapCallback::unmap_count, m.size1()); 860 } 861 862 #endif // #if TSAN_DEBUG==0 863