kernel: guard btck::Handle move-assignment against self-move #35143

pull thomasbuilds wants to merge 1 commits into bitcoin:master from thomasbuilds:fix-btck-handle-self-move-assign changing 2 files +14 −2
  1. thomasbuilds commented at 11:05 AM on April 23, 2026: contributor

    The move-assignment operator for btck::Handle<> in src/kernel/bitcoinkernel_wrapper.h unconditionally called DestroyFunc(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 via std::exchange(other.m_ptr, nullptr) (since &other == this), which leaves m_ptr pointing at freed memory. The destructor then calls DestroyFunc again on it, resulting in a double-free.

    Trace of h = std::move(h) with the old code, where h.m_ptr == P:

    1. DestroyFunc(m_ptr) -> delete P. this->m_ptr still literally stores the now-dangling value P.
    2. std::exchange(other.m_ptr, nullptr) — because &other == this, this reads the dangling P back, writes nullptr to m_ptr, and returns P.
    3. m_ptr = P restores the dangling pointer.
    4. ~Handle() later runs DestroyFunc(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 CheckHandle in src/test/kernel/test_kernel.cpp to exercise self-move-assignment for every Handle-derived type, checking that the stored pointer and the serialized bytes (where applicable) are unchanged.

  2. 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.
    14547eb489
  3. DrahtBot added the label Validation on Apr 23, 2026
  4. DrahtBot commented at 11:05 AM on April 23, 2026: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    ACK sedited, alexanderwiederin, yuvicc

    If your review is incorrectly listed, please copy-paste <code>&lt;!--meta-tag:bot-skip--&gt;</code> into the comment that the bot should ignore.

    <!--5faf32d7da4f0f540f40219e4f7537a3-->

  5. sedited approved
  6. sedited commented at 11:35 AM on April 23, 2026: contributor

    Thanks, ACK 14547eb489243a1991a91447af2919de16b0fc98

  7. sedited assigned alexanderwiederin on Apr 23, 2026
  8. sedited unassigned alexanderwiederin on Apr 23, 2026
  9. sedited requested review from alexanderwiederin on Apr 23, 2026
  10. ?
    added_to_project_v2 sedited
  11. ?
    project_v2_item_status_changed github-project-automation[bot]
  12. ?
    project_v2_item_status_changed sedited
  13. alexanderwiederin commented at 3:33 PM on April 23, 2026: contributor

    ACK https://github.com/bitcoin/bitcoin/pull/35143/changes/14547eb489243a1991a91447af2919de16b0fc98

    Fixes double-free on self-move assignment with the if (this != &other) guard already present in the copy-assignment operator.

  14. yuvicc commented at 11:17 AM on April 26, 2026: contributor

    lgtm ACK 14547eb489243a1991a91447af2919de16b0fc98

  15. fanquake merged this on Apr 26, 2026
  16. fanquake closed this on Apr 26, 2026

  17. ?
    project_v2_item_status_changed github-project-automation[bot]
  18. thomasbuilds deleted the branch on Apr 27, 2026

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-04-30 21:12 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me