0

audio: Fix crash in the flac fuzzer test

When pushing decoded samples into `fifo_`, the fuzzer test will get a
crash as in the reported link in chromium. When the client get the error
from the errorcallback, we will stop the decode process. Also, the
single decode process will be called only when the `fifo_` is empty.

BUG=chromium:1465739, b/293889978

Test: Manual
Change-Id: I5da73421ae2e0d6889a2c7c2fb8c078d375fdb9e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4735554
Commit-Queue: Hongyu Long <hongyulong@chromium.org>
Reviewed-by: Dale Curtis <dalecurtis@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1181664}
This commit is contained in:
Hongyu Long
2023-08-09 20:18:50 +00:00
committed by Chromium LUCI CQ
parent 516f322ba7
commit c67d4c5ed5
2 changed files with 33 additions and 10 deletions

@ -70,7 +70,8 @@ bool FlacAudioHandler::AtEnd() const {
auto state = FLAC__stream_decoder_get_state(decoder_.get());
return state ==
FLAC__StreamDecoderState::FLAC__STREAM_DECODER_END_OF_STREAM ||
state == FLAC__StreamDecoderState::FLAC__STREAM_DECODER_ABORTED;
state == FLAC__StreamDecoderState::FLAC__STREAM_DECODER_ABORTED ||
has_error_;
}
bool FlacAudioHandler::CopyTo(AudioBus* bus, size_t* frames_written) {
@ -86,17 +87,25 @@ bool FlacAudioHandler::CopyTo(AudioBus* bus, size_t* frames_written) {
DCHECK_EQ(bus->frames(), kDefaultFrameCount);
DCHECK_EQ(bus->channels(), num_channels_);
while (!AtEnd() && fifo_->frames() < bus->frames()) {
if (!FLAC__stream_decoder_process_single(decoder_.get())) {
return false;
// Records the number of frames copied into `bus`.
int frames_copied = 0;
do {
if (fifo_->frames() == 0 && !AtEnd()) {
if (!FLAC__stream_decoder_process_single(decoder_.get())) {
return false;
}
}
}
const int frames = std::min(bus->frames(), fifo_->frames());
fifo_->Consume(/*destination=*/bus, /*start_frame=*/0,
/*frames_to_consume=*/frames);
if (fifo_->frames() > 0) {
const int frames =
std::min(bus->frames() - frames_copied, fifo_->frames());
fifo_->Consume(bus, frames_copied, frames);
frames_copied += frames;
}
} while (!AtEnd() && frames_copied < bus->frames());
*frames_written = frames;
*frames_written = frames_copied;
return true;
}
@ -106,6 +115,7 @@ void FlacAudioHandler::Reset() {
fifo_->Clear();
}
cursor_ = 0;
has_error_ = false;
}
FLAC__StreamDecoderReadStatus FlacAudioHandler::ReadCallback(
@ -138,6 +148,7 @@ void FlacAudioHandler::ErrorCallback(const FLAC__StreamDecoder* decoder,
void* client_data) {
LOG(ERROR) << "Got an error callback: "
<< FLAC__StreamDecoderErrorStatusString[status];
reinterpret_cast<FlacAudioHandler*>(client_data)->ErrorCallbackInternal();
}
FLAC__StreamDecoderReadStatus FlacAudioHandler::ReadCallbackInternal(
@ -168,6 +179,10 @@ FLAC__StreamDecoderReadStatus FlacAudioHandler::ReadCallbackInternal(
FLAC__StreamDecoderWriteStatus FlacAudioHandler::WriteCallbackInternal(
const FLAC__Frame* frame,
const FLAC__int32* const buffer[]) {
if (has_error_) {
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
}
// Get the number of channels and the number of samples per channel.
const int num_channels = frame->header.channels;
const int num_samples = frame->header.blocksize;
@ -180,7 +195,7 @@ FLAC__StreamDecoderWriteStatus FlacAudioHandler::WriteCallbackInternal(
// Discard the packet if there are more than the number of `max_blocksize`
// frames.
if (num_samples > bus_->frames()) {
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
}
for (int ch = 0; ch < num_channels; ++ch) {
@ -248,6 +263,10 @@ void FlacAudioHandler::MetaCallbackInternal(
bus_ = AudioBus::Create(num_channels_, max_blocksize);
}
void FlacAudioHandler::ErrorCallbackInternal() {
has_error_ = true;
}
bool FlacAudioHandler::AreParamsValid() const {
return (num_channels_ > 0 &&
num_channels_ <= static_cast<int>(limits::kMaxChannels)) &&

@ -72,6 +72,7 @@ class MEDIA_EXPORT FlacAudioHandler : public AudioHandler {
const FLAC__Frame* frame,
const FLAC__int32* const buffer[]);
void MetaCallbackInternal(const FLAC__StreamMetadata* metadata);
void ErrorCallbackInternal();
// Check if the metadata fecthed in `MetaCallback()` is valid or not. This
// function will check the `num_channels_`, `bits_per_sample_`, `sample_rate_`
@ -97,6 +98,9 @@ class MEDIA_EXPORT FlacAudioHandler : public AudioHandler {
// Equal to the total number of samples per channel.
uint64_t total_frames_ = 0u;
// Set to true if the error callback is called.
bool has_error_ = false;
};
} // namespace media