whisper : default-initialize whisper_mel to avoid uninitialized read - #3981
Merged
Conversation
ousamabenyounes
force-pushed
the
fix/issue-3978
branch
2 times, most recently
from
August 16, 2026 16:51
03932d9 to
30e5495
Compare
danbev
reviewed
Aug 24, 2026
ousamabenyounes
force-pushed
the
fix/issue-3978
branch
from
August 24, 2026 21:20
30e5495 to
e59025e
Compare
Contributor
Author
|
Removed the verbose comments as requested. The zero-samples test still passes. |
Member
|
@ousamabenyounes Thanks! Can you take a look at the conflict? |
ousamabenyounes
force-pushed
the
fix/issue-3978
branch
from
August 27, 2026 18:06
e59025e to
ebca3ec
Compare
whisper_full()/whisper_full_with_state() only compute the mel spectrogram when n_samples > 0. For n_samples == 0 on a freshly allocated state the mel is never touched, but struct whisper_mel had no member initializers, so n_len / n_len_org / n_mel were indeterminate heap garbage (the state is allocated with new whisper_state). seek_end is derived from that garbage and, depending on it, the call either quietly returns 0 or runs the encoder with garbage dimensions over an empty (NULL) mel buffer, dereferencing address 0 in the mel copy loop. Give whisper_mel default member initializers so a never-computed mel reads as 0 frames and the n_samples == 0 case deterministically takes the existing too-short path. Fixes ggml-org#3978
ousamabenyounes
force-pushed
the
fix/issue-3978
branch
from
August 30, 2026 13:11
ebca3ec to
02c45f5
Compare
Contributor
Author
|
@danbev Rebased onto the latest Locally, |
danbev
approved these changes
Aug 31, 2026
bygreencn
added a commit
to bygreencn/whisper.cpp
that referenced
this pull request
Sep 3, 2026
* ggerganov/master: (144 commits) whisper : default-initialize whisper_mel to avoid uninitialized read (ggml-org#3981) parakeet : fix TDT decode by outputting raw logits from the joint graph (ggml-org#4017) talk-llama : sync llama.cpp pi : init sync : ggml ggml : bump version to 0.22.0 (ggml/1607) sycl : mark tq2_0 as not supported (llama/27660) webgpu : fix handling of infinity values during ARGSORT and TOP_K (llama/27538) metal : per-device tuned (Q, NE) for flash-attn vec (llama/26570) sync : ggml metal: per-op source split + parallel compile (llama/26561) scripts : update ggml-am sync : ggml ggml : shorten virtual device naming in CUDA and Metal (llama/27608) webgpu : reorder includes since V that appears in common_decls.tmpl may be defined as K in flash_attn_decls.tmpl if KV_OVERLAP (llama/27545) ggml : fix ggml_clamp (llama/27644) Deepseek 4: `-sm tensor` (llama/26490) Fix meta tensor split state propagation (llama/27574) cuda : add POOL_1D support (llama/27573) vulkan : added the PAD_REFLECT_1D operation (llama/26586) ...
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.
What
whisper_full()/whisper_full_with_state()called withn_samples == 0on afreshly allocated state can dereference a NULL mel buffer inside the encoder, or
silently return 0 — the outcome depends on heap garbage, so the crash is
intermittent.
Give
struct whisper_meldefault member initializers so a never-computed melreads as "0 frames".
Why
The mel spectrogram is only computed when there is audio:
if (n_samples > 0) { ... whisper_pcm_to_mel_with_state(...) }. Forn_samples == 0the mel is never touched. Butwhisper_melhad no memberinitializers, and the state is allocated with
new whisper_state, somel.n_len / n_len_org / n_melwere indeterminate heap garbage whilemel.datais a correctly-constructed empty vector (NULL data pointer).
seek_endis derived frommel.n_len_org. If the garbage lands below thedelta_minguard the call quietly returns 0; otherwise decoding proceeds andwhisper_encode_internalcopies the mel with garbage dimensions from the empty(NULL) buffer → read at address 0. The zero-sample input is reachable from real
use (a push-to-talk recording stopped before the first capture buffer yields a
valid-header, zero-frame WAV).
With the fields default-initialized to 0,
n_samples == 0deterministicallytakes the existing "input too short" path and returns 0 segments. The two code
paths that legitimately set a mel (
log_mel_spectrogram,whisper_set_mel_with_state) overwrite all three fields before any read, so thedefaults are observable only on the never-computed mel — the bug case.
Test verification (RED → GREEN)
Added
tests/test-whisper-zero-samples.cpp: loadfor-tests-ggml-tiny.bin, callwhisper_full(ctx, params, nullptr, 0), assertrc == 0andn_segments == 0.Because the read is of uninitialized memory, the deterministic RED is shown with
valgrind on the unpatched struct (only the production change reverted, the new
test applied):
RED (upstream base —
whisper_melwithout initializers):GREEN (with the fix):
Normal (non-valgrind) run of the new test plus the existing
whisper-clitinytest both pass.
Fixes #3978