Skip to content

mod-audio-fork: robustness fixes (lifetime, races, input validation, tests) - #3

Draft
pragmatrix wants to merge 36 commits into
questnetfrom
robustness-fixes
Draft

pragmatrix wants to merge 36 commits into
questnetfrom
robustness-fixes

Conversation

@pragmatrix

Copy link
Copy Markdown
Member

Why

mod_audio_fork had several crash and memory-safety problems: use-after-free of the AudioPipe, races between the lws thread and session cleanup, unchecked inputs on the API (missing arguments, unbounded sample rates, long URIs), NULL dereferences, and C++ exceptions that could terminate FreeSWITCH. Some behaviour was also unsafe by default (bidirectional audio enabled implicitly, unbounded inbound binary).

Summary

  • Ownership: AudioPipe is owned by shared_ptr (session side via PipeHandle, pending lists, lws slot). Bidirectional state moved to a shared StreamState so cleanup never frees memory the lws thread uses.
  • Races: concurrent stop and media-bug close tear down only once; context/stopFlag are atomic; send_text and graceful-shutdown read the pipe handle under the session mutex; module unload wakes the lws thread so it can exit.
  • Input validation: start needs the sample rate argument (previously a NULL strcmp crash); sample rates are limited to 64000; host/path are length-checked and strings terminated; the read codec is checked after pre-answer.
  • Exceptions: the lws callback, fork_session_init, parse_ws_uri and enqueueText no longer let C++ exceptions escape into C code.
  • Connections: close() on a not-yet-connected pipe is honoured; failed connects report CONNECT_FAIL and are dropped; texts sent before the websocket is up are queued (up to 1 MB each); start metadata limit raised to 1 MB.
  • Audio: mixing playout audio saturates instead of wrapping; inbound binary is only accepted when it is played back; a playback mode skips forking caller audio.
  • Added: Audio-Fork-Bugname header on all events, bugname no longer limited to 64 bytes, justfile and Dockerfile for compile-and-unit-test runs, just ide-setup.
  • Removed: playAudio and transcription messages and events.
  • issues/review-findings.md records the review status: what is fixed, what was checked and found not to be an issue, and what is still open.

Behaviour changes

  • bidirectional_audio_enable now defaults to 0 for the short start syntax; callers that relied on it being on must pass it explicitly.
  • playAudio and transcription text frames and their play_audio / transcription events are gone. Servers sending them now hit the unknown-type branch.
  • start rejects sample rates above 64000 and a missing sample rate.

Validation

  • just test (compile against FreeSWITCH 1.11.3 / libwebsockets 5.0.0 headers in Docker, plus unit tests): passes, including the new saturating-add tests.
  • Not done: no live-call run, no ThreadSanitizer run, and the AVX2 path is not built by the test targets.

Still open (see issues/review-findings.md): module unload with calls in progress does not close live pipes; first text fragment size is not bounded by the receive limit; findAndRemovePendingConnect can drop pipes that have not started connecting.

Note

This was created entirely with AI assistance.

pragmatrix and others added 30 commits October 8, 2026 16:05
… resample overflow, null logs

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…p playAudio and transcription

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…y start failures

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… drop unused private_t fields

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…yed back

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…to the frame

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…clangd and IntelliSense config

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…utdown read the pipe handle

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… reading a NULL argv

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… issue

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…callers, check read_impl status

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@pragmatrix
pragmatrix marked this pull request as draft October 8, 2026 19:06
pragmatrix and others added 2 commits October 8, 2026 21:15
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…watch, note the receive buffer and event subclass findings

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
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