Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright (c) 2012-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.5#include <common/system.h>6#include <support/lockedpool.h>7#include <test/util/common.h>8#include <util/byte_units.h>10#include <boost/test/unit_test.hpp>12#include <limits>13#include <memory>14#include <stdexcept>15#include <utility>16#include <vector>18BOOST_AUTO_TEST_SUITE(allocator_tests)20BOOST_AUTO_TEST_CASE(arena_tests)21{22// Fake memory base address for testing23// without actually using memory.24void *synth_base = reinterpret_cast<void*>(0x08000000);25const size_t synth_size{1_MiB};26Arena b(synth_base, synth_size, 16);27void *chunk = b.alloc(1000);28#ifdef ARENA_DEBUG29b.walk();30#endif31BOOST_CHECK(chunk != nullptr);32BOOST_CHECK(b.stats().used == 1008); // Aligned to 1633BOOST_CHECK(b.stats().total == synth_size); // Nothing has disappeared?34b.free(chunk);35#ifdef ARENA_DEBUG36b.walk();37#endif38BOOST_CHECK(b.stats().used == 0);39BOOST_CHECK(b.stats().free == synth_size);40BOOST_CHECK_EXCEPTION(b.free(chunk), std::runtime_error, HasReason{"Arena: invalid or double free"});42void *a0 = b.alloc(128);43void *a1 = b.alloc(256);44void *a2 = b.alloc(512);45BOOST_CHECK(b.stats().used == 896);46BOOST_CHECK(b.stats().total == synth_size);47#ifdef ARENA_DEBUG48b.walk();49#endif50b.free(a0);51#ifdef ARENA_DEBUG52b.walk();53#endif54BOOST_CHECK(b.stats().used == 768);55b.free(a1);56BOOST_CHECK(b.stats().used == 512);57void *a3 = b.alloc(128);58#ifdef ARENA_DEBUG59b.walk();60#endif61BOOST_CHECK(b.stats().used == 640);62b.free(a2);63BOOST_CHECK(b.stats().used == 128);64b.free(a3);65BOOST_CHECK(b.stats().used == 0);66BOOST_CHECK_EQUAL(b.stats().chunks_used, 0U);67BOOST_CHECK(b.stats().total == synth_size);68BOOST_CHECK(b.stats().free == synth_size);69BOOST_CHECK_EQUAL(b.stats().chunks_free, 1U);71std::vector<void*> addr;72BOOST_CHECK(b.alloc(0) == nullptr); // allocating 0 always returns nullptr73#ifdef ARENA_DEBUG74b.walk();75#endif76// Sweeping allocate all memory77addr.reserve(2048);78for (int x=0; x<1024; ++x)79addr.push_back(b.alloc(1024));80BOOST_CHECK(b.stats().free == 0);81BOOST_CHECK(b.alloc(1024) == nullptr); // memory is full, this must return nullptr82BOOST_CHECK(b.alloc(0) == nullptr);83for (int x=0; x<1024; ++x)84b.free(addr[x]);85addr.clear();86BOOST_CHECK(b.stats().total == synth_size);87BOOST_CHECK(b.stats().free == synth_size);89// Now in the other direction...90for (int x=0; x<1024; ++x)91addr.push_back(b.alloc(1024));92for (int x=0; x<1024; ++x)93b.free(addr[1023-x]);94addr.clear();96// Now allocate in smaller unequal chunks, then deallocate haphazardly97// Not all the chunks will succeed allocating, but freeing nullptr is98// allowed so that is no problem.99for (int x=0; x<2048; ++x)100addr.push_back(b.alloc(x+1));101for (int x=0; x<2048; ++x)102b.free(addr[((x*23)%2048)^242]);103addr.clear();105// Go entirely wild: free and alloc interleaved,106// generate targets and sizes using pseudo-randomness.107for (int x=0; x<2048; ++x)108addr.push_back(nullptr);109uint32_t s = 0x12345678;110for (int x=0; x<5000; ++x) {111int idx = s & (addr.size()-1);112if (s & 0x80000000) {113b.free(addr[idx]);114addr[idx] = nullptr;115} else if(!addr[idx]) {116addr[idx] = b.alloc((s >> 16) & 2047);117}118bool lsb = s & 1;119s >>= 1;120if (lsb)121s ^= 0xf00f00f0; // LFSR period 0xf7ffffe0122}123for (void *ptr: addr)124b.free(ptr);125addr.clear();127BOOST_CHECK(b.stats().total == synth_size);128BOOST_CHECK(b.stats().free == synth_size);129}131/** Mock LockedPageAllocator for testing */132class TestLockedPageAllocator: public LockedPageAllocator133{134public:135TestLockedPageAllocator(int count_in, int lockedcount_in): count(count_in), lockedcount(lockedcount_in) {}136void* AllocateLocked(size_t len, bool *lockingSuccess) override137{138*lockingSuccess = false;139if (count > 0) {140--count;142if (lockedcount > 0) {143--lockedcount;144*lockingSuccess = true;145}147return reinterpret_cast<void*>(uint64_t{static_cast<uint64_t>(0x08000000) + (count << 24)}); // Fake address, do not actually use this memory148}149return nullptr;150}151void FreeLocked(void* addr, size_t len) override152{153}154size_t GetLimit() override155{156return std::numeric_limits<size_t>::max();157}158private:159int count;160int lockedcount;161};163BOOST_AUTO_TEST_CASE(lockedpool_tests_mock)164{165// Test over three virtual arenas, of which one will succeed being locked166std::unique_ptr<LockedPageAllocator> x = std::make_unique<TestLockedPageAllocator>(3, 1);167LockedPool pool(std::move(x));168BOOST_CHECK(pool.stats().total == 0);169BOOST_CHECK(pool.stats().locked == 0);171// Ensure unreasonable requests are refused without allocating anything172void *invalid_toosmall = pool.alloc(0);173BOOST_CHECK(invalid_toosmall == nullptr);174BOOST_CHECK(pool.stats().used == 0);175BOOST_CHECK(pool.stats().free == 0);176void *invalid_toobig = pool.alloc(LockedPool::ARENA_SIZE+1);177BOOST_CHECK(invalid_toobig == nullptr);178BOOST_CHECK(pool.stats().used == 0);179BOOST_CHECK(pool.stats().free == 0);181void *a0 = pool.alloc(LockedPool::ARENA_SIZE / 2);182BOOST_CHECK(a0);183BOOST_CHECK(pool.stats().locked == LockedPool::ARENA_SIZE);184void *a1 = pool.alloc(LockedPool::ARENA_SIZE / 2);185BOOST_CHECK(a1);186void *a2 = pool.alloc(LockedPool::ARENA_SIZE / 2);187BOOST_CHECK(a2);188void *a3 = pool.alloc(LockedPool::ARENA_SIZE / 2);189BOOST_CHECK(a3);190void *a4 = pool.alloc(LockedPool::ARENA_SIZE / 2);191BOOST_CHECK(a4);192void *a5 = pool.alloc(LockedPool::ARENA_SIZE / 2);193BOOST_CHECK(a5);194// We've passed a count of three arenas, so this allocation should fail195void *a6 = pool.alloc(16);196BOOST_CHECK(!a6);198pool.free(a0);199pool.free(a2);200pool.free(a4);201pool.free(a1);202pool.free(a3);203pool.free(a5);204BOOST_CHECK(pool.stats().total == 3*LockedPool::ARENA_SIZE);205BOOST_CHECK(pool.stats().locked == LockedPool::ARENA_SIZE);206BOOST_CHECK(pool.stats().used == 0);207}209// These tests used the live LockedPoolManager object, this is also used210// by other tests so the conditions are somewhat less controllable and thus the211// tests are somewhat more error-prone.212BOOST_AUTO_TEST_CASE(lockedpool_tests_live)213{214LockedPoolManager &pool = LockedPoolManager::Instance();215LockedPool::Stats initial = pool.stats();217void *a0 = pool.alloc(16);218BOOST_CHECK(a0);219// Test reading and writing the allocated memory220*((uint32_t*)a0) = 0x1234;221BOOST_CHECK(*((uint32_t*)a0) == 0x1234);223pool.free(a0);224BOOST_CHECK_EXCEPTION(pool.free(a0), std::runtime_error, HasReason{"Arena: invalid or double free"});225// If more than one new arena was allocated for the above tests, something is wrong226BOOST_CHECK(pool.stats().total <= (initial.total + LockedPool::ARENA_SIZE));227// Usage must be back to where it started228BOOST_CHECK(pool.stats().used == initial.used);229}231BOOST_AUTO_TEST_SUITE_END()
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.