1 //===-- secondary_test.cpp --------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "secondary.h" 10 11 #include "gtest/gtest.h" 12 13 #include <stdio.h> 14 15 #include <condition_variable> 16 #include <mutex> 17 #include <thread> 18 19 TEST(ScudoSecondaryTest, SecondaryBasic) { 20 scudo::GlobalStats S; 21 S.init(); 22 scudo::MapAllocator *L = new scudo::MapAllocator; 23 L->init(&S); 24 const scudo::uptr Size = 1U << 16; 25 void *P = L->allocate(Size); 26 EXPECT_NE(P, nullptr); 27 memset(P, 'A', Size); 28 EXPECT_GE(scudo::MapAllocator::getBlockSize(P), Size); 29 L->deallocate(P); 30 EXPECT_DEATH(memset(P, 'A', Size), ""); 31 32 const scudo::uptr Align = 1U << 16; 33 P = L->allocate(Size + Align, Align); 34 EXPECT_NE(P, nullptr); 35 void *AlignedP = reinterpret_cast<void *>( 36 scudo::roundUpTo(reinterpret_cast<scudo::uptr>(P), Align)); 37 memset(AlignedP, 'A', Size); 38 L->deallocate(P); 39 40 std::vector<void *> V; 41 for (scudo::uptr I = 0; I < 32U; I++) 42 V.push_back(L->allocate(Size)); 43 std::random_shuffle(V.begin(), V.end()); 44 while (!V.empty()) { 45 L->deallocate(V.back()); 46 V.pop_back(); 47 } 48 L->printStats(); 49 } 50 51 // This exercises a variety of combinations of size and alignment for the 52 // MapAllocator. The size computation done here mimic the ones done by the 53 // combined allocator. 54 TEST(ScudoSecondaryTest, SecondaryCombinations) { 55 constexpr scudo::uptr MinAlign = FIRST_32_SECOND_64(8, 16); 56 constexpr scudo::uptr HeaderSize = scudo::roundUpTo(8, MinAlign); 57 scudo::MapAllocator *L = new scudo::MapAllocator; 58 L->init(nullptr); 59 for (scudo::uptr SizeLog = 0; SizeLog <= 20; SizeLog++) { 60 for (scudo::uptr AlignLog = FIRST_32_SECOND_64(3, 4); AlignLog <= 16; 61 AlignLog++) { 62 const scudo::uptr Align = 1U << AlignLog; 63 for (scudo::sptr Delta = -128; Delta <= 128; Delta += 8) { 64 if (static_cast<scudo::sptr>(1U << SizeLog) + Delta <= 0) 65 continue; 66 const scudo::uptr UserSize = 67 scudo::roundUpTo((1U << SizeLog) + Delta, MinAlign); 68 const scudo::uptr Size = 69 HeaderSize + UserSize + (Align > MinAlign ? Align - HeaderSize : 0); 70 void *P = L->allocate(Size, Align); 71 EXPECT_NE(P, nullptr); 72 void *AlignedP = reinterpret_cast<void *>( 73 scudo::roundUpTo(reinterpret_cast<scudo::uptr>(P), Align)); 74 memset(AlignedP, 0xff, UserSize); 75 L->deallocate(P); 76 } 77 } 78 } 79 L->printStats(); 80 } 81 82 TEST(ScudoSecondaryTest, SecondaryIterate) { 83 scudo::MapAllocator *L = new scudo::MapAllocator; 84 L->init(nullptr); 85 std::vector<void *> V; 86 const scudo::uptr PageSize = scudo::getPageSizeCached(); 87 for (scudo::uptr I = 0; I < 32U; I++) 88 V.push_back(L->allocate((std::rand() % 16) * PageSize)); 89 auto Lambda = [V](scudo::uptr Block) { 90 EXPECT_NE(std::find(V.begin(), V.end(), reinterpret_cast<void *>(Block)), 91 V.end()); 92 }; 93 L->disable(); 94 L->iterateOverBlocks(Lambda); 95 L->enable(); 96 while (!V.empty()) { 97 L->deallocate(V.back()); 98 V.pop_back(); 99 } 100 L->printStats(); 101 } 102 103 static std::mutex Mutex; 104 static std::condition_variable Cv; 105 static bool Ready = false; 106 107 static void performAllocations(scudo::MapAllocator *L) { 108 std::vector<void *> V; 109 const scudo::uptr PageSize = scudo::getPageSizeCached(); 110 { 111 std::unique_lock<std::mutex> Lock(Mutex); 112 while (!Ready) 113 Cv.wait(Lock); 114 } 115 for (scudo::uptr I = 0; I < 32U; I++) 116 V.push_back(L->allocate((std::rand() % 16) * PageSize)); 117 while (!V.empty()) { 118 L->deallocate(V.back()); 119 V.pop_back(); 120 } 121 } 122 123 TEST(ScudoSecondaryTest, SecondaryThreadsRace) { 124 scudo::MapAllocator *L = new scudo::MapAllocator; 125 L->init(nullptr); 126 std::thread Threads[10]; 127 for (scudo::uptr I = 0; I < 10U; I++) 128 Threads[I] = std::thread(performAllocations, L); 129 { 130 std::unique_lock<std::mutex> Lock(Mutex); 131 Ready = true; 132 Cv.notify_all(); 133 } 134 for (auto &T : Threads) 135 T.join(); 136 L->printStats(); 137 } 138