This commit is contained in:
he pang 2026-08-14 22:42:25 -04:00 committed by GitHub
commit 0a4dd57db3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 53 additions and 0 deletions

View File

@ -3195,6 +3195,14 @@ static bool log_mel_spectrogram(
int64_t stage_1_pad = WHISPER_SAMPLE_RATE * 30;
int64_t stage_2_pad = frame_size / 2;
// The reflective padding below reads samples[1 .. stage_2_pad], so an input
// shorter than stage_2_pad + 1 would read past the end of the buffer.
if (n_samples < stage_2_pad + 1) {
WHISPER_LOG_ERROR("%s: audio too short: %d samples, need at least %d\n",
__func__, n_samples, (int) stage_2_pad + 1);
return false;
}
// Initialize a vector and copy data from C array to it.
std::vector<float> samples_padded;
samples_padded.resize(n_samples + stage_1_pad + stage_2_pad * 2);

View File

@ -178,3 +178,13 @@ add_parakeet_transcription_test(
tests/parakeet-expected-diffusion-output.txt
0.95)
# log_mel_spectrogram out-of-bounds read on very short audio (issue #3923)
set(MEL_OOB_TEST test-log-mel-oob)
add_executable(${MEL_OOB_TEST} ${MEL_OOB_TEST}.cpp)
target_include_directories(${MEL_OOB_TEST} PRIVATE ../include ../ggml/include ../examples)
target_link_libraries(${MEL_OOB_TEST} PRIVATE common)
target_compile_definitions(${MEL_OOB_TEST} PRIVATE
WHISPER_MODEL_PATH="${PROJECT_SOURCE_DIR}/models/for-tests-ggml-tiny.bin")
add_test(NAME ${MEL_OOB_TEST} COMMAND ${MEL_OOB_TEST})
set_tests_properties(${MEL_OOB_TEST} PROPERTIES LABELS "unit;gh")

View File

@ -0,0 +1,35 @@
#include "whisper.h"
#include <string>
#include <vector>
#ifdef NDEBUG
#undef NDEBUG
#endif
#include <cassert>
// Regression test for the heap out-of-bounds read in log_mel_spectrogram().
// Reflective padding reads samples[1 .. WHISPER_N_FFT/2], so an input shorter
// than WHISPER_N_FFT/2 + 1 (201) samples used to read past the end of the
// caller's buffer. Such inputs must now be rejected with a non-zero return.
int main() {
std::string model_path = WHISPER_MODEL_PATH;
struct whisper_context_params cparams = whisper_context_default_params();
struct whisper_context * ctx = whisper_init_from_file_with_params(model_path.c_str(), cparams);
assert(ctx != nullptr);
std::vector<float> samples(256, 0.0f);
// Shorter than the reflective-pad window: must be rejected, not read OOB.
assert(whisper_pcm_to_mel(ctx, samples.data(), 4, 1) != 0);
assert(whisper_pcm_to_mel(ctx, samples.data(), 200, 1) != 0);
// Long enough to pad safely: must still succeed.
assert(whisper_pcm_to_mel(ctx, samples.data(), 201, 1) == 0);
whisper_free(ctx);
return 0;
}