Canceling a DVK WAV transfer and starting another before deferred work arrives lets the canceled operation mutate the replacement. This is a P1 crash/cross-transfer bug confirmed by source tracing at upstream/main 87b80c6; deterministic reproduction and regression coverage are being prepared.
Public source: https://github.com/aethersdr/AetherSDR/blob/main/src/core/DvkWavTransfer.cpp
Both command callbacks capture raw this. The port handlers reject only m_cancelled, which both start methods reset. A reply from canceled operation A is therefore admitted during operation B, including a different transfer direction. It can create/truncate B's output or finish/clean up B on an old error. Callbacks also outlive the transfer object if the model retains them.
The upload reply schedules a 200 ms lambda that likewise only checks m_cancelled before dereferencing m_client. Cancel A, start B while awaiting its reply, and A's timer dereferences the cleared client. If B already has a client, A can connect it to A's old port.
Proposed narrow fix: operation identity plus expected-phase checks for command replies and delayed connection, weak QObject lifetime checks, and captured socket identity. Preserve existing wire commands and WAV format. Add socket-free cancel/restart regressions in both directions, including same-direction replacements and mutations that remove each guard. No live radio writes or TX are needed to prove stale-work rejection.
Related: #2501 / #3309 fixed duplicate socket completion and teardown reentry, not deferred work crossing transfers. #5634 / #5638 address the analogous ProfileTransfer lifecycle independently.
Generated with OpenAI Codex.
Canceling a DVK WAV transfer and starting another before deferred work arrives lets the canceled operation mutate the replacement. This is a P1 crash/cross-transfer bug confirmed by source tracing at upstream/main 87b80c6; deterministic reproduction and regression coverage are being prepared.
Public source: https://github.com/aethersdr/AetherSDR/blob/main/src/core/DvkWavTransfer.cpp
Both command callbacks capture raw this. The port handlers reject only m_cancelled, which both start methods reset. A reply from canceled operation A is therefore admitted during operation B, including a different transfer direction. It can create/truncate B's output or finish/clean up B on an old error. Callbacks also outlive the transfer object if the model retains them.
The upload reply schedules a 200 ms lambda that likewise only checks m_cancelled before dereferencing m_client. Cancel A, start B while awaiting its reply, and A's timer dereferences the cleared client. If B already has a client, A can connect it to A's old port.
Proposed narrow fix: operation identity plus expected-phase checks for command replies and delayed connection, weak QObject lifetime checks, and captured socket identity. Preserve existing wire commands and WAV format. Add socket-free cancel/restart regressions in both directions, including same-direction replacements and mutations that remove each guard. No live radio writes or TX are needed to prove stale-work rejection.
Related: #2501 / #3309 fixed duplicate socket completion and teardown reentry, not deferred work crossing transfers. #5634 / #5638 address the analogous ProfileTransfer lifecycle independently.
Generated with OpenAI Codex.