From 14547eb489243a1991a91447af2919de16b0fc98 Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 23 Apr 2026 12:46:39 +0200 Subject: [PATCH] kernel: guard btck::Handle move-assignment against self-move The move-assignment operator for btck::Handle<> unconditionally called DestroyFunc(m_ptr) before reading the source pointer. On a self-move (h = std::move(h)), this destroyed the held resource and then reassigned the now-dangling pointer back to m_ptr via std::exchange, leading to a double-free when the object is later destroyed. Mirror the existing self-check in the copy-assignment operator by guarding the move-assignment with 'if (this != &other)' so a self-move becomes a no-op, leaving the object in a valid state as required by the standard library. Handle<> is the base of 16 public types in the kernel C++ API wrapper (Transaction, Block, BlockHeader, ChainParams, Context, Coin, BlockValidationState, ScriptPubkey, TransactionOutput, Txid, OutPoint, TransactionInput, PrecomputedTransactionData, BlockHash, BlockSpentOutputs, TransactionSpentOutputs), so self-move can arise from generic algorithms operating on containers of these types. Extend CheckHandle in test_kernel to cover self-move-assignment for every Handle-derived type. --- src/kernel/bitcoinkernel_wrapper.h | 6 ++++-- src/test/kernel/test_kernel.cpp | 10 ++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/kernel/bitcoinkernel_wrapper.h b/src/kernel/bitcoinkernel_wrapper.h index 38dd709f948..12299dfa130 100644 --- a/src/kernel/bitcoinkernel_wrapper.h +++ b/src/kernel/bitcoinkernel_wrapper.h @@ -341,8 +341,10 @@ public: Handle(Handle&& other) noexcept : m_ptr(other.m_ptr) { other.m_ptr = nullptr; } Handle& operator=(Handle&& other) noexcept { - DestroyFunc(m_ptr); - m_ptr = std::exchange(other.m_ptr, nullptr); + if (this != &other) { + DestroyFunc(m_ptr); + m_ptr = std::exchange(other.m_ptr, nullptr); + } return *this; } diff --git a/src/test/kernel/test_kernel.cpp b/src/test/kernel/test_kernel.cpp index b22a5edede9..76b8398a7d7 100644 --- a/src/test/kernel/test_kernel.cpp +++ b/src/test/kernel/test_kernel.cpp @@ -315,6 +315,16 @@ void CheckHandle(T object, T distinct_object) if constexpr (HasToBytes) { check_equal(object2.ToBytes(), object3.ToBytes()); } + + // Self move-assignment must not destroy the held resource. + // Use a reference to avoid -Wself-move warnings. + original_ptr = object2.get(); + auto& object2_ref = object2; + object2 = std::move(object2_ref); + BOOST_CHECK_EQUAL(object2.get(), original_ptr); + if constexpr (HasToBytes) { + check_equal(object2.ToBytes(), object3.ToBytes()); + } } template