Skip to content

Fix NULL-stream crash and div-by-zero on malformed WAV channel count - #7

Open
austek wants to merge 1 commit into
espeak-ng:masterfrom
ZirekHQ:fix/cli-crash-bugs-espeak
Open

Fix NULL-stream crash and div-by-zero on malformed WAV channel count#7
austek wants to merge 1 commit into
espeak-ng:masterfrom
ZirekHQ:fix/cli-crash-bugs-espeak

Conversation

@austek

@austek austek commented Aug 23, 2026

Copy link
Copy Markdown

Summary

Same bugs, same fix as waywardgeek/sonic#69 — this repo's main.c/wave.c are byte-identical to what those files had upstream, so the fix ports directly.

  1. SEGV in sonicSetSpeed: sonicCreateStream is documented to "Return NULL only if we are out of memory," but main.c's runSonic never checked before immediately calling sonicSetSpeed(stream, ...), dereferencing a NULL stream. Fix: check for NULL after sonicCreateStream, matching the existing fprintf+exit(1) pattern already used for the file-open failure checks right above it.

  2. FPE in runSonic: BUFFER_SIZE / numChannels divides by whatever numChannels wave.c's readHeader read straight from the input file's header, with no validation — unlike the format and bit-depth fields, which are already rejected if invalid. A WAV file with numChannels=0 in its fmt chunk passes readHeader unmodified, then main.c's division raises SIGFPE. Fix: reject numChannels <= 0 in readHeader, the same way the existing format/bit-depth checks already reject other invalid header fields.

Adds tests/wave_channel_validation_test.c, wired into this fork's tests/Makefile (which now also links wave.c, needed by the new test).

Test plan

  • cd tests && make runtests && ./runtests — passes, new test included
  • Same build under -fsanitize=address,undefined — no finding from this path; only the separate, already-known findSincCoefficient left-shift issue remains
  • Built the real sonic CLI from this fork's code directly and reproduced both fixes end-to-end: the 0-channel WAV crashed with SIGFPE before the fix, exits cleanly with an error message after; normal usage unaffected

1. SEGV in sonicSetSpeed: sonicCreateStream is documented to "Return
   NULL only if we are out of memory," but main.c's runSonic never
   checked before immediately calling sonicSetSpeed(stream, ...),
   dereferencing a NULL stream. Fix: check for NULL after
   sonicCreateStream, matching the existing fprintf+exit(1) pattern
   already used for the file-open failure checks just above it.

2. FPE in runSonic (main.c:55): BUFFER_SIZE / numChannels divides by
   whatever numChannels wave.c's readHeader read straight from the
   input file's header, with no validation -- unlike the format and
   bit-depth fields, which are already rejected if invalid. A WAV file
   with numChannels=0 in its fmt chunk passes readHeader unmodified,
   then main.c's division by zero raises SIGFPE. Fix: reject
   numChannels <= 0 in readHeader, the same way the existing
   format/bit-depth checks already reject other invalid header
   fields.

Adds tests/wave_channel_validation_test.c, wired into this fork's
tests/Makefile (which also now links wave.c, needed by the new test).
Verified against the real sonic CLI built from this fork's code
directly: the 0-channel WAV crashes with SIGFPE before the fix, exits
cleanly with an error message after.

Ported from waywardgeek/sonic#69, which fixes the same bugs (also
present here, byte-identical main.c/wave.c) upstream.
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