Skip to content

fix: segment time units, params pointer lifetimes, getter bounds checks - #14

Merged
rmorse merged 1 commit into
developfrom
fix/core-soundness
Sep 24, 2026
Merged

rmorse merged 1 commit into
developfrom
fix/core-soundness

Conversation

@rmorse

@rmorse rmorse commented Sep 24, 2026 •

Copy link
Copy Markdown
Member

Summary

Fixes existing bugs found while reviewing the crate for the whisper.cpp 1.9 upgrade.

  • Segment times are now milliseconds (breaking). whisper.cpp reports segment times in centiseconds; full_get_segment_timestamps() passed them through, so Segment::start_ms/end_ms, start_seconds()/end_seconds() and WhisperStreamPcm::run callback times were 10x too small. Fixed at the single conversion point, which covers transcribe*, WhisperStream, WhisperStreamPcm and the fallback transcriber.
  • Use-after-free in FullParams::suppress_regex(). The CString was dropped at the end of the setter while whisper.cpp kept the pointer.
  • Dangling FullParams::prompt_tokens(). It stored a borrowed slice pointer in a Clone + Send + Sync struct. Tokens are now copied.
  • Unchecked getter indices (breaking). whisper.cpp's result getters don't bounds-check, so out-of-range indices were UB from safe code. Result/Option getters now return Err/None; plain-value getters panic like slice indexing (documented under # Panics).
  • Added WhisperState::full_get_segment_no_speech_prob(), replacing a raw FFI call in the fallback transcriber.

The language/initial_prompt setters no longer write pointers into the inner struct either; as_raw() is the single place pointers are wired up, and it is the only path params take to C.

Notes

Validation

Windows / MSVC, test models from cargo xtask test-setup:

  • cargo fmt --all -- --check
  • cargo clippy --workspace --all-targets -- -D warnings
  • cargo clippy -p whisper-cpp-plus --all-targets --features async -- -D warnings
  • cargo test --workspace -- --test-threads=1: 124 passed, none skipped
  • cargo test -p whisper-cpp-plus --features async -- --test-threads=1: 112 passed
  • cargo doc -p whisper-cpp-plus --no-deps: no warnings

New tests:

  • params unit tests: string params and prompt tokens stay valid after the original params are cloned and dropped; None/empty map to null.
  • real_audio: jfk.wav's last segment ends near the audio length in ms (the old code gave ~1/10th); every getter rejects out-of-range indices with Err/None/panic.

- Segment timestamps are now milliseconds. whisper.cpp reports centiseconds;
  full_get_segment_timestamps passed them through, so Segment::start_ms/end_ms,
  start_seconds()/end_seconds() and stream callback times were 10x too small.
- FullParams owns suppress_regex and prompt_tokens and wires them up in
  as_raw(). suppress_regex previously pointed at a freed CString, and
  prompt_tokens at a borrowed slice that dangled after move/clone.
- WhisperState result getters validate segment/token indices before calling
  whisper.cpp, which does not bounds-check. Result/Option getters return
  Err/None; plain-value getters panic like slice indexing.
- Expose WhisperState::full_get_segment_no_speech_prob() and use it in the
  temperature-fallback transcriber instead of a raw FFI call.
@rmorse
rmorse changed the base branch from chore/whisper-cpp-1.9 to develop September 24, 2026 18:43
@rmorse

rmorse commented Sep 24, 2026

Copy link
Copy Markdown
Member Author

Closing and reopening to trigger CI after retargeting to develop.

@rmorse rmorse closed this Sep 24, 2026
@rmorse rmorse reopened this Sep 24, 2026
@rmorse
rmorse merged commit aac2d4c into develop Sep 24, 2026
2 checks passed
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