freedv-gui/test
Mooneer Salem 2c7aa5ff82
Windows CI: RADE loss testing + ASan/UBSan sanitizer coverage (#1487)
* CI (Windows): add RADE loss testing (prerequisite for sanitizer coverage)

Ports the RADE loss test infrastructure from the ms-rade-v2 branch
(as of commit f013450b there) so the Windows sanitizer jobs added in
the following commits have a RADE loss test to actually run:

- test/TestFreeDVRadeLoss.ps1: transmits a known corpus through FreeDV,
  records the result, plays it back through RX, and compares TX/RX RADE
  features via loss.py against a threshold.
- test/RadeVerificationReport.ps1: assembles the RADE integration
  verification report from a test run.
- cmake-windows.yml: adds the rade-loss-baseline job (computes the loss
  threshold from a software-only baseline on Linux, since rade_tx_wav/
  rade_rx_wav are excluded from the Windows build), wires RADE loss
  testing and verification-report generation into the `test` job, adds
  crash dump collection (WER LocalDumps) for post-mortem diagnosis, and
  switches audio-endpoint readiness waiting to Wait-AudioDevices.ps1 to
  avoid starting a test before a virtual cable is actually enumerable.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jz1Nz4hmnEzwQ7hjQtCBhk

* Windows CI: add UBSan/ASan sanitizer build+test jobs

llvm-mingw supports UBSan on every architecture it targets and ASan on
x86 only (confirmed against the toolchain's own release assets: only
x86_64/i386 ship a libclang_rt.asan_dynamic-*.dll, no aarch64 variant
exists). Adds build-sanitizer (mirrors build-pgo-inst minus PGO, one
variant per {UBSAN x86_64, UBSAN aarch64, ASAN x86_64}) and
test-sanitizer (mirrors test, pointed at the new artifacts).

No manual DLL copy step needed for ASan: cmake/GetDependencies.cmake.in
already walks freedv.exe's PE import table via objdump and derives the
toolchain's <arch>-w64-mingw32/bin/ directory as a search path when
FREEDV_USING_LLVM_MINGW is set -- the same mechanism that bundles every
other DLL dependency already picks up libclang_rt.asan_dynamic-*.dll
automatically once ENABLE_ASAN is on. This path was already prepared
for in a prior commit (73cd6f49, "Fix cross-compile definitions to
allow asan to be used in the first place") but never wired into CI.

Sanitizer test steps are continue-on-error, matching the existing
SANITIZERS_ENABLED leniency on macOS/Linux (ctest doesn't enforce the
PASS_REGULAR_EXPRESSION under sanitizers there either) -- a sanitizer
build is slower and less reliable for real-time audio, so what matters
here is whether a sanitizer catches a genuine memory-safety/UB bug
(an abort with a diagnostic in the log), not the loss threshold.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jz1Nz4hmnEzwQ7hjQtCBhk

* Fix Windows sanitizer options: drive-letter colon breaks the parser

Every test-sanitizer run was failing at freedv.exe startup with
"AddressSanitizer: ERROR: expected '=' in ASAN_OPTIONS" (and the UBSan
equivalent), masked as job "success" by continue-on-error -- meaning
zero actual testing happened in the previous push.

ASAN_OPTIONS/UBSAN_OPTIONS are colon-separated key=value pairs. The
absolute path used for suppressions= started with a Windows drive
letter (D:\...), and the sanitizer's own option parser split on that
colon too: "suppressions=D" parsed as one pair, then "\...\foo.txt"
(no '=') aborted the parse before FreeDV ever started.

Fix: copy the suppression files next to freedv.exe (alongside the
existing test script copies) and reference them by bare relative
filename, which contains no colon to collide with.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jz1Nz4hmnEzwQ7hjQtCBhk

* Suppress known wxWidgets MSW UBSan finding (null pointer in tooltip.cpp)

wxToolInfo's constructor does a member access through a null pointer of
type TTTOOLINFOW in wx's own MSW backend (tooltip.cpp:100), hit
consistently on both new Windows UBSAN test-sanitizer jobs
(windows-2022 and windows-11-arm). Third-party code, not ours -- same
treatment as the existing macOS vptr suppressions for wx's own latent
UB.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jz1Nz4hmnEzwQ7hjQtCBhk

* Suppress libressl UBSan finding; make Windows sanitizer jobs actually fail

test/ubsan_suppressions.txt: add function:crypto/stack/stack.c for
"call to function local_sk_X509_NAME_ENTRY_pop_free through pointer to
incorrect function type" -- a well-known, benign pattern in OpenSSL/
LibreSSL's type-erased sk_TYPE_pop_free callback casting, not a real bug.

cmake-windows.yml: the three test-sanitizer test steps are
continue-on-error (needed so an ordinary loss-threshold miss under
instrumentation overhead doesn't stop the other tests, matching the
SANITIZERS_ENABLED leniency ctest already gives sanitizer builds on
macOS/Linux) -- but continue-on-error suppresses the job's conclusion,
not just the step's outcome, so a genuine sanitizer abort was *also*
being swallowed into job "success" with no fix. Added a "Check for
sanitizer errors" step (no continue-on-error) that scans every test's
captured output for an actual AddressSanitizer/UndefinedBehaviorSanitizer/
LeakSanitizer report and fails the job for real if one is found, while
a plain "Test failed" from a loss-threshold miss (no sanitizer report
in the output) still doesn't. Also wired Tee-Object logging into the
FullDuplex and Reporting test steps (RadeLoss already had it) so all
three are covered by the scan.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jz1Nz4hmnEzwQ7hjQtCBhk

* CI (Windows): drop RadeVerificationReport, fix missing hamlibserver.py

Remove RadeVerificationReport.ps1 and the workflow steps that generate/
upload the RADE verification report from the `test` job -- out of scope
for this PR (Windows ASan/UBSan CI + the RADE loss test infra it needs).

Separately: PR CI showed both `test` and `test-sanitizer (ASAN, ...)`
failing the RADE Reporting step with "python.exe: can't open file
'...\bin\hamlibserver.py'". TestFreeDVReporting.ps1 unconditionally
launches hamlibserver.py (a mock rigctld) as a subprocess before
starting FreeDV, but neither job's "Copy test scripts to install
folder" step actually copied it there -- only TestFreeDVReporting.ps1
itself and its conf template were copied. Added the missing Copy-Item
to both jobs.

(The consequent "Couldn't connect to Radio with hamlib" fatal error
also triggered an apparent AddressSanitizer heap-use-after-free in
wxMutexInternal::LockTimeout during the ASan job's abnormal shutdown --
very likely collateral damage from the broken test flow rather than a
real bug, but worth re-checking once this fix lands.)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jz1Nz4hmnEzwQ7hjQtCBhk

* CI (Windows): actually commit the RadeVerificationReport/hamlib workflow changes

Follow-up to 54aa6988 -- that commit only picked up the file deletion;
the cmake-windows.yml edits (removing the report generation/upload
steps and the RadeVerificationReport.ps1 copy, adding the missing
hamlibserver.py copy to both the test and test-sanitizer jobs) didn't
get staged due to a failed `git add` on the already-removed path.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jz1Nz4hmnEzwQ7hjQtCBhk

* master still uses RADEV1, not V2.

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 10:53:43 -07:00
..
fading Build AppImages as part of CI workflow. (#937) 2025-06-24 08:57:46 -07:00
GeneratePGOProfiles.ps1 CI (Windows): make collect-pgo-profile wait for real audio endpoints (#1483) 2026-09-07 23:57:12 -07:00
TestFreeDVFullDuplex.ps1 Tighten remaining audio settings to improve CI pass rate. (#1412) 2026-06-23 15:59:56 -07:00
TestFreeDVRadeLoss.ps1 Windows CI: RADE loss testing + ASan/UBSan sanitizer coverage (#1487) 2026-09-13 10:53:43 -07:00
TestFreeDVReporting.ps1 Tighten remaining audio settings to improve CI pass rate. (#1412) 2026-06-23 15:59:56 -07:00
asan_suppressions.txt Remove 800XA, 700C, 2020 and 2020B. (#889) 2025-05-26 12:29:47 -07:00
check-for-zeros.py Add tests to verify lack of sync loss in RX (#761) 2024-11-23 08:08:40 -08:00
freedv-ctest-fullduplex.conf.tmpl Hide all modes except for RADE by default. (#1108) 2025-12-10 16:00:47 -08:00
freedv-ctest-loss.conf.tmpl Hide all modes except for RADE by default. (#1108) 2025-12-10 16:00:47 -08:00
freedv-ctest-reporting-mpp.conf.tmpl Hide all modes except for RADE by default. (#1108) 2025-12-10 16:00:47 -08:00
freedv-ctest-reporting.conf.tmpl Hide all modes except for RADE by default. (#1108) 2025-12-10 16:00:47 -08:00
freedv-ctest.conf.tmpl Hide all modes except for RADE by default. (#1108) 2025-12-10 16:00:47 -08:00
freedv-pgo.conf.tmpl Enable LTO/PGO for macOS .app build. (#1456) 2026-08-07 16:32:00 -07:00
generate_pgo_profiles.sh Enable Linux AppImage builds for Profile Guided Optimization (PGO). (#1173) 2026-01-28 13:00:49 -08:00
hamlibserver.py Ensure that PTT is actually off when opening Hamlib connection. (#1308) 2026-04-25 14:35:02 -07:00
lsan_suppressions.txt Upgrade built-in Python to 3.14.0. (#1109) 2025-11-30 19:02:40 -08:00
test_rade_loss.sh Prevent PulseAudio/pipewire from quitting during CI tests. (#1455) 2026-08-05 14:48:45 -07:00
test_rade_reporting.sh test: fix intermittent rade_reporting_awgn CI failure (#1484) 2026-09-08 07:30:36 -07:00
test_zeros.sh Prevent PulseAudio/pipewire from quitting during CI tests. (#1455) 2026-08-05 14:48:45 -07:00
ubsan_suppressions.txt Windows CI: RADE loss testing + ASan/UBSan sanitizer coverage (#1487) 2026-09-13 10:53:43 -07:00