APM fuzzer: fuzz more sample rates, clean up input generation

APM has historically allowed sample rates not divisible by 100, but there is also code that explicitly states that such rates are not supported.
It is unclear how well rates like 22050 are handled in practice.
This CL adds support for fuzzing more sample rates, to help find issues.

We usually preserve fuzzer data reads to avoid invalidating unresolved fuzzer-found issues, but to make the code a little more readable this CL removes the discarded reads. This renders the only currently open bug non-reproducible, crbug.com/1299393.

Bug: webrtc:9413, chromium:1299393
Change-Id: I98ac1c653627c20adc73b8edede02f1526d80d9d
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/264504
Reviewed-by: Alessio Bazzica <alessiob@webrtc.org>
Commit-Queue: Sam Zackrisson <saza@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#37114}
This commit is contained in:
Sam Zackrisson 2022-05-31 15:03:28 +02:00 committed by WebRTC LUCI CQ
parent 099ff62d94
commit 306eee3d17
6 changed files with 17 additions and 33 deletions

View File

@ -40,27 +40,21 @@ rtc::scoped_refptr<AudioProcessing> CreateApm(test::FuzzDataHelper* fuzz_data,
rtc::TaskQueue* worker_queue) {
// Parse boolean values for optionally enabling different
// configurable public components of APM.
static_cast<void>(fuzz_data->ReadOrDefaultValue(true));
bool use_ts = fuzz_data->ReadOrDefaultValue(true);
static_cast<void>(fuzz_data->ReadOrDefaultValue(true));
static_cast<void>(fuzz_data->ReadOrDefaultValue(true));
static_cast<void>(fuzz_data->ReadOrDefaultValue(true));
bool use_red = fuzz_data->ReadOrDefaultValue(true);
bool use_hpf = fuzz_data->ReadOrDefaultValue(true);
bool use_aec3 = fuzz_data->ReadOrDefaultValue(true);
bool use_aec = fuzz_data->ReadOrDefaultValue(true);
bool use_aecm = fuzz_data->ReadOrDefaultValue(true);
bool use_agc = fuzz_data->ReadOrDefaultValue(true);
bool use_ns = fuzz_data->ReadOrDefaultValue(true);
static_cast<void>(fuzz_data->ReadOrDefaultValue(true));
static_cast<void>(fuzz_data->ReadOrDefaultValue(true));
bool use_agc_limiter = fuzz_data->ReadOrDefaultValue(true);
bool use_agc2 = fuzz_data->ReadOrDefaultValue(true);
bool use_agc2_adaptive_digital = fuzz_data->ReadOrDefaultValue(true);
// Read an int8 value, but don't let it be too large or small.
// Read a gain value supported by GainController2::Validate().
const float gain_controller2_gain_db =
rtc::SafeClamp<int>(fuzz_data->ReadOrDefaultValue<int8_t>(0), -40, 40);
fuzz_data->ReadOrDefaultValue<uint8_t>(0) % 50;
constexpr size_t kNumFieldTrials = arraysize(kFieldTrialNames);
// Verify that the read data type has enough bits to fuzz the field trials.
@ -76,10 +70,6 @@ rtc::scoped_refptr<AudioProcessing> CreateApm(test::FuzzDataHelper* fuzz_data,
}
field_trial::InitFieldTrialsFromString(field_trial_string->c_str());
bool use_agc2_adaptive_digital = fuzz_data->ReadOrDefaultValue(true);
static_cast<void>(fuzz_data->ReadOrDefaultValue(true));
static_cast<void>(fuzz_data->ReadOrDefaultValue(true));
// Ignore a few bytes. Bytes from this segment will be used for
// future config flag changes. We assume 40 bytes is enough for
// configuring the APM.

View File

@ -27,13 +27,12 @@ bool ValidForApm(float x) {
}
void GenerateFloatFrame(test::FuzzDataHelper* fuzz_data,
size_t input_rate,
size_t num_channels,
int input_rate,
int num_channels,
float* const* float_frames) {
const size_t samples_per_input_channel =
rtc::CheckedDivExact(input_rate, static_cast<size_t>(100));
const int samples_per_input_channel = input_rate / 100;
RTC_DCHECK_LE(samples_per_input_channel, 480);
for (size_t i = 0; i < num_channels; ++i) {
for (int i = 0; i < num_channels; ++i) {
std::fill(float_frames[i], float_frames[i] + samples_per_input_channel, 0);
const size_t read_bytes = sizeof(float) * samples_per_input_channel;
if (fuzz_data->CanReadBytes(read_bytes)) {
@ -43,7 +42,7 @@ void GenerateFloatFrame(test::FuzzDataHelper* fuzz_data,
}
// Sanitize input.
for (size_t j = 0; j < samples_per_input_channel; ++j) {
for (int j = 0; j < samples_per_input_channel; ++j) {
if (!ValidForApm(float_frames[i][j])) {
float_frames[i][j] = 0.f;
}
@ -52,18 +51,17 @@ void GenerateFloatFrame(test::FuzzDataHelper* fuzz_data,
}
void GenerateFixedFrame(test::FuzzDataHelper* fuzz_data,
size_t input_rate,
size_t num_channels,
int input_rate,
int num_channels,
AudioFrame* fixed_frame) {
const size_t samples_per_input_channel =
rtc::CheckedDivExact(input_rate, static_cast<size_t>(100));
const int samples_per_input_channel = input_rate / 100;
fixed_frame->samples_per_channel_ = samples_per_input_channel;
fixed_frame->sample_rate_hz_ = input_rate;
fixed_frame->num_channels_ = num_channels;
RTC_DCHECK_LE(samples_per_input_channel * num_channels,
AudioFrame::kMaxDataSizeSamples);
for (size_t i = 0; i < samples_per_input_channel * num_channels; ++i) {
for (int i = 0; i < samples_per_input_channel * num_channels; ++i) {
fixed_frame->mutable_data()[i] = fuzz_data->ReadOrDefaultValue<int16_t>(0);
}
}
@ -82,9 +80,8 @@ void FuzzAudioProcessing(test::FuzzDataHelper* fuzz_data,
}
float* const* ptr_to_float_frames = &float_frame_ptrs[0];
using Rate = AudioProcessing::NativeRate;
const Rate rate_kinds[] = {Rate::kSampleRate8kHz, Rate::kSampleRate16kHz,
Rate::kSampleRate32kHz, Rate::kSampleRate48kHz};
constexpr int kSampleRatesHz[] = {8000, 11025, 16000, 22050,
32000, 44100, 48000};
// We may run out of fuzz data in the middle of a loop iteration. In
// that case, default values will be used for the rest of that
@ -92,14 +89,11 @@ void FuzzAudioProcessing(test::FuzzDataHelper* fuzz_data,
while (fuzz_data->CanReadBytes(1)) {
const bool is_float = fuzz_data->ReadOrDefaultValue(true);
// Decide input/output rate for this iteration.
const auto input_rate =
static_cast<size_t>(fuzz_data->SelectOneOf(rate_kinds));
const auto output_rate =
static_cast<size_t>(fuzz_data->SelectOneOf(rate_kinds));
const int input_rate = fuzz_data->SelectOneOf(kSampleRatesHz);
const int output_rate = fuzz_data->SelectOneOf(kSampleRatesHz);
const uint8_t stream_delay = fuzz_data->ReadOrDefaultValue<uint8_t>(0);
// API call needed for AEC-2 and AEC-m to run.
// API call needed for AECM to run.
apm->set_stream_delay_ms(stream_delay);
const bool key_pressed = fuzz_data->ReadOrDefaultValue(true);