Skip to content

Heap use-after-free when clearing send recipients #856

Description

@epicleafies

SendRecipientsListModel::clear() (qml/models/sendrecipientslistmodel.cpp) deletes each SendRecipient in a loop while its pointer is still in m_recipients; the list is only cleared after the delete loop. During the surrounding beginResetModel()/endResetModel() signal emissions, QML re-enters WalletQmlModel (for example through a coin-control or fee binding) and calls scheduleFeeEstimates(), which runs BuildRecipients() over m_recipients and dereferences the freed recipients.

ASAN on an unmodified qt6 build (99618b0) confirms the use-after-free: freed in SendRecipient::~SendRecipient via clear(), used in BuildRecipients via scheduleFeeEstimates invoked from QML.

clearToFront() in the same file has the same delete-before-remove shape, and additionally removes rows without beginRemoveRows/endRemoveRows (it only emits countChanged), a model-contract violation that desyncs any attached view.

Impact: reproduces intermittently (roughly 3 to 7 percent of runs) when importing a multi-recipient PSBT, which is the recurring qml_test_psbt.py CI failure at the "multi-recipient PSBT submitted" step. It is also reachable from transaction discard and the normal Send page teardown, so it can crash the app during ordinary send flows. #825 (crash on send, with a cascade of null-property TypeErrors from Send.qml during post-send teardown) and #841 (intermittent crash sending a labeled multi-recipient transaction, not reproducible on demand) are consistent with this defect: multi-recipient, teardown-timed, and intermittent.

Suggested fix: detach the container before destroying elements (swap-then-clear, or deleteLater) in both clear() and clearToFront(), and add the missing row-removal notifications to clearToFront() (mirroring the existing remove()).

Related: #762 proposes separating imported-PSBT state from the send draft, which would remove the entanglement at the root; the memory-safety fix stands on its own and is needed regardless.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status
    Open

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions