Conversation
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Introduces the initial whispercpp safe wrapper crate and the whispercpp-sys FFI crate, wiring in a vendored/patch-verified whisper.cpp build, exception-catching shims, and a documented safe API surface.
Changes:
- Added safe Rust API (
Context,State,Params,Lang,WhisperError) plus an example smoke binary. - Added
whispercpp-sysbuild.rs to cmake-build a vendored whisper.cpp submodule, build an exception-catching shim, and generate bindgen output intoOUT_DIR. - Restructured the repo into a workspace; updated README/CI and removed template scaffolding.
Reviewed changes
Copilot reviewed 35 out of 36 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| whispercpp/src/sys.rs | Re-exports the raw whispercpp-sys bindings under whispercpp::sys. |
| whispercpp/src/state.rs | Adds State, segment/token accessors, and full() inference logic with poisoning semantics. |
| whispercpp/src/params.rs | Adds Params builder with owned C strings, clamps, abort callback trampoline, and unit tests. |
| whispercpp/src/lib.rs | Defines crate module layout and public re-exports. |
| whispercpp/src/lang.rs | Adds typed Lang enum with optional serde wire format and tests. |
| whispercpp/src/error.rs | Adds WhisperError and WhisperResult definitions. |
| whispercpp/src/context.rs | Adds Context loader/state creation, poisoning model, locks, and system_info caching. |
| whispercpp/examples/smoke.rs | Adds an end-to-end smoke example reading WAV and printing segments. |
| whispercpp/TODO.md | Documents intentionally-unsupported whisper.cpp surface and audit policy. |
| whispercpp/README.md | Points crate readme to workspace README. |
| whispercpp/Cargo.toml | Defines whispercpp crate metadata, features, deps, and example. |
| whispercpp/.gitignore | Ignores per-crate target/. |
| whispercpp-sys/wrapper.h | Bindgen entry point including whisper.h and shim header. |
| whispercpp-sys/whispercpp_shim.h | Declares C-ABI exception-catching shim API + sentinel codes. |
| whispercpp-sys/whispercpp_shim.cpp | Implements the exception-catching shims and TLS sentinel. |
| whispercpp-sys/whisper.cpp | Adds the whisper.cpp submodule pin reference. |
| whispercpp-sys/src/lib.rs | Exposes generated bindings via include!(OUT_DIR/generated.rs). |
| whispercpp-sys/build.rs | CMake-builds bundled whisper.cpp, verifies patch markers, builds shim, runs bindgen. |
| whispercpp-sys/README.md | Points sys crate readme to workspace README. |
| whispercpp-sys/Cargo.toml | Defines sys crate features and build dependencies (cmake/bindgen/cc). |
| whispercpp-sys/.gitignore | Ignores sys crate target/. |
| tests/foo.rs | Removes template test placeholder. |
| src/lib.rs | Removes template root crate lib. |
| examples/foo.rs | Removes template example placeholder. |
| ci/sanitizer.sh | Removes template sanitizer script. |
| ci/miri_tb.sh | Removes template miri script. |
| ci/miri_sb.sh | Removes template miri script. |
| benches/foo.rs | Removes template benchmark placeholder. |
| README.md | Replaces template README with whispercpp docs (features/backends/safety). |
| README-zh_CN.md | Removes template Chinese README. |
| Cargo.toml | Converts repo into a workspace with shared package metadata/lints. |
| CHANGELOG.md | Removes template changelog placeholder. |
| .gitmodules | Adds whisper.cpp submodule pointing at the fork rust branch. |
| .github/workflows/loc.yml | Updates LoC gist key to whispercpp. |
| .github/workflows/ci.yml | Replaces template CI with a matrix that builds bundled whisper.cpp, runs tests, sanitizer, and miri. |
Comments suppressed due to low confidence (5)
whispercpp/src/params.rs:1
owned.len() as i32can wrap/truncate for slices longer thani32::MAX, potentially passing a negative/garbledprompt_n_tokensinto whisper.cpp. Since whisper.cpp expects anint, this should be validated withi32::try_from(...)and handled explicitly (e.g., return aWhisperErrorvariant) before updatingraw.prompt_n_tokens.
whispercpp/src/params.rs:1- This
expect(...)introduces a panic in a public setter in a module that otherwise aims to be panic-free. You can avoid the unwrap entirely by computinguser_datafrom the newly-createdouterbefore it is moved intoself._abort_callback(the heap address is already stable), then storeouterand publish the raw fields.
whispercpp/src/params.rs:1 - The doc comment doesn't match the actual storage type (
AbortCallback = Box<UnsafeCell<Box<dyn FnMut() -> bool>>>). Please update the docs to reflect the real layout (including theUnsafeCell) since the safety argument depends on it.
whispercpp/src/state.rs:1 - This doc comment contains several grammatical fragments (e.g., "surfaced the original" mid-sentence) and placeholder artifacts (e.g., "'s"). Since this is safety-critical documentation explaining poisoning/double-free behavior, it should be cleaned up to be fully readable and unambiguous.
whispercpp/src/params.rs:1 - The name
MAX_INITIAL_TS_Ssuggests seconds, but the docs describe a frame/token index limit (1500 frames = 30s). If whisper.cpp interpretsmax_initial_tsas seconds (common in its CLI/API), clamping to1500.0seconds is far beyond the 30s chunk width and may interact badly with downstream timestamp/token logic. Please confirm the unit expected by whisper.cpp and either (a) change the constant to30.0seconds, or (b) rename/re-document the constant and setter to make it explicit that the value is an index (not seconds), and ensure the conversion logic matches upstream expectations.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+1
to
+4
| [package] | ||
| name = "whispercpp" | ||
| version = "0.0.1" | ||
| edition.workspace = true |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 35 out of 36 changed files in this pull request and generated 6 comments.
Comments suppressed due to low confidence (2)
whispercpp/src/sys.rs:1
- This module doc claims a
pkg-config/system-install path exists whenbundledis off, but the PR description and thewhispercpp-sysbuild script/documentation state there is no system/pkg-config path (bundled-only to preserve patch-dependent safety). Update this docstring to match the actual build contract to avoid misleading API consumers.
whispercpp/src/params.rs:1 - There are multiple leftover placeholder fragments like
Codexand broken punctuation in public-facing docs/comments. These reduce readability and make the safety rationale harder to audit; please remove the placeholders and repair the sentences (same issue appears in other modules too).
| bash ci/miri_sb.sh "${{ matrix.target }}" | ||
| submodules: recursive | ||
| - run: rustup update stable && rustup default stable | ||
| - run: cargo doc --workspace --no-deps --features whispercpp/serde |
Initial release of `whispercpp` and `whispercpp-sys`: - `whispercpp` — safe API: `Context`, `State`, `Params`, `Lang`, `WhisperError`. Panic-free setters; FFI throws contained behind a C++ exception-catching shim. `Send + Sync` `Context`, per-`Context` `Mutex` serializing concurrent inference. - `whispercpp-sys` — bindgen output + `build.rs` that cmake-builds a vendored, patched whisper.cpp submodule. Submodule pinned to the `Findit-AI/whisper.cpp@rust` fork branch; `build.rs` carries a build-time canary that hard-fails if required patch markers are missing from the linked source. Memory-safety patches on the fork's `rust` branch close upstream hazards reachable from safe Rust: - `whisper_kv_cache_free` made idempotent (closes a multi-decoder OOM double-free of a ggml backend buffer). - RAII guards around `whisper_init_state`, `whisper_init_with_params_no_state`, `whisper_vad_init_with_params` so a throw mid-init releases the partial allocation. - Tensor headers fully validated: `n_dims ∈ [0, 4]`, name length bounded, `ttype < GGML_TYPE_COUNT`, per-dim positivity, 64-bit overflow check on `nelements`. - Hparams validated against bounded ranges; min `n_text_ctx = 64` so the decode batch can hold the worst-case prompt. - Special-token ids verified to fit `n_vocab` after the multilingual shift. - File / buffer loaders throw on partial reads; peek-based EOF. - Tensor-name set tracking rejects models that satisfy the loaded-count check by repeating one name. - `ggml_log_set` installed once per process via `std::atomic` — closes a race between concurrent `create_state` and `State::full`. - `vocab.num_languages()` synthesis null-checks `whisper_lang_str`. - Abort callback wired through every sched-based graph compute. - `whisper_batch` default member initializers + OOM-safe alloc chain in `whisper_batch_init`. - `path_model` assignment guarded so a `std::string` OOM at the tail of `Context::new` doesn't leak the model. - `whisper_kv_cache_init` frees its `ggml_context` on alloc failure. CI gates: - `rustfmt`, `clippy --workspace --all-targets -- -D warnings` - `build-bundled` on ubuntu-latest / macos-latest / windows-latest - `build-macos-gpu` (Metal + CoreML) - `test --lib` on Linux + macOS - `sanitizer (asan)` on x86_64-linux - `sanitizer (asan, aarch64-linux)` on ubuntu-24.04-arm - `ubsan (C++ side)` against `-fsanitize=undefined` - `miri --strict-provenance` against the safe-wrapper crate's tests; FFI-touching tests gated via `#[cfg_attr(miri, ignore)]` - `doc` — rustdoc with `-Dwarnings`
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Initial release of
whispercppandwhispercpp-sys: safe Rust bindings for whisper.cpp speech-to-text inference.whispercpp— safe API:Context,State,Params,Lang,WhisperError. Panic-free setters; FFI throws contained behind a C++ exception-catching shim.whispercpp-sys— bindgen output +build.rsthat cmake-builds a vendored, patched whisper.cpp submodule. No pkg-config / system path; the Rust safety surface depends on patches that only the bundled build supplies.Highlights
Findit-AI/whisper.cpp@rust, a fork branch that carries each memory-safety fix as a reviewable commit on top ofv1.8.4.Send + SyncContext, per-ContextStateisSend. Concurrent inference is serialised through a per-Contextmutex so the leak budget on caught-exception sentinels is structural, not documentary.whisper_*accessors are exposed; every throwing constructor / inference entry point routes through awhispercpp_*shim that catches and surfaces the exception class as a sentinel (WhisperError::ConstructorLost,StateLost, …).serdeforLang's ISO-639-1 wire format.build.rs::verify_patched_sourcescans the linked source for required patch markers and hard-fails the build if any are missing — catches submodule drift.Memory-safety fixes carried on the fork's
rustbranchwhisper_kv_cache_freemade idempotent (closes a multi-decoder OOM double-free of a ggml backend buffer).whisper_init_state,whisper_init_with_params_no_state,whisper_vad_init_with_paramsso a throw mid-init releases the partial allocation rather than leaking the whisper_context / whisper_state.n_dims ∈ [0, 4], name length bounded,ttype < GGML_TYPE_COUNT, per-dim positivity, 64-bit overflow check onnelements.n_text_ctx = 64so the decode batch can hold the worst-case prompt.n_vocabafter the multilingual shift (closes a corrupt-vocab OOB intologits[]).ggml_log_setinstalled once per process viastd::atomic— closes a race between concurrentcreate_stateandState::full.vocab.num_languages()synthesis null-checkswhisper_lang_str(closesstd::string(nullptr)UB).whisper_batchdefault member initializers +whisper_batch_initOOM-safe alloc chain.path_modelassignment guarded so astd::stringOOM at the tail ofContext::newdoesn't leak the model.whisper_kv_cache_initfrees itsggml_contexton alloc failure.CI
rustfmt,clippy --workspace --all-targets -- -D warningsbuild-bundledonubuntu-latest/macos-latest/windows-latestbuild-macos-gpu(Metal + CoreML)test --libon Linux + macOSsanitizer— Linux ASan + HWAddress sanitizer against the bundled FFI smoke test (nightly +-Zbuild-std)miri --strict-provenanceagainst the safe wrapper's tests; FFI-touching tests gated via#[cfg_attr(miri, ignore)]doc— rustdoc with-DwarningsTest plan
cargo clippy --workspace --all-targets -- -D warningscleancargo test -p whispercpp --features serde --lib(24/24)large-v3-turbo(1.6 GB) loads + transcribes a fixture wav correctlygit checkout v1.8.4+ rebuild)🤖 Generated with Claude Code