diff --git a/src/audio/audio_utils.cpp b/src/audio/audio_utils.cpp index 5c0136c1a6..6caaafa245 100644 --- a/src/audio/audio_utils.cpp +++ b/src/audio/audio_utils.cpp @@ -105,12 +105,18 @@ std::vector readWav(const std::string_view& wavData, uint32_t targetSampl drwav_uninit(&wav); throw std::runtime_error("WAV file header claims more frames than possible from data chunk size"); } - // Validate decoded buffer size before resampling (float32 mono output) + // Validate decoded buffer size before any large allocations. + const uint64_t n = wav.totalPCMFrameCount; + size_t decodedSamples = static_cast(n); + if (decodedSamples > std::numeric_limits::max() / sizeof(float)) { + drwav_uninit(&wav); + throw std::overflow_error("Decoded audio buffer size overflow"); + } if (targetSampleRate > 0) { - validateAudioFileSize(wav.totalPCMFrameCount, wav.sampleRate, targetSampleRate, /*will be downmixed to mono*/ 1, sizeof(float)); + validateAudioFileSize(n, wav.sampleRate, targetSampleRate, /*will be downmixed to mono*/ 1, sizeof(float)); + } else { + validateAudioFileSizeAgainstMaxValue(decodedSamples * sizeof(float)); } - - const uint64_t n = wav.totalPCMFrameCount; std::vector pcm16; if (n > AUDIO_BUFFER_SIZE_LIMIT / wav.channels) { drwav_uninit(&wav); diff --git a/src/test/audio/audio_utils_test.cpp b/src/test/audio/audio_utils_test.cpp index ede322830d..d9a3200e84 100644 --- a/src/test/audio/audio_utils_test.cpp +++ b/src/test/audio/audio_utils_test.cpp @@ -160,6 +160,27 @@ TEST_F(AudioUtilsSampleRateTest, wavFileAcceptedWhenAtMaxFileSizeEnv) { UnSetEnvironmentVar("OVMS_AUDIO_MAX_FILE_SIZE_BYTES"); } +TEST_F(AudioUtilsSampleRateTest, readWithoutResampleWavRejectedWhenExceedsMaxFileSizeEnv) { + const std::string wav = buildWavBuffer(/*sampleRate=*/16000, /*numSamples=*/16); + std::string_view view(wav); + size_t expectedDecodedSize = static_cast(16 * sizeof(float)); + SetEnvironmentVar("OVMS_AUDIO_MAX_FILE_SIZE_BYTES", std::to_string(expectedDecodedSize - 1)); + EXPECT_THROW({ auto decoded = readWithoutResample(view, "wav"); }, std::runtime_error); + UnSetEnvironmentVar("OVMS_AUDIO_MAX_FILE_SIZE_BYTES"); +} + +TEST_F(AudioUtilsSampleRateTest, readWithoutResampleWavAcceptedWhenAtMaxFileSizeEnv) { + const std::string wav = buildWavBuffer(/*sampleRate=*/32000, /*numSamples=*/16); + std::string_view view(wav); + // Native-rate WAV decode keeps the full 16 float samples, or 64 bytes total. + size_t expectedDecodedSize = static_cast(16 * sizeof(float)); + SetEnvironmentVar("OVMS_AUDIO_MAX_FILE_SIZE_BYTES", std::to_string(expectedDecodedSize)); + std::vector decoded; + EXPECT_NO_THROW({ decoded = readWithoutResample(view, "wav"); }); + EXPECT_EQ(decoded.size(), 16u); + UnSetEnvironmentVar("OVMS_AUDIO_MAX_FILE_SIZE_BYTES"); +} + TEST_F(AudioUtilsSampleRateTest, mp3FileRejectedWhenExceedsMaxFileSizeEnv) { // Minimal valid MP3 frame (see previous test for structure) std::string mp3;