Branch data Line data Source code
# 1 : : // Copyright (c) 2012-2019 The Bitcoin Core developers # 2 : : // Distributed under the MIT software license, see the accompanying # 3 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php. # 4 : : # 5 : : #include <util/system.h> # 6 : : # 7 : : #include <test/util/setup_common.h> # 8 : : # 9 : : #include <memory> # 10 : : # 11 : : #include <boost/test/unit_test.hpp> # 12 : : # 13 : : BOOST_FIXTURE_TEST_SUITE(allocator_tests, BasicTestingSetup) # 14 : : # 15 : : BOOST_AUTO_TEST_CASE(arena_tests) # 16 : 2 : { # 17 : : // Fake memory base address for testing # 18 : : // without actually using memory. # 19 : 2 : void *synth_base = reinterpret_cast<void*>(0x08000000); # 20 : 2 : const size_t synth_size = 1024*1024; # 21 : 2 : Arena b(synth_base, synth_size, 16); # 22 : 2 : void *chunk = b.alloc(1000); # 23 : : #ifdef ARENA_DEBUG # 24 : : b.walk(); # 25 : : #endif # 26 : 2 : BOOST_CHECK(chunk != nullptr); # 27 : 2 : BOOST_CHECK(b.stats().used == 1008); // Aligned to 16 # 28 : 2 : BOOST_CHECK(b.stats().total == synth_size); // Nothing has disappeared? # 29 : 2 : b.free(chunk); # 30 : : #ifdef ARENA_DEBUG # 31 : : b.walk(); # 32 : : #endif # 33 : 2 : BOOST_CHECK(b.stats().used == 0); # 34 : 2 : BOOST_CHECK(b.stats().free == synth_size); # 35 : 2 : try { // Test exception on double-free # 36 : 2 : b.free(chunk); # 37 : 2 : BOOST_CHECK(0); # 38 : 2 : } catch(std::runtime_error &) # 39 : 2 : { # 40 : 2 : } # 41 : : # 42 : 2 : void *a0 = b.alloc(128); # 43 : 2 : void *a1 = b.alloc(256); # 44 : 2 : void *a2 = b.alloc(512); # 45 : 2 : BOOST_CHECK(b.stats().used == 896); # 46 : 2 : BOOST_CHECK(b.stats().total == synth_size); # 47 : : #ifdef ARENA_DEBUG # 48 : : b.walk(); # 49 : : #endif # 50 : 2 : b.free(a0); # 51 : : #ifdef ARENA_DEBUG # 52 : : b.walk(); # 53 : : #endif # 54 : 2 : BOOST_CHECK(b.stats().used == 768); # 55 : 2 : b.free(a1); # 56 : 2 : BOOST_CHECK(b.stats().used == 512); # 57 : 2 : void *a3 = b.alloc(128); # 58 : : #ifdef ARENA_DEBUG # 59 : : b.walk(); # 60 : : #endif # 61 : 2 : BOOST_CHECK(b.stats().used == 640); # 62 : 2 : b.free(a2); # 63 : 2 : BOOST_CHECK(b.stats().used == 128); # 64 : 2 : b.free(a3); # 65 : 2 : BOOST_CHECK(b.stats().used == 0); # 66 : 2 : BOOST_CHECK_EQUAL(b.stats().chunks_used, 0U); # 67 : 2 : BOOST_CHECK(b.stats().total == synth_size); # 68 : 2 : BOOST_CHECK(b.stats().free == synth_size); # 69 : 2 : BOOST_CHECK_EQUAL(b.stats().chunks_free, 1U); # 70 : : # 71 : 2 : std::vector<void*> addr; # 72 : 2 : BOOST_CHECK(b.alloc(0) == nullptr); // allocating 0 always returns nullptr # 73 : : #ifdef ARENA_DEBUG # 74 : : b.walk(); # 75 : : #endif # 76 : : // Sweeping allocate all memory # 77 [ + + ]: 2050 : for (int x=0; x<1024; ++x) # 78 : 2048 : addr.push_back(b.alloc(1024)); # 79 : 2 : BOOST_CHECK(b.stats().free == 0); # 80 : 2 : BOOST_CHECK(b.alloc(1024) == nullptr); // memory is full, this must return nullptr # 81 : 2 : BOOST_CHECK(b.alloc(0) == nullptr); # 82 [ + + ]: 2050 : for (int x=0; x<1024; ++x) # 83 : 2048 : b.free(addr[x]); # 84 : 2 : addr.clear(); # 85 : 2 : BOOST_CHECK(b.stats().total == synth_size); # 86 : 2 : BOOST_CHECK(b.stats().free == synth_size); # 87 : : # 88 : : // Now in the other direction... # 89 [ + + ]: 2050 : for (int x=0; x<1024; ++x) # 90 : 2048 : addr.push_back(b.alloc(1024)); # 91 [ + + ]: 2050 : for (int x=0; x<1024; ++x) # 92 : 2048 : b.free(addr[1023-x]); # 93 : 2 : addr.clear(); # 94 : : # 95 : : // Now allocate in smaller unequal chunks, then deallocate haphazardly # 96 : : // Not all the chunks will succeed allocating, but freeing nullptr is # 97 : : // allowed so that is no problem. # 98 [ + + ]: 4098 : for (int x=0; x<2048; ++x) # 99 : 4096 : addr.push_back(b.alloc(x+1)); # 100 [ + + ]: 4098 : for (int x=0; x<2048; ++x) # 101 : 4096 : b.free(addr[((x*23)%2048)^242]); # 102 : 2 : addr.clear(); # 103 : : # 104 : : // Go entirely wild: free and alloc interleaved, # 105 : : // generate targets and sizes using pseudo-randomness. # 106 [ + + ]: 4098 : for (int x=0; x<2048; ++x) # 107 : 4096 : addr.push_back(nullptr); # 108 : 2 : uint32_t s = 0x12345678; # 109 [ + + ]: 10002 : for (int x=0; x<5000; ++x) { # 110 : 10000 : int idx = s & (addr.size()-1); # 111 [ + + ]: 10000 : if (s & 0x80000000) { # 112 : 4916 : b.free(addr[idx]); # 113 : 4916 : addr[idx] = nullptr; # 114 [ + + ]: 5084 : } else if(!addr[idx]) { # 115 : 3482 : addr[idx] = b.alloc((s >> 16) & 2047); # 116 : 3482 : } # 117 : 10000 : bool lsb = s & 1; # 118 : 10000 : s >>= 1; # 119 [ + + ]: 10000 : if (lsb) # 120 : 4916 : s ^= 0xf00f00f0; // LFSR period 0xf7ffffe0 # 121 : 10000 : } # 122 [ + + ]: 2 : for (void *ptr: addr) # 123 : 4096 : b.free(ptr); # 124 : 2 : addr.clear(); # 125 : : # 126 : 2 : BOOST_CHECK(b.stats().total == synth_size); # 127 : 2 : BOOST_CHECK(b.stats().free == synth_size); # 128 : 2 : } # 129 : : # 130 : : /** Mock LockedPageAllocator for testing */ # 131 : : class TestLockedPageAllocator: public LockedPageAllocator # 132 : : { # 133 : : public: # 134 : 2 : TestLockedPageAllocator(int count_in, int lockedcount_in): count(count_in), lockedcount(lockedcount_in) {} # 135 : : void* AllocateLocked(size_t len, bool *lockingSuccess) override # 136 : 8 : { # 137 : 8 : *lockingSuccess = false; # 138 [ + + ]: 8 : if (count > 0) { # 139 : 6 : --count; # 140 : : # 141 [ + + ]: 6 : if (lockedcount > 0) { # 142 : 2 : --lockedcount; # 143 : 2 : *lockingSuccess = true; # 144 : 2 : } # 145 : : # 146 : 6 : return reinterpret_cast<void*>(uint64_t{static_cast<uint64_t>(0x08000000) + (count << 24)}); // Fake address, do not actually use this memory # 147 : 6 : } # 148 : 2 : return nullptr; # 149 : 2 : } # 150 : : void FreeLocked(void* addr, size_t len) override # 151 : 6 : { # 152 : 6 : } # 153 : : size_t GetLimit() override # 154 : 2 : { # 155 : 2 : return std::numeric_limits<size_t>::max(); # 156 : 2 : } # 157 : : private: # 158 : : int count; # 159 : : int lockedcount; # 160 : : }; # 161 : : # 162 : : BOOST_AUTO_TEST_CASE(lockedpool_tests_mock) # 163 : 2 : { # 164 : : // Test over three virtual arenas, of which one will succeed being locked # 165 : 2 : std::unique_ptr<LockedPageAllocator> x = std::make_unique<TestLockedPageAllocator>(3, 1); # 166 : 2 : LockedPool pool(std::move(x)); # 167 : 2 : BOOST_CHECK(pool.stats().total == 0); # 168 : 2 : BOOST_CHECK(pool.stats().locked == 0); # 169 : : # 170 : : // Ensure unreasonable requests are refused without allocating anything # 171 : 2 : void *invalid_toosmall = pool.alloc(0); # 172 : 2 : BOOST_CHECK(invalid_toosmall == nullptr); # 173 : 2 : BOOST_CHECK(pool.stats().used == 0); # 174 : 2 : BOOST_CHECK(pool.stats().free == 0); # 175 : 2 : void *invalid_toobig = pool.alloc(LockedPool::ARENA_SIZE+1); # 176 : 2 : BOOST_CHECK(invalid_toobig == nullptr); # 177 : 2 : BOOST_CHECK(pool.stats().used == 0); # 178 : 2 : BOOST_CHECK(pool.stats().free == 0); # 179 : : # 180 : 2 : void *a0 = pool.alloc(LockedPool::ARENA_SIZE / 2); # 181 : 2 : BOOST_CHECK(a0); # 182 : 2 : BOOST_CHECK(pool.stats().locked == LockedPool::ARENA_SIZE); # 183 : 2 : void *a1 = pool.alloc(LockedPool::ARENA_SIZE / 2); # 184 : 2 : BOOST_CHECK(a1); # 185 : 2 : void *a2 = pool.alloc(LockedPool::ARENA_SIZE / 2); # 186 : 2 : BOOST_CHECK(a2); # 187 : 2 : void *a3 = pool.alloc(LockedPool::ARENA_SIZE / 2); # 188 : 2 : BOOST_CHECK(a3); # 189 : 2 : void *a4 = pool.alloc(LockedPool::ARENA_SIZE / 2); # 190 : 2 : BOOST_CHECK(a4); # 191 : 2 : void *a5 = pool.alloc(LockedPool::ARENA_SIZE / 2); # 192 : 2 : BOOST_CHECK(a5); # 193 : : // We've passed a count of three arenas, so this allocation should fail # 194 : 2 : void *a6 = pool.alloc(16); # 195 : 2 : BOOST_CHECK(!a6); # 196 : : # 197 : 2 : pool.free(a0); # 198 : 2 : pool.free(a2); # 199 : 2 : pool.free(a4); # 200 : 2 : pool.free(a1); # 201 : 2 : pool.free(a3); # 202 : 2 : pool.free(a5); # 203 : 2 : BOOST_CHECK(pool.stats().total == 3*LockedPool::ARENA_SIZE); # 204 : 2 : BOOST_CHECK(pool.stats().locked == LockedPool::ARENA_SIZE); # 205 : 2 : BOOST_CHECK(pool.stats().used == 0); # 206 : 2 : } # 207 : : # 208 : : // These tests used the live LockedPoolManager object, this is also used # 209 : : // by other tests so the conditions are somewhat less controllable and thus the # 210 : : // tests are somewhat more error-prone. # 211 : : BOOST_AUTO_TEST_CASE(lockedpool_tests_live) # 212 : 2 : { # 213 : 2 : LockedPoolManager &pool = LockedPoolManager::Instance(); # 214 : 2 : LockedPool::Stats initial = pool.stats(); # 215 : : # 216 : 2 : void *a0 = pool.alloc(16); # 217 : 2 : BOOST_CHECK(a0); # 218 : : // Test reading and writing the allocated memory # 219 : 2 : *((uint32_t*)a0) = 0x1234; # 220 : 2 : BOOST_CHECK(*((uint32_t*)a0) == 0x1234); # 221 : : # 222 : 2 : pool.free(a0); # 223 : 2 : try { // Test exception on double-free # 224 : 2 : pool.free(a0); # 225 : 2 : BOOST_CHECK(0); # 226 : 2 : } catch(std::runtime_error &) # 227 : 2 : { # 228 : 2 : } # 229 : : // If more than one new arena was allocated for the above tests, something is wrong # 230 : 2 : BOOST_CHECK(pool.stats().total <= (initial.total + LockedPool::ARENA_SIZE)); # 231 : : // Usage must be back to where it started # 232 : 2 : BOOST_CHECK(pool.stats().used == initial.used); # 233 : 2 : } # 234 : : # 235 : : BOOST_AUTO_TEST_SUITE_END()