Skip to content

SOFA reader fuzz harness + docs site (Doxygen + concepts + Pages)#7

Merged
tap merged 2 commits into
mainfrom
claude/ambitap-audit-review-rjj2md
Jul 3, 2026
Merged

SOFA reader fuzz harness + docs site (Doxygen + concepts + Pages)#7
tap merged 2 commits into
mainfrom
claude/ambitap-audit-review-rjj2md

Conversation

@tap

@tap tap commented Jul 3, 2026

Copy link
Copy Markdown
Owner

Summary

Two quality/evidence items — and a real bug the fuzzer caught on its first run.

SOFA reader fuzzing 🐛

  • tests/fuzz/fuzz_sofa_reader.cpp — a libFuzzer harness over the whole load_sofadecompose_sh path, the library's only untrusted-file surface. Clang + ASan/UBSan, behind a new AMBITAP_BUILD_FUZZERS option (requires Clang + AMBITAP_ENABLE_SOFA), with a small deterministic seed corpus (tests/fuzz/corpus/: one valid SOFA + hand-authored malformed cases).
  • The bug: load_sofa dereferenced Data.IR, SourcePosition, and Data.SamplingRate through the file's declared M/N/R dimensions without checking those arrays were present and sized — a truncated or hostile file that parsed structurally read off a null/short buffer (UBSan: load of null float* at sofa_reader.h:161). Fixed by validating every dereferenced array against its expected element count up front; malformed inputs now throw cleanly.
  • tests/test_sofa.cpp — reject-malformed contract (built on the SOFA CI leg).
  • CI: a new bounded fuzz (sofa reader smoke) job (clang-18) replays the seed corpus and fuzzes a few minutes on every push. tests/fuzz/README.md documents deep-campaign usage.

Docs site

  • docs/CONCEPTS.md — orientation guide: conventions, the real-time contract, the processor lifecycle, the embedded profile.
  • docs/Doxyfile — API reference generated from the header doc-comments (README as main page; AUDIT/EMBEDDED/COMPARISON/CONCEPTS as related pages; generated tables excluded; Graphviz include graphs). The doc-comment warnings it surfaced (undocumented params on matrix_applier/sh_block_applier/probe_response, a couple of literal angle-bracket tokens) are cleaned up.
  • .github/workflows/docs.yml — build on PRs, deploy to GitHub Pages from main. docs/html/ is gitignored (generated).

Notes for merge

  • Pages deploy needs Pages enabled once in repo settings (Settings → Pages → Source: GitHub Actions). Until then the deploy step no-ops/errors, but the build step still validates docs on every PR.
  • The fuzz job is pinned to clang-18 + its exact runtime package (libclang-rt-18-dev), matching the format job's toolchain.

Test plan

  • 118 tests green with AMBITAP_ENABLE_SOFA=ON (116 + 2 new SOFA tests)
  • 116 tests green in the default build
  • Fuzzer builds (clang-18 + ASan/UBSan) and smoke-runs clean over the committed corpus
  • Original crash reproducer now passes; regression covered by test_sofa.cpp
  • Doxygen builds warning-clean (bar two cosmetic cross-refs)
  • clang-format clean

🤖 Generated with Claude Code

https://claude.ai/code/session_01Ng2WDk5ho2yhzvfC2boRPQ


Generated by Claude Code

tap and others added 2 commits July 3, 2026 04:39
Two evidence/quality items — and a real bug the fuzzer caught on its first
run.

Fuzzing:
- tests/fuzz/fuzz_sofa_reader.cpp: libFuzzer harness over the SOFA reader
  (load_sofa + decompose_sh), the library's only untrusted-file surface.
  Clang + ASan/UBSan; AMBITAP_BUILD_FUZZERS CMake option (requires Clang +
  AMBITAP_ENABLE_SOFA); small deterministic seed corpus in
  tests/fuzz/corpus/ (one valid SOFA + hand-authored malformed cases).
- Bug found: load_sofa dereferenced Data.IR, SourcePosition, and
  Data.SamplingRate through the declared M/N/R dimensions without checking
  the arrays were present and sized — a truncated or hostile file that
  parsed structurally read off a null/short buffer (UBSan: load of null
  float* at sofa_reader.h:161). Fixed by validating every dereferenced
  array against its expected element count up front; malformed inputs now
  throw cleanly.
- tests/test_sofa.cpp: reject-malformed contract (built on the SOFA leg).
- CI: new bounded "fuzz (sofa reader smoke)" job — clang-18, replays the
  seed corpus and fuzzes a few minutes on every push. tests/fuzz/README.md
  documents deep-campaign usage.

Docs site:
- docs/CONCEPTS.md: the orientation guide — conventions, the real-time
  contract, the processor lifecycle, the embedded profile.
- docs/Doxyfile: API reference generated from the header doc-comments
  (README as mainpage; AUDIT/EMBEDDED/COMPARISON/CONCEPTS as related
  pages; generated tables excluded; Graphviz include graphs). Cleaned up
  the doc-comment warnings it surfaced (undocumented params on
  matrix_applier/sh_block_applier/probe_response, a couple of literal
  angle-bracket tokens).
- .github/workflows/docs.yml: build on PRs, deploy to GitHub Pages from
  main. docs/html/ is gitignored (generated).
- README documentation section + AUDIT.md ledger updated.

118 tests green with SOFA enabled (116 + 2 new); fuzzer smoke-runs clean
over the committed corpus; Doxygen builds warning-clean (bar two cosmetic
cross-refs); format clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ng2WDk5ho2yhzvfC2boRPQ
Integrates the measured C++ head-to-head against libspatialaudio and SAF:

- bench/compare/: run.sh clones + builds libspatialaudio 0.4.1 and SAF
  v1.3.5 from source, compiles the two harnesses
  (bench_libspatialaudio.cpp, bench_saf.c), and runs all three benchmarks
  (AmbiTap's own bench/ + the two others) with one shared methodology
  (48 kHz, median of 9x400 blocks, 50 warm-up). README documents the
  known asymmetries (SAF's afSTFT filterbank vs broadband matrix decoders;
  libspatialaudio's order-1-only built-in HRTF; SAF SIMD off by default).
- docs/COMPARISON.md: adds the measured µs/block head-to-head table
  (encoder/rotator/decoder/binaural, orders 1/3/5), a platforms/SIMD
  matrix, per-library pros/cons, and a refreshed feature matrix current to
  July 2026. Numbers captured on a single Xeon; the doc says to re-run
  before quoting absolutes.

The harnesses depend on external libraries (GitHub clones + OpenBLAS/
LAPACKE) so they are a manual reproducibility tool like the Python
comparison notebook, not wired into CI. bench/compare/_work/ (the clones)
is gitignored; bench/compare/ is excluded from the clang-format gate and
.clang-format-ignore (external-style throwaway harnesses, one of them C).
README documentation section updated to point at the head-to-head.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ng2WDk5ho2yhzvfC2boRPQ
@tap tap merged commit f0b3f8e into main Jul 3, 2026
12 of 13 checks passed
@tap tap deleted the claude/ambitap-audit-review-rjj2md branch July 3, 2026 16:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant