aethersdr / aethersdr/AetherSDR
[Hardening] DAX nudge one-shot: re-arm coupled to broad streamStatusRemoved (in_use==0) — follow-up to #4384
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 221
- Forks
- 117
- Avg merge
- 2d 7h
- Merged PRs (30d)
- 299
Description
Summary
Follow-up hardening from the review of #4384 (merged, fixes #4383). The #1439 DAX-nudge one-shot (m_nudgedDaxStreams) re-arms by clearing the stream id in the removed-branch of RadioModel::handleDaxRxStreamRegistry, gated on streamStatusRemoved():
// src/models/RadioModel.cpp (removed-branch)
if (streamStatusRemoved(stream, kvs)) {
m_panStream->unregisterDaxStream(stream.streamId);
m_nudgedDaxStreams.remove(stream.streamId); // re-arm the one-shot
return;
}
streamStatusRemoved() is deliberately broad (src/models/RadioModel.cpp:192-198):
return stream.action == QStringLiteral("removed")
|| kvs.contains(QStringLiteral("removed"))
|| kvs.value(QStringLiteral("in_use")) == QStringLiteral("0");
The latent fragility
The #4384 loop-freedom guarantee relies on an unstated assumption: that a dax_rx stream status never carries in_use=0 during the radio's transient unbind→rebind. If some firmware did emit in_use=0 on a still-live dax_rx stream during that transient, streamStatusRemoved() would return true, the one-shot would re-arm mid-cycle, and the next empty-slice= echo could re-fire the nudge — partially re-opening the #4009/#4383 storm class.
Verified zero risk on FLEX-8400 fw 4.2.20.41343: across the live storm capture, no dax_rx stream status ever carried in_use (0 occurrences), and the merged fix was confirmed to eliminate the storm on hardware. This is a cross-firmware robustness concern, not a live defect.
Why this needs design, not a one-liner
The tempting fix — narrow the re-arm to stream.action == "removed" only — would regress re-arm on any firmware that signals a genuine teardown via in_use=0 (or a bare removed key) rather than the removed action token: the flag would never clear, so a legitimately re-created stream reusing the same id would not get its create-time nudge (the legacy/WAN !autoBound fallback #1439 exists for). The broad streamStatusRemoved() check is needed for correct removal detection; it is only over-eager as a re-arm trigger.
Suggested direction
Decouple "is this a removal?" from "should the one-shot re-arm?" — e.g.:
- re-arm on a definitive teardown (
action == "removed"or aremovedkey) but treat a barein_use=0on adax_rxstream as not a re-arm trigger unless corroborated by an actual stream removal; or - confirm the stream is truly gone via the PanadapterStream registry (
unregisterDaxStreamresult) before clearingm_nudgedDaxStreams.
Either keeps removal detection intact while making the one-shot's re-arm immune to a transient in_use=0.
Provenance
- Hardening surfaced in the independent review of #4384 (bots did not flag this; their notes were the non-blocking fire-once narrowing).
- Related: #4383 (fixed), #4384 (merged fix), #4009, #4017, #1439.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in src/models/RadioModel.cpp at RadioModel::handleDaxRxStreamRegistry and streamStatusRemoved(), then trace the PanadapterStream registry handling around unregisterDaxStream. Compare the removal signals described in the issue and verify that genuine teardown still re-arms the one-shot while a transient in_use=0 does not; preserve the existing removal detection and loop-freedom behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100