Added new AudioProcessing fuzzer

This is a high-level fuzzer that creates an AudioProcessing instance.
All possible combinations of publicly visible components are
fuzzed. Input and output sample rate, call order and use of the
float/fix interface is fuzzed. Sample rate may change between calls.

To fuzz floating point numbers, raw data is converted to floats, and
filtered for special values like 'inf', 'nan' and very large
values. Note that the default use case of APM is to only allow values
between +/- 2^15.

BUG=webrtc:7820

Review-Url: https://codereview.webrtc.org/2876793002
Cr-Commit-Position: refs/heads/master@{#18678}
This commit is contained in:
aleloi 2017-06-20 05:26:55 -07:00 committed by Commit Bot
parent be45757028
commit 8c51282f7f
4 changed files with 267 additions and 0 deletions

View File

@ -358,3 +358,16 @@ webrtc_fuzzer_test("transport_feedback_packet_loss_tracker_fuzzer") {
"../../voice_engine",
]
}
webrtc_fuzzer_test("audio_processing_fuzzer") {
sources = [
"audio_processing_fuzzer.cc",
"audio_processing_fuzzer.h",
"audio_processing_fuzzer_configs.cc",
]
deps = [
"../../base:rtc_base_approved",
"../../modules:module_api",
"../../modules/audio_processing",
]
}

View File

@ -0,0 +1,157 @@
/*
* Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/test/fuzzers/audio_processing_fuzzer.h"
#include <algorithm>
#include <array>
#include <cmath>
#include "webrtc/base/checks.h"
#include "webrtc/modules/audio_processing/include/audio_processing.h"
#include "webrtc/modules/include/module_common_types.h"
namespace webrtc {
namespace {
size_t ByteToNativeRate(uint8_t data) {
using Rate = AudioProcessing::NativeRate;
switch (data % 4) {
case 0:
// Breaks AEC3.
// return static_cast<size_t>(Rate::kSampleRate8kHz);
case 1:
return static_cast<size_t>(Rate::kSampleRate16kHz);
case 2:
return static_cast<size_t>(Rate::kSampleRate32kHz);
default:
return static_cast<size_t>(Rate::kSampleRate48kHz);
}
}
template <class T>
bool ParseSequence(size_t size,
const uint8_t** data,
size_t* remaining_size,
T* result_data) {
const size_t data_size_bytes = sizeof(T) * size;
if (data_size_bytes > *remaining_size) {
return false;
}
std::copy(*data, *data + data_size_bytes,
reinterpret_cast<uint8_t*>(result_data));
*data += data_size_bytes;
*remaining_size -= data_size_bytes;
return true;
}
void FuzzAudioProcessing(const uint8_t* data,
size_t size,
bool is_float,
AudioProcessing* apm) {
AudioFrame fixed_frame;
std::array<float, 480> float_frame;
float* const first_channel = &float_frame[0];
while (size > 0) {
// Decide input/output rate for this iteration.
const auto input_rate_byte = ParseByte(&data, &size);
const auto output_rate_byte = ParseByte(&data, &size);
if (!input_rate_byte || !output_rate_byte) {
return;
}
const auto input_rate_hz = ByteToNativeRate(*input_rate_byte);
const auto output_rate_hz = ByteToNativeRate(*output_rate_byte);
const size_t samples_per_input_channel =
rtc::CheckedDivExact(input_rate_hz, 100ul);
fixed_frame.samples_per_channel_ = samples_per_input_channel;
fixed_frame.sample_rate_hz_ = input_rate_hz;
// Two channels breaks AEC3.
fixed_frame.num_channels_ = 1;
// Fill the arrays with audio samples from the data.
if (is_float) {
if (!ParseSequence(samples_per_input_channel, &data, &size,
&float_frame[0])) {
return;
}
} else if (!ParseSequence(samples_per_input_channel, &data, &size,
fixed_frame.mutable_data())) {
return;
}
// Filter obviously wrong values like inf/nan and values that will
// lead to inf/nan in calculations. 1e6 leads to DCHECKS failing.
for (auto& x : float_frame) {
if (!std::isnormal(x) || std::abs(x) > 1e5) {
x = 0;
}
}
// Make the APM call depending on capture/render mode and float /
// fix interface.
const auto is_capture = ParseBool(&data, &size);
if (!is_capture) {
return;
}
if (*is_capture) {
auto apm_return_code =
is_float ? (apm->ProcessStream(
&first_channel, StreamConfig(input_rate_hz, 1),
StreamConfig(output_rate_hz, 1), &first_channel))
: (apm->ProcessStream(&fixed_frame));
RTC_DCHECK_NE(apm_return_code, AudioProcessing::kBadDataLengthError);
} else {
auto apm_return_code =
is_float ? (apm->ProcessReverseStream(
&first_channel, StreamConfig(input_rate_hz, 1),
StreamConfig(output_rate_hz, 1), &first_channel))
: (apm->ProcessReverseStream(&fixed_frame));
RTC_DCHECK_NE(apm_return_code, AudioProcessing::kBadDataLengthError);
}
}
}
} // namespace
rtc::Optional<bool> ParseBool(const uint8_t** data, size_t* remaining_size) {
if (1 > *remaining_size) {
return rtc::Optional<bool>();
}
auto res = rtc::Optional<bool>((**data) % 2);
*data += 1;
*remaining_size -= 1;
return res;
}
rtc::Optional<uint8_t> ParseByte(const uint8_t** data, size_t* remaining_size) {
if (1 > *remaining_size) {
return rtc::Optional<uint8_t>();
}
auto res = rtc::Optional<uint8_t>((**data));
*data += 1;
*remaining_size -= 1;
return res;
}
void FuzzAudioProcessing(const uint8_t* data,
size_t size,
std::unique_ptr<AudioProcessing> apm) {
const auto is_float = ParseBool(&data, &size);
if (!is_float) {
return;
}
FuzzAudioProcessing(data, size, *is_float, apm.get());
}
} // namespace webrtc

View File

@ -0,0 +1,27 @@
/*
* Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_TEST_FUZZERS_AUDIO_PROCESSING_FUZZER_H_
#define WEBRTC_TEST_FUZZERS_AUDIO_PROCESSING_FUZZER_H_
#include <memory>
#include "webrtc/modules/audio_processing/include/audio_processing.h"
namespace webrtc {
rtc::Optional<bool> ParseBool(const uint8_t** data, size_t* remaining_size);
rtc::Optional<uint8_t> ParseByte(const uint8_t** data, size_t* remaining_size);
void FuzzAudioProcessing(const uint8_t* data,
size_t size,
std::unique_ptr<AudioProcessing> apm);
} // namespace webrtc
#endif // WEBRTC_TEST_FUZZERS_AUDIO_PROCESSING_FUZZER_H_

View File

@ -0,0 +1,70 @@
/*
* Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/modules/audio_processing/include/audio_processing.h"
#include "webrtc/test/fuzzers/audio_processing_fuzzer.h"
#include "webrtc/base/optional.h"
namespace webrtc {
std::unique_ptr<AudioProcessing> CreateAPM(const uint8_t** data,
size_t* remaining_size) {
// Parse boolean values for optionally enabling different
// configurable public components of APM.
auto exp_agc = ParseBool(data, remaining_size);
auto exp_ns = ParseBool(data, remaining_size);
auto bf = ParseBool(data, remaining_size);
auto ef = ParseBool(data, remaining_size);
auto raf = ParseBool(data, remaining_size);
auto da = ParseBool(data, remaining_size);
auto ie = ParseBool(data, remaining_size);
auto red = ParseBool(data, remaining_size);
auto lc = ParseBool(data, remaining_size);
auto hpf = ParseBool(data, remaining_size);
auto aec3 = ParseBool(data, remaining_size);
if (!(exp_agc && exp_ns && bf && ef && raf && da && ie && red && lc && hpf &&
aec3)) {
return nullptr;
}
// Components can be enabled through webrtc::Config and
// webrtc::AudioProcessingConfig.
Config config;
config.Set<ExperimentalAgc>(new ExperimentalAgc(*exp_agc));
config.Set<ExperimentalNs>(new ExperimentalNs(*exp_ns));
if (*bf) {
config.Set<Beamforming>(new Beamforming());
}
config.Set<ExtendedFilter>(new ExtendedFilter(*ef));
config.Set<RefinedAdaptiveFilter>(new RefinedAdaptiveFilter(*raf));
config.Set<DelayAgnostic>(new DelayAgnostic(*da));
config.Set<Intelligibility>(new Intelligibility(*ie));
std::unique_ptr<AudioProcessing> apm(AudioProcessing::Create(config));
webrtc::AudioProcessing::Config apm_config;
apm_config.residual_echo_detector.enabled = *red;
apm_config.level_controller.enabled = *lc;
apm_config.high_pass_filter.enabled = *hpf;
apm_config.echo_canceller3.enabled = *aec3;
apm->ApplyConfig(apm_config);
return apm;
}
void FuzzOneInput(const uint8_t* data, size_t size) {
auto apm = CreateAPM(&data, &size);
FuzzAudioProcessing(data, size, std::move(apm));
}
} // namespace webrtc