Repository navigation
fix: v26.10.6's missing x86_64 AppImage, two race fixes, sanitizer lanes, and HackRF unplug + Windows (#42, #46, #47, #75, #80) - #78
Merged
Conversation
… API floor The v26.10.6 tag built every package but the x86_64 AppImage, which failed to compile: HackRfDiscovery.cpp used BOARD_ID_UNDETECTED, a name newer libhackrf headers declare but Ubuntu 22.04's libhackrf-dev 2021.03.1 (the AppImage's build host) calls BOARD_ID_INVALID. Every other build has the newer header, so only the release tag saw it. Use the number, 0xFF, as HackRfWorker::readBoardId already does. No per-PR lane builds against that header, and this is the second break of this class (#67), so add libhackrf_api_floor: a ctest source scan that fails when src/ uses a libhackrf name outside the 2021.03.1 header's declarations. Checked against the 2021.03.1 header itself: every HackRF source compiles with it after this change, and the scan flags exactly the two lines that broke the tag. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The full suite failed once on main with "sim: nothing emitted after disconnected() (spectrumFrameReady)" in backend_seam_affinity_test. RadioModel disconnects the simulator's vended RadioConnection directly, and SimBackend turned that into two queued slots: a signal-to-signal re-emit of disconnected(), then the handler that clears m_connected and stops the worker. A spectrum row the worker queued between the two was forwarded after the announcement, breaking IRadioBackend rule 6. One handler now closes the gate and then emits disconnected(), so there is no gap for a row to land in. The core of upstream aethersdr#6088; its session stamp on spectrum rows depends on refactors this fork does not have. sim_backend_test pins the ordering: at the moment disconnected() is announced the backend already reports disconnected, and a row emitted from inside that announcement is dropped. Both checks failed before the fix. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
icom_identity_test failed intermittently ("ambiguity releases the previously
selected destination without retargeting unkey"): once under ASan on CI and
2 runs in 40 in a plain local Debug build. sendUserCommand() read the clock
once, queueWrite() stamped the request with a second, later reading, and the
pump at the first reading skipped the request as not yet due. When a
millisecond boundary fell between the two reads, the PTT-off write sat in
the queue until the next timer tick instead of leaving at once.
Pump with a fresh reading. The disconnect path already reads the clock after
queueing its emergency writes; the meter tick's reads are routine and only
wait one tick.
A test seam, m_nowForTest, lets the test make every clock reading later than
the last, which reproduces the race on every run: the new check failed
deterministically before the fix and passes after it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t timeouts under sanitizers (#46, #47) Both weekly sanitizer lanes have been red for weeks without finding a sanitizer report: - ASan + UBSan (#47) stopped building on 2026-10-03: "final link failed: No space left on device". Every test executable linked its own static copy of libaethercore. A new AETHER_SHARED_CORE option (default OFF, never for releases) builds the core as one shared library, and the ASan lane turns it on. From upstream aethersdr#6136, with its workflow changes: df -h around the build, and a Configure or Build failure now reaches the tracking issue instead of skipping the whole report chain. Static checks assert per PR that the option yields libaethercore.so and the default stays static. - TSan (#46) timed out weather_radar_loading_test every week. It takes ~15 s in a plain build (mostly waiting), 26 s under ASan, and over its 30 s limit under TSan. In an instrumented build every test TIMEOUT, its own or the 300 s default, is now multiplied by AETHER_SANITIZER_TIMEOUT_SCALE (4). Ordinary builds keep every limit as written. From upstream aethersdr#6208. Verified locally: the whole tree (app and all 512 tests) builds with AETHER_SHARED_CORE=ON and every test passes; a configure with -fsanitize=thread scales weather_radar_loading_test to 120 s and a plain configure leaves it at 30 s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
HackRfWorker declared streamStopped() and HackRfBackend handled it, but nothing ever emitted it. libhackrf reports a stream that dies under it (unplug, USB error, reset) only by calling back no more, so the spectrum froze, the session stayed "connected", and connecting again was refused with "already connected to a radio". The backend's 50 ms arbiter tick now also runs HackRfWorker::checkStreamHealth(). A stream that should be running but that libhackrf says has ended (hackrf_is_streaming), or that has delivered no transfer for 2 s, is marked stopped and reported once. The backend then reports "HackRF stream stopped unexpectedly" and disconnects, in that order: the old handler disconnected first and emitted the error after disconnected(), which IRadioBackend rule 6 forbids. A report after the session has ended is ignored. hackrf_backend_test pins the rule (streamFault) and the ordering; the ordering checks failed on the old handler. tools/hackrf_unplug_test.py checks it on hardware, receive only: it resets the board with libhackrf's own reset request, so it drops off USB and re-enumerates the way an unplug does (or waits for a real unplug with --physical). On a HackRF Pro it passes 9/9 (disconnected in 0.3-0.4 s, still running, reconnects, receives again); on the old build the app never disconnected and could not reconnect. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every Windows build so far compiled the HackRF backend out: nothing supplied libhackrf, which ships no Windows binaries. scripts/setup/setup-hackrf.ps1 builds it the way Great Scott Gadgets' own Windows guide does, with MSVC against vcpkg's libusb and pthreads, at the release the macOS DMG builds (2026.01.3, from its .zip; the host/libhackrf tree is identical to the .tar.xz the DMG pins). It stages hackrf.h, hackrf.lib and the hackrf, libusb and pthreads DLLs in third_party/hackrf. - CMakeLists.txt: on Windows, link that staging as an imported DLL and copy its DLLs next to AetherSDR.exe. The probes now chain on HACKRF_TARGET rather than HACKRF_FOUND, which pkg_check_modules caches: keyed on the flag, a reconfigure skipped the probe that sets the target and the core built without libhackrf's include path. - windows-installer.yml: build it (cached on the script), configure with REQUIRE_HACKRF=ON, and ship the three DLLs in the payload, where check-deploy-dependencies.ps1 already proves every import is present. - ci.yml check-windows: the same build and REQUIRE_HACKRF=ON, so every PR compiles the backend with MSVC. - README: an optional setup step in the Windows build instructions. docs/HACKRF.md: a Windows section (no Zadig: the firmware asks Windows for WinUSB). Not yet checked against a HackRF on a Windows machine, and the doc says so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ry (#42) libhackrf built and staged on both Windows lanes; the step then failed on its last line, removing third_party\hackrf-temp, because something still held a handle on build\src a moment after the post-link DLL copy. The scratch tree is now removed with a short retry and only a warning if it stays busy, and Expand-Archive overwrites a leftover one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rts (#80) The TSan image now carries Qt 6.12.0 (it was 6.8.3 on the last weekly run), and four tests fail on two reports that are wholly inside Qt: tci_automation, tci_server_review and hl2_tci_signaling on the lock-order inversion between QSslSocketPrivate::tlsBackendInUse() and the TLS factory-loader mutex, and whats_new_dialog on ~QHttpThreadDelegate vs a main-thread reply delete. Upstream suppressed exactly these two, anchored on the Qt frames, in aethersdr#6173; this takes its tsan.supp entries verbatim. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 20, 2026
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.
Closes #75, closes #46, closes #47, closes #80, closes #42.
All four open issues, plus the broken v26.10.6 x86_64 AppImage.
v26.10.6 shipped without an x86_64 AppImage
HackRfDiscovery.cppusedBOARD_ID_UNDETECTED, which Ubuntu 22.04's libhackrf 2021.03.1 (the x86_64 AppImage's build host) callsBOARD_ID_INVALID. Only the tag build uses that header, so only the release broke, and release signing timed out waiting for the missing file. It now uses the number, 0xFF. A new ctest,libhackrf_api_floor, fails whensrc/uses a libhackrf name the 2021.03.1 header doesn't declare. This is the second break of this kind (#67).#75: the demo radio sent a frame after "disconnected"
RadioModeldisconnects the simulator's vended connection directly, andSimBackendsplit that into two queued slots: re-emitdisconnected(), then close the gate. A spectrum row could land between them. One handler now closes the gate and then announces the disconnect, the core of upstream aethersdr#6088.#47: ASan lane
sendUserCommand()read the clock once andqueueWrite()stamped the request with a later reading, so the pump skipped the PTT-off as not yet due whenever a millisecond boundary fell between the two. This failed 2 of 40 local runs. It now pumps with a fresh reading. A clock seam reproduces the race on every run: the new check failed before the fix, and 40 of 40 runs pass after it.AETHER_SHARED_COREoption (sanitizer CI only) builds the core as one shared library, from upstream ci(sanitizers): link the ASan lane against a shared core so it fits on disk. Principle VIII. aethersdr/AetherSDR#6136. A failed Configure or Build now reaches the tracking issue instead of skipping the whole report chain.#46: TSan lane
weather_radar_loading_testtimed out every week, with a 30 s limit against ~15 s plain and 26 s under ASan. In instrumented builds every TIMEOUT is now ×4 (upstream aethersdr#6208); ordinary builds keep their limits.#80: TSan on Qt 6.12
The TSan image moved from Qt 6.8.3 to 6.12.0, and four tests (tci_automation, tci_server_review, hl2_tci_signaling, whats_new_dialog) now fail on two reports wholly inside Qt: a lock-order inversion in its TLS backend init, and
~QHttpThreadDelegateracing a main-thread reply delete. Upstream suppressed exactly these, anchored on the Qt frames, in aethersdr#6173;tsan.supptakes those entries verbatim.#42: HackRF backend, the last two items
HackRfWorker::streamStoppedwas declared and handled but never emitted. An unplugged HackRF froze the spectrum, stayed "connected", and refused a reconnect. The backend's 50 ms tick now runscheckStreamHealth(): if libhackrf says the stream ended, or no transfer arrives for 2 s, the backend reports "HackRF stream stopped unexpectedly" and disconnects, in that order (rule 6).scripts/setup/setup-hackrf.ps1builds libhackrf 2026.01.3 with MSVC against vcpkg's libusb and pthreads, as Great Scott Gadgets' guide does. The installer and portable ZIP ship hackrf.dll, libusb-1.0.dll and pthreadVC3.dll, andREQUIRE_HACKRF=ONgates both the installer and the per-PR Windows build. The firmware asks Windows for WinUSB, so there's no Zadig step.Testing
Whole tree with
AETHER_SHARED_CORE=ON: builds, and 512/512 ctest pass.A
-fsanitize=threadconfigure scalesweather_radar_loading_testto 120 s; a plain configure leaves it at 30 s.Every HackRF source compiles against the libhackrf 2021.03.1 header.
Unplug, on hardware (HackRF Pro).
tools/hackrf_unplug_test.py(new, receive only) resets the board with libhackrf's reset request, so it drops off USB and re-enumerates. It passed 9/9:On the old build the app never disconnected and refused to reconnect.
Red then green:
sim_backend_test(2 checks),icom_identity_test(1),hackrf_backend_test(2 ordering checks).Windows: CI only, not yet run against a HackRF on Windows. The Windows Installer and AppImage workflows are dispatched on this branch before merge.
🤖 Generated with Claude Code