]> git.djapps.eu Git - pkg/ggml/sources/whisper.cpp/commitdiff
whisper : heap out-of-bounds read in log_mel_spectrogram on very short audio (#3956)
authorMd Shafiuzzaman <redacted>
Fri, 7 Aug 2026 06:17:31 +0000 (23:17 -0700)
committerGitHub <redacted>
Fri, 7 Aug 2026 06:17:31 +0000 (08:17 +0200)
log_mel_spectrogram reflect-pads the start of the audio buffer by reading 200 samples from samples[1], with no check that the input has that many samples. Audio shorter than 201 samples reads past the end of `samples` (heap out-of-bounds read); the existing minimum-length check runs later, in whisper_full_with_state, after this access.

Clamp the reflected count to the available input. Normal-length audio (n_samples >= 201) is unchanged.

src/whisper.cpp

index 4ac3b1104f3f64b07f269b10673de9e903903af4..89146e2e4da7847f717700b550eaf8baf71f9d4e 100644 (file)
@@ -3203,8 +3203,12 @@ static bool log_mel_spectrogram(
     // pad 30 seconds of zeros at the end of audio (480,000 samples) + reflective pad 200 samples at the end of audio
     std::fill(samples_padded.begin() + n_samples + stage_2_pad, samples_padded.begin() + n_samples + stage_1_pad + 2 * stage_2_pad, 0);
 
-    // reflective pad 200 samples at the beginning of audio
-    std::reverse_copy(samples + 1, samples + 1 + stage_2_pad, samples_padded.begin());
+    // reflective pad up to 200 samples at the beginning of audio
+    // clamp the reflected count to the available input so very short audio (n_samples <= stage_2_pad)
+    // does not read past the end of `samples`
+    const int64_t n_reflect = std::min<int64_t>(stage_2_pad, std::max<int64_t>(0, (int64_t) n_samples - 1));
+    std::reverse_copy(samples + 1, samples + 1 + n_reflect, samples_padded.begin() + (stage_2_pad - n_reflect));
+
 
     mel.n_mel     = n_mel;
     // https://github.com/pytorch/pytorch/blob/main/aten/src/ATen/native/SpectralOps.cpp#L936