diff --git a/include/bitcoin/system/allocator.hpp b/include/bitcoin/system/allocator.hpp index 6589387e7e..7bba9fd8cc 100644 --- a/include/bitcoin/system/allocator.hpp +++ b/include/bitcoin/system/allocator.hpp @@ -205,6 +205,16 @@ class allocator }; } + /// Utility for passing deleted to shared pointer construction. + template + auto deleter() NOEXCEPT + { + return [arena = arena_](Type* ptr) NOEXCEPT + { + deleter(arena)(ptr); + }; + } + /// Other /// ----------------------------------------------------------------------- @@ -269,6 +279,8 @@ inline bool operator==(const allocator& left, return left == right; } +using byte_allocator = allocator; + } // namespace libbitcoin #endif diff --git a/include/bitcoin/system/chain/block.hpp b/include/bitcoin/system/chain/block.hpp index 83cf2a6345..6db8d06e2f 100644 --- a/include/bitcoin/system/chain/block.hpp +++ b/include/bitcoin/system/chain/block.hpp @@ -114,7 +114,7 @@ class BC_API block /// Set/get memory allocation. void set_allocation(size_t allocation) const NOEXCEPT; - const size_t get_allocation() const NOEXCEPT; + size_t get_allocation() const NOEXCEPT; /// Identity. /// ----------------------------------------------------------------------- diff --git a/src/chain/block.cpp b/src/chain/block.cpp index c2b95f9090..448af5f01a 100644 --- a/src/chain/block.cpp +++ b/src/chain/block.cpp @@ -105,9 +105,9 @@ block::block(reader&& source, bool witness) NOEXCEPT block::block(reader& source, bool witness) NOEXCEPT : header_(source.get_allocator().new_object(source), - source.get_allocator().deleter(source.get_arena())), + source.get_allocator().deleter()), txs_(source.get_allocator().new_object(), - source.get_allocator().deleter(source.get_arena())) + source.get_allocator().deleter()) { assign_data(source, witness); } @@ -149,7 +149,7 @@ void block::assign_data(reader& source, bool witness) NOEXCEPT for (size_t tx = 0; tx < count; ++tx) txs->emplace_back(allocator.new_object(source, witness), - allocator.deleter(source.get_arena())); + allocator.deleter()); size_ = serialized_size(*txs_); valid_ = source; @@ -160,7 +160,7 @@ void block::set_allocation(size_t allocation) const NOEXCEPT allocation_ = allocation; } -const size_t block::get_allocation() const NOEXCEPT +size_t block::get_allocation() const NOEXCEPT { return allocation_; } diff --git a/src/chain/input.cpp b/src/chain/input.cpp index bc37e64f10..776f86d514 100644 --- a/src/chain/input.cpp +++ b/src/chain/input.cpp @@ -177,9 +177,9 @@ input::input(reader&& source) NOEXCEPT // Witness is deserialized and assigned by transaction. input::input(reader& source) NOEXCEPT : point_(source.get_allocator().new_object(source), - source.get_allocator().deleter(source.get_arena())), + source.get_allocator().deleter()), script_(source.get_allocator().new_object(source, true), - source.get_allocator().deleter(source.get_arena())), + source.get_allocator().deleter()), witness_(nullptr), sequence_(source.read_4_bytes_little_endian()), valid_(source), @@ -305,7 +305,7 @@ void input::set_witness(reader& source) NOEXCEPT auto& allocator = source.get_allocator(); witness_.reset(allocator.new_object(source, true), - allocator.deleter(source.get_arena())); + allocator.deleter()); size_.witnessed = ceilinged_add(size_.nominal, witness_->serialized_size(true)); diff --git a/src/chain/operation.cpp b/src/chain/operation.cpp index a3e09530ea..37ed26226b 100644 --- a/src/chain/operation.cpp +++ b/src/chain/operation.cpp @@ -222,7 +222,7 @@ void operation::assign_data(reader& source) NOEXCEPT // An invalid source.read_bytes_raw returns nullptr. allocator.construct(&data_, source.read_bytes_raw(size), - allocator.deleter(source.get_arena())); + allocator.deleter()); underflow_ = !source; diff --git a/src/chain/output.cpp b/src/chain/output.cpp index 7daefbe995..acc46612b9 100644 --- a/src/chain/output.cpp +++ b/src/chain/output.cpp @@ -93,7 +93,7 @@ output::output(reader&& source) NOEXCEPT output::output(reader& source) NOEXCEPT : value_(source.read_8_bytes_little_endian()), script_(source.get_allocator().new_object(source, true), - source.get_allocator().deleter(source.get_arena())), + source.get_allocator().deleter()), valid_(source), size_(serialized_size(*script_, value_)) { diff --git a/src/chain/script.cpp b/src/chain/script.cpp index fdc26e69a8..f552926039 100644 --- a/src/chain/script.cpp +++ b/src/chain/script.cpp @@ -270,6 +270,8 @@ void script::assign_data(reader& source, bool prefix) NOEXCEPT } valid_ = source; + + // TODO: possible leak with linear arena allocation. offset = ops_.begin(); } @@ -285,7 +287,7 @@ script script::from_string(const std::string& mnemonic) NOEXCEPT if (tokens.front().empty()) tokens.clear(); - operations ops; + operations ops{}; ops.reserve(tokens.size()); // Create an op list from the split tokens. diff --git a/src/chain/transaction.cpp b/src/chain/transaction.cpp index 186805322f..c1ce944b62 100644 --- a/src/chain/transaction.cpp +++ b/src/chain/transaction.cpp @@ -159,9 +159,9 @@ transaction::transaction(reader&& source, bool witness) NOEXCEPT transaction::transaction(reader& source, bool witness) NOEXCEPT : version_(source.read_4_bytes_little_endian()), inputs_(source.get_allocator().new_object(), - source.get_allocator().deleter(source.get_arena())), + source.get_allocator().deleter()), outputs_(source.get_allocator().new_object(), - source.get_allocator().deleter(source.get_arena())) + source.get_allocator().deleter()) { assign_data(source, witness); } @@ -244,7 +244,7 @@ void transaction::assign_data(reader& source, bool witness) NOEXCEPT for (size_t in = 0; in < count; ++in) ins->emplace_back( allocator.new_object(source), - allocator.deleter(source.get_arena())); + allocator.deleter()); // Expensive repeated recomputation, so cache segregated state. // Detect witness as no inputs (marker) and expected flag (bip144). @@ -261,14 +261,14 @@ void transaction::assign_data(reader& source, bool witness) NOEXCEPT ins->reserve(count); for (size_t in = 0; in < count; ++in) ins->emplace_back(allocator.new_object(source), - allocator.deleter(source.get_arena())); + allocator.deleter()); auto outs = to_non_const_raw_ptr(outputs_); count = source.read_size(max_block_size); outs->reserve(count); for (size_t out = 0; out < count; ++out) outs->emplace_back(allocator.new_object(source), - allocator.deleter(source.get_arena())); + allocator.deleter()); // Read or skip witnesses as specified. if (witness) @@ -290,7 +290,7 @@ void transaction::assign_data(reader& source, bool witness) NOEXCEPT outs->reserve(count); for (size_t out = 0; out < count; ++out) outs->emplace_back(allocator.new_object(source), - allocator.deleter(source.get_arena())); + allocator.deleter()); } locktime_ = source.read_4_bytes_little_endian(); diff --git a/src/chain/witness.cpp b/src/chain/witness.cpp index 210ddd7113..cfc5e09709 100644 --- a/src/chain/witness.cpp +++ b/src/chain/witness.cpp @@ -167,7 +167,7 @@ void witness::skip(reader& source, bool prefix) NOEXCEPT void witness::assign_data(reader& source, bool prefix) NOEXCEPT { size_ = zero; - const auto& allocator = source.get_allocator(); + auto& allocator = source.get_allocator(); if (prefix) { @@ -178,7 +178,7 @@ void witness::assign_data(reader& source, bool prefix) NOEXCEPT { const auto size = source.read_size(max_block_weight); stack_.emplace_back(source.read_bytes_raw(size), - allocator.deleter(source.get_arena())); + allocator.deleter()); size_ = element_size(size_, stack_.back()); } } @@ -188,7 +188,7 @@ void witness::assign_data(reader& source, bool prefix) NOEXCEPT { const auto size = source.read_size(max_block_weight); stack_.emplace_back(source.read_bytes_raw(size), - allocator.deleter(source.get_arena())); + allocator.deleter()); size_ = element_size(size_, stack_.back()); } } diff --git a/test/stream/streamers/byte_reader.cpp b/test/stream/streamers/byte_reader.cpp index 98c52523dc..819a94d7a9 100644 --- a/test/stream/streamers/byte_reader.cpp +++ b/test/stream/streamers/byte_reader.cpp @@ -1439,7 +1439,7 @@ BOOST_AUTO_TEST_CASE(byte_reader__read_bytes_raw1__end_zero__not_null_valid) const auto ptr = reader.read_bytes_raw(0); BOOST_REQUIRE(ptr != nullptr); BOOST_REQUIRE(reader); - allocator<>::deleter(reader.get_arena())(ptr); + reader.get_allocator().deleter(reader.get_arena())(ptr); } BOOST_AUTO_TEST_CASE(byte_reader__read_bytes_raw1__to_end__expected) @@ -1451,7 +1451,7 @@ BOOST_AUTO_TEST_CASE(byte_reader__read_bytes_raw1__to_end__expected) BOOST_REQUIRE(ptr != nullptr); BOOST_REQUIRE_EQUAL(*ptr, to_chunk("abc")); BOOST_REQUIRE(reader); - allocator<>::deleter(reader.get_arena())(ptr); + reader.get_allocator().deleter()(ptr); } BOOST_AUTO_TEST_CASE(byte_reader__read_bytes_raw1__middle__expected) @@ -1464,7 +1464,7 @@ BOOST_AUTO_TEST_CASE(byte_reader__read_bytes_raw1__middle__expected) BOOST_REQUIRE_EQUAL(*ptr, to_chunk("abc")); BOOST_REQUIRE_EQUAL(stream.get(), '*'); BOOST_REQUIRE(reader); - allocator<>::deleter(reader.get_arena())(ptr); + reader.get_allocator().deleter()(ptr); } BOOST_AUTO_TEST_CASE(byte_reader__read_bytes_raw1__past_end__nullptr_invalid)