diff --git a/common_audio/signal_processing/filter_ar.c b/common_audio/signal_processing/filter_ar.c index 621fef5e40..49d5d61960 100644 --- a/common_audio/signal_processing/filter_ar.c +++ b/common_audio/signal_processing/filter_ar.c @@ -29,7 +29,7 @@ size_t WebRtcSpl_FilterAR(const int16_t* a, int16_t* filtered_low, size_t filtered_low_length) { - int32_t o; + int64_t o; int32_t oLOW; size_t i, j, stop; const int16_t* x_ptr = &x[0]; diff --git a/test/fuzzers/BUILD.gn b/test/fuzzers/BUILD.gn index f88b47deec..0aee276b76 100644 --- a/test/fuzzers/BUILD.gn +++ b/test/fuzzers/BUILD.gn @@ -328,12 +328,12 @@ webrtc_fuzzer_test("neteq_signal_fuzzer") { "neteq_signal_fuzzer.cc", ] deps = [ + ":fuzz_data_helper", "../../api:array_view", "../../modules/audio_coding:neteq", "../../modules/audio_coding:neteq_test_tools", "../../modules/audio_coding:neteq_tools_minimal", "../../modules/audio_coding:pcm16b", - "../../modules/rtp_rtcp:rtp_rtcp_format", "../../rtc_base:rtc_base_approved", "../../rtc_base:rtc_base_tests_utils", ] @@ -416,3 +416,27 @@ webrtc_fuzzer_test("audio_processing_fuzzer") { "../../rtc_base:rtc_base_approved", ] } + +webrtc_fuzzer_test("comfort_noise_decoder_fuzzer") { + sources = [ + "comfort_noise_decoder_fuzzer.cc", + ] + deps = [ + ":fuzz_data_helper", + "../../api:array_view", + "../../modules/audio_coding:cng", + "../../rtc_base:rtc_base_approved", + ] +} + +rtc_static_library("fuzz_data_helper") { + sources = [ + "fuzz_data_helper.cc", + "fuzz_data_helper.h", + ] + deps = [ + "../../api:array_view", + "../../modules/rtp_rtcp:rtp_rtcp_format", + ] + visibility = [ ":*" ] # Only targets in this file can depend on this. +} diff --git a/test/fuzzers/comfort_noise_decoder_fuzzer.cc b/test/fuzzers/comfort_noise_decoder_fuzzer.cc new file mode 100644 index 0000000000..3033f20842 --- /dev/null +++ b/test/fuzzers/comfort_noise_decoder_fuzzer.cc @@ -0,0 +1,53 @@ +/* + * 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 "api/array_view.h" +#include "modules/audio_coding/codecs/cng/webrtc_cng.h" +#include "rtc_base/buffer.h" +#include "test/fuzzers/fuzz_data_helper.h" + +namespace webrtc { +namespace test { +namespace { + +void FuzzOneInputTest(rtc::ArrayView data) { + FuzzDataHelper fuzz_data(data); + ComfortNoiseDecoder cng_decoder; + + while (1) { + if (!fuzz_data.CanReadBytes(1)) + break; + const uint8_t sid_frame_len = fuzz_data.Read(); + auto sid_frame = fuzz_data.ReadByteArray(sid_frame_len); + if (sid_frame.empty()) + break; + cng_decoder.UpdateSid(sid_frame); + if (!fuzz_data.CanReadBytes(3)) + break; + constexpr bool kTrueOrFalse[] = {true, false}; + const bool new_period = fuzz_data.SelectOneOf(kTrueOrFalse); + constexpr size_t kOutputSizes[] = {80, 160, 320, 480}; + const size_t output_size = fuzz_data.SelectOneOf(kOutputSizes); + const size_t num_generate_calls = fuzz_data.Read(); + rtc::BufferT output(output_size); + for (size_t i = 0; i < num_generate_calls; ++i) { + cng_decoder.Generate(output, new_period); + } + } +} + +} // namespace +} // namespace test + +void FuzzOneInput(const uint8_t* data, size_t size) { + test::FuzzOneInputTest(rtc::ArrayView(data, size)); +} + +} // namespace webrtc diff --git a/test/fuzzers/fuzz_data_helper.cc b/test/fuzzers/fuzz_data_helper.cc new file mode 100644 index 0000000000..866f7bc4b8 --- /dev/null +++ b/test/fuzzers/fuzz_data_helper.cc @@ -0,0 +1,20 @@ +/* + * 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 "test/fuzzers/fuzz_data_helper.h" + +namespace webrtc { +namespace test { + +FuzzDataHelper::FuzzDataHelper(rtc::ArrayView data) + : data_(data) {} + +} // namespace test +} // namespace webrtc diff --git a/test/fuzzers/fuzz_data_helper.h b/test/fuzzers/fuzz_data_helper.h new file mode 100644 index 0000000000..fb64bfe4ff --- /dev/null +++ b/test/fuzzers/fuzz_data_helper.h @@ -0,0 +1,90 @@ +/* + * 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 TEST_FUZZERS_FUZZ_DATA_HELPER_H_ +#define TEST_FUZZERS_FUZZ_DATA_HELPER_H_ + +#include + +#include "api/array_view.h" +#include "modules/rtp_rtcp/source/byte_io.h" + +namespace webrtc { +namespace test { + +// Helper class to take care of the fuzzer input, read from it, and keep track +// of when the end of the data has been reached. +class FuzzDataHelper { + public: + explicit FuzzDataHelper(rtc::ArrayView data); + + // Returns true if n bytes can be read. + bool CanReadBytes(size_t n) const { return data_ix_ + n <= data_.size(); } + + // Reads and returns data of type T. + template + T Read() { + RTC_CHECK(CanReadBytes(sizeof(T))); + T x = ByteReader::ReadLittleEndian(&data_[data_ix_]); + data_ix_ += sizeof(T); + return x; + } + + // Reads and returns data of type T. Returns default_value if not enough + // fuzzer input remains to read a T. + template + T ReadOrDefaultValue(T default_value) { + if (!CanReadBytes(sizeof(T))) { + return default_value; + } + return Read(); + } + + // Like ReadOrDefaultValue, but replaces the value 0 with default_value. + template + T ReadOrDefaultValueNotZero(T default_value) { + static_assert(std::is_integral::value, ""); + T x = ReadOrDefaultValue(default_value); + return x == 0 ? default_value : x; + } + + // Returns one of the elements from the provided input array. The selection + // is based on the fuzzer input data. If not enough fuzzer data is available, + // the method will return the first element in the input array. The reason for + // not flagging this as an error is to allow the method to be called from + // class constructors, and in constructors we typically do not handle + // errors. The code will work anyway, and the fuzzer will likely see that + // providing more data will actually make this method return something else. + template + T SelectOneOf(const T (&select_from)[N]) { + static_assert(N <= std::numeric_limits::max(), ""); + // Read an index between 0 and select_from.size() - 1 from the fuzzer data. + uint8_t index = ReadOrDefaultValue(0) % N; + return select_from[index]; + } + + rtc::ArrayView ReadByteArray(size_t bytes) { + if (!CanReadBytes(bytes)) { + return rtc::ArrayView(nullptr, 0); + } + const size_t index_to_return = data_ix_; + data_ix_ += bytes; + return data_.subview(index_to_return, bytes); + } + + private: + rtc::ArrayView data_; + size_t data_ix_ = 0; +}; + +} // namespace test +} // namespace webrtc + +#endif // TEST_FUZZERS_FUZZ_DATA_HELPER_H_ diff --git a/test/fuzzers/neteq_signal_fuzzer.cc b/test/fuzzers/neteq_signal_fuzzer.cc index f0b79113ae..28f2a1bf28 100644 --- a/test/fuzzers/neteq_signal_fuzzer.cc +++ b/test/fuzzers/neteq_signal_fuzzer.cc @@ -18,75 +18,19 @@ #include "modules/audio_coding/neteq/tools/audio_checksum.h" #include "modules/audio_coding/neteq/tools/encode_neteq_input.h" #include "modules/audio_coding/neteq/tools/neteq_test.h" -#include "modules/rtp_rtcp/source/byte_io.h" #include "rtc_base/numerics/safe_conversions.h" #include "rtc_base/random.h" +#include "test/fuzzers/fuzz_data_helper.h" namespace webrtc { namespace test { namespace { -// Helper class to take care of the fuzzer input, read from it, and keep track -// of when the end of the data has been reached. -class FuzzData { - public: - explicit FuzzData(rtc::ArrayView data) : data_(data) {} - - // Returns true if n bytes can be read. - bool CanReadBytes(size_t n) const { return data_ix_ + n <= data_.size(); } - - // Reads and returns data of type T. - template - T Read() { - RTC_CHECK(CanReadBytes(sizeof(T))); - T x = ByteReader::ReadLittleEndian(&data_[data_ix_]); - data_ix_ += sizeof(T); - return x; - } - - // Reads and returns data of type T. Returns default_value if not enough - // fuzzer input remains to read a T. - template - T ReadOrDefaultValue(T default_value) { - if (!CanReadBytes(sizeof(T))) { - return default_value; - } - return Read(); - } - - // Like ReadOrDefaultValue, but replaces the value 0 with default_value. - template - T ReadOrDefaultValueNotZero(T default_value) { - static_assert(std::is_integral::value, ""); - T x = ReadOrDefaultValue(default_value); - return x == 0 ? default_value : x; - } - - // Returns one of the elements from the provided input array. The selection - // is based on the fuzzer input data. If not enough fuzzer data is available, - // the method will return the first element in the input array. The reason for - // not flaggin this as an error is that the method is called from the - // FuzzSignalInput constructor, and in constructors we typically do not handle - // errors. The code will work anyway, and the fuzzer will likely see that - // providing more data will actually make this method return something else. - template - T SelectOneOf(rtc::ArrayView select_from) { - RTC_CHECK_LE(select_from.size(), std::numeric_limits::max()); - // Read an index between 0 and select_from.size() - 1 from the fuzzer data. - uint8_t index = ReadOrDefaultValue(0) % select_from.size(); - return select_from[index]; - } - - private: - rtc::ArrayView data_; - size_t data_ix_ = 0; -}; - // Generate a mixture of sine wave and gaussian noise. class SineAndNoiseGenerator : public EncodeNetEqInput::Generator { public: // The noise generator is seeded with a value from the fuzzer data, but 0 is // avoided (since it is not allowed by the Random class). - SineAndNoiseGenerator(int sample_rate_hz, FuzzData* fuzz_data) + SineAndNoiseGenerator(int sample_rate_hz, FuzzDataHelper* fuzz_data) : sample_rate_hz_(sample_rate_hz), fuzz_data_(*fuzz_data), noise_generator_(fuzz_data_.ReadOrDefaultValueNotZero(1)) {} @@ -117,13 +61,13 @@ class SineAndNoiseGenerator : public EncodeNetEqInput::Generator { const double kPi = std::acos(-1); std::vector samples_; double phase_ = 0.0; - FuzzData& fuzz_data_; + FuzzDataHelper& fuzz_data_; Random noise_generator_; }; class FuzzSignalInput : public NetEqInput { public: - explicit FuzzSignalInput(FuzzData* fuzz_data, + explicit FuzzSignalInput(FuzzDataHelper* fuzz_data, int sample_rate, uint8_t payload_type) : fuzz_data_(*fuzz_data) { @@ -141,8 +85,7 @@ class FuzzSignalInput : public NetEqInput { // call to NetEq::GetAudio. 10 ms is nominal, 9 and 11 ms will both lead to // clock drift (in different directions). constexpr int output_event_periods[] = {9, 10, 11}; - output_event_period_ms_ = - fuzz_data_.SelectOneOf(rtc::ArrayView(output_event_periods)); + output_event_period_ms_ = fuzz_data_.SelectOneOf(output_event_periods); } rtc::Optional NextPacketTime() const override { @@ -188,7 +131,7 @@ class FuzzSignalInput : public NetEqInput { private: bool ended_ = false; - FuzzData& fuzz_data_; + FuzzDataHelper& fuzz_data_; std::unique_ptr input_; std::unique_ptr packet_; int64_t next_output_event_ms_ = 0; @@ -199,13 +142,12 @@ class FuzzSignalInput : public NetEqInput { void FuzzOneInputTest(const uint8_t* data, size_t size) { if (size < 1) return; - FuzzData fuzz_data(rtc::ArrayView(data, size)); + FuzzDataHelper fuzz_data(rtc::ArrayView(data, size)); // Allowed sample rates and payload types used in the test. std::pair rate_types[] = { {8000, 93}, {16000, 94}, {32000, 95}, {48000, 96}}; - const auto rate_type = fuzz_data.SelectOneOf( - rtc::ArrayView>(rate_types)); + const auto rate_type = fuzz_data.SelectOneOf(rate_types); const int sample_rate = rate_type.first; const uint8_t payload_type = rate_type.second;