kernel: guard btck::Handle move-assignment against self-move#35143
Merged
fanquake merged 1 commit intobitcoin:masterfrom Apr 26, 2026
Merged
kernel: guard btck::Handle move-assignment against self-move#35143fanquake merged 1 commit intobitcoin:masterfrom
fanquake merged 1 commit intobitcoin:masterfrom
Conversation
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.
Contributor
|
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ReviewsSee the guideline for information on the review process.
If your review is incorrectly listed, please copy-paste |
sedited
approved these changes
Apr 23, 2026
Contributor
alexanderwiederin
left a comment
There was a problem hiding this comment.
ACK 14547eb
Fixes double-free on self-move assignment with the if (this != &other) guard already present in the copy-assignment operator.
yuvicc
reviewed
Apr 26, 2026
sedited
pushed a commit
to sedited/rust-bitcoinkernel
that referenced
this pull request
Apr 30, 2026
…e8612d6 fb0e8612d6 Merge bitcoin/bitcoin#35175: multi_index: fix compilation failure with boost >= 1.91 cef58341a0 Merge bitcoin/bitcoin#32876: refactor: use options struct for signing and PSBT operations 0bc9d354df multi_index: fix compilation failure with boost >= 1.91 eab72d14d7 refactor: use SignOptions for MutableTransactionSignatureCreator 5ed41752c5 refactor: use SignOptions for SignTransaction dc4a5d1270 refactor: use PSBTFillOptions for filling and signing 8592152186 Merge bitcoin/bitcoin#34911: rpc, mempool: -deprecatedrpc fullrbf and bip125-replaceable from mempool RPCs ad3f73862b Merge bitcoin/bitcoin#35149: doc: clarify clang-tidy in developer notes f40da7afc0 Merge bitcoin/bitcoin#35153: doc: update llvm based coverage example a7bea426b4 Merge bitcoin/bitcoin#35143: kernel: guard btck::Handle move-assignment against self-move ef21e29298 doc: update llvm based coverage example a1e534bbf0 doc: clarify clang-tidy in developer notes 8deed0df06 doc: add release notes for PR 34911 1a85ca1dff rpc, mempool: rpcdeprecate `bip125-replaceable` key in mempool RPCs reponses f89d18c3b1 rpc, mempool: rpcdeprecate `fullrbf` key in getmempoolinfo RPC response 14547eb489 kernel: guard btck::Handle move-assignment against self-move git-subtree-dir: libbitcoinkernel-sys/bitcoin git-subtree-split: fb0e8612d6f74071af77b3f27d915da69e0a726b
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The move-assignment operator for
btck::Handle<>insrc/kernel/bitcoinkernel_wrapper.hunconditionally calledDestroyFunc(m_ptr)before reading the source pointer. On a self-move (h = std::move(h)), this destroys the held resource and then restores the now-dangling pointer viastd::exchange(other.m_ptr, nullptr)(since&other == this), which leavesm_ptrpointing at freed memory. The destructor then callsDestroyFuncagain on it, resulting in a double-free.Trace of
h = std::move(h)with the old code, whereh.m_ptr == P:DestroyFunc(m_ptr)->delete P.this->m_ptrstill literally stores the now-dangling valueP.std::exchange(other.m_ptr, nullptr)— because&other == this, this reads the danglingPback, writesnullptrtom_ptr, and returnsP.m_ptr = Prestores the dangling pointer.~Handle()later runsDestroyFunc(P)-> double free, UB.The copy-assignment operator already guards against self-assignment with
if (this != &other); the move variant should be symmetric. The standard library requires moved-from objects to be in a valid (at minimum, safely destructible) state, which the previous implementation violated when source and destination alias.Handle<>is the base class 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 (std::sort,std::remove, erase-remove idioms, etc.).Fix: mirror the copy-assignment pattern by guarding the move-assignment body with
if (this != &other), making a self-move a no-op.Also extend
CheckHandleinsrc/test/kernel/test_kernel.cppto exercise self-move-assignment for everyHandle-derived type, checking that the stored pointer and the serialized bytes (where applicable) are unchanged.