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