pipeline_integration_fuzzertest.cc 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. // Copyright 2016 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include <stddef.h>
  5. #include <stdint.h>
  6. #include <vector>
  7. #include "base/at_exit.h"
  8. #include "base/bind.h"
  9. #include "base/callback_helpers.h"
  10. #include "base/command_line.h"
  11. #include "base/location.h"
  12. #include "base/logging.h"
  13. #include "base/test/test_timeouts.h"
  14. #include "base/threading/thread_task_runner_handle.h"
  15. #include "media/base/bind_to_current_loop.h"
  16. #include "media/base/eme_constants.h"
  17. #include "media/base/media.h"
  18. #include "media/base/media_switches.h"
  19. #include "media/base/pipeline_status.h"
  20. #include "media/media_buildflags.h"
  21. #include "media/test/pipeline_integration_test_base.h"
  22. #include "media/test/test_media_source.h"
  23. #include "third_party/googletest/src/googletest/src/gtest-internal-inl.h"
  24. namespace {
  25. // Keep these aligned with BUILD.gn's pipeline_integration_fuzzer_variants
  26. enum FuzzerVariant {
  27. SRC,
  28. WEBM_OPUS,
  29. WEBM_VORBIS,
  30. WEBM_VP8,
  31. WEBM_VP9,
  32. WEBM_OPUS_VP9,
  33. #if BUILDFLAG(ENABLE_AV1_DECODER)
  34. MP4_AV1,
  35. #endif
  36. MP4_FLAC,
  37. MP4_OPUS,
  38. MP3,
  39. #if BUILDFLAG(USE_PROPRIETARY_CODECS)
  40. ADTS,
  41. MP4_AACLC,
  42. MP4_AACSBR,
  43. MP4_AVC1,
  44. MP4_AACLC_AVC,
  45. #if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER)
  46. MP2T_AACLC,
  47. MP2T_AACSBR,
  48. MP2T_AVC,
  49. MP2T_MP3,
  50. MP2T_AACLC_AVC,
  51. #endif // BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER)
  52. #endif // BUILDFLAG(USE_PROPRIETARY_CODECS)
  53. };
  54. std::string MseFuzzerVariantEnumToMimeTypeString(FuzzerVariant variant) {
  55. switch (variant) {
  56. case WEBM_OPUS:
  57. return "audio/webm; codecs=\"opus\"";
  58. case WEBM_VORBIS:
  59. return "audio/webm; codecs=\"vorbis\"";
  60. case WEBM_VP8:
  61. return "video/webm; codecs=\"vp8\"";
  62. case WEBM_VP9:
  63. return "video/webm; codecs=\"vp9\"";
  64. case WEBM_OPUS_VP9:
  65. return "video/webm; codecs=\"opus,vp9\"";
  66. #if BUILDFLAG(ENABLE_AV1_DECODER)
  67. case MP4_AV1:
  68. return "video/mp4; codecs=\"av01.0.04M.08\"";
  69. #endif // BUILDFLAG(ENABLE_AV1_DECODER)
  70. case MP4_FLAC:
  71. return "audio/mp4; codecs=\"flac\"";
  72. case MP4_OPUS:
  73. return "audio/mp4; codecs=\"opus\"";
  74. case MP3:
  75. return "audio/mpeg";
  76. #if BUILDFLAG(USE_PROPRIETARY_CODECS)
  77. case ADTS:
  78. return "audio/aac";
  79. case MP4_AACLC:
  80. return "audio/mp4; codecs=\"mp4a.40.2\"";
  81. case MP4_AACSBR:
  82. return "audio/mp4; codecs=\"mp4a.40.5\"";
  83. case MP4_AVC1:
  84. return "video/mp4; codecs=\"avc1.42E01E\"";
  85. case MP4_AACLC_AVC:
  86. return "video/mp4; codecs=\"mp4a.40.2,avc1.42E01E\"";
  87. #if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER)
  88. case MP2T_AACLC:
  89. return "video/mp2t; codecs=\"mp4a.67\"";
  90. case MP2T_AACSBR:
  91. return "video/mp2t; codecs=\"mp4a.40.5\"";
  92. case MP2T_AVC:
  93. return "video/mp2t; codecs=\"avc1.42E01E\"";
  94. case MP2T_MP3:
  95. // Note, "mp4a.6B" appears to be an equivalent codec substring.
  96. return "video/mp2t; codecs=\"mp4a.69\"";
  97. case MP2T_AACLC_AVC:
  98. return "video/mp2t; codecs=\"mp4a.40.2,avc1.42E01E\"";
  99. #endif // BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER)
  100. #endif // BUILDFLAG(USE_PROPRIETARY_CODECS)
  101. case SRC:
  102. NOTREACHED() << "SRC is an invalid MSE fuzzer variant";
  103. break;
  104. }
  105. return "";
  106. }
  107. } // namespace
  108. namespace media {
  109. // Limit the amount of initial (or post-seek) audio silence padding allowed in
  110. // rendering of fuzzed input.
  111. constexpr base::TimeDelta kMaxPlayDelay = base::Seconds(10);
  112. void OnEncryptedMediaInitData(media::PipelineIntegrationTestBase* test,
  113. media::EmeInitDataType /* type */,
  114. const std::vector<uint8_t>& /* init_data */) {
  115. // Encrypted media is not supported in this test. For an encrypted media file,
  116. // we will start demuxing the data but media pipeline will wait for a CDM to
  117. // be available to start initialization, which will not happen in this case.
  118. // To prevent the test timeout, we'll just fail the test immediately here.
  119. // Note: Since the callback is on the media task runner but the test is on
  120. // the main task runner, this must be posted.
  121. // TODO(xhwang): Support encrypted media in this fuzzer test.
  122. base::ThreadTaskRunnerHandle::Get()->PostTask(
  123. FROM_HERE, base::BindOnce(&PipelineIntegrationTestBase::FailTest,
  124. base::Unretained(test),
  125. media::PIPELINE_ERROR_INITIALIZATION_FAILED));
  126. }
  127. void OnAudioPlayDelay(media::PipelineIntegrationTestBase* test,
  128. base::TimeDelta play_delay) {
  129. CHECK_GT(play_delay, base::TimeDelta());
  130. if (play_delay > kMaxPlayDelay) {
  131. // Note: Since the callback is on the media task runner but the test is on
  132. // the main task runner, this must be posted.
  133. base::ThreadTaskRunnerHandle::Get()->PostTask(
  134. FROM_HERE, base::BindOnce(&PipelineIntegrationTestBase::FailTest,
  135. base::Unretained(test),
  136. media::PIPELINE_ERROR_INITIALIZATION_FAILED));
  137. }
  138. }
  139. class ProgressivePipelineIntegrationFuzzerTest
  140. : public PipelineIntegrationTestBase {
  141. public:
  142. ProgressivePipelineIntegrationFuzzerTest() {
  143. set_encrypted_media_init_data_cb(
  144. base::BindRepeating(&OnEncryptedMediaInitData, this));
  145. set_audio_play_delay_cb(
  146. BindToCurrentLoop(base::BindRepeating(&OnAudioPlayDelay, this)));
  147. }
  148. ~ProgressivePipelineIntegrationFuzzerTest() override = default;
  149. void RunTest(const uint8_t* data, size_t size) {
  150. if (PIPELINE_OK != Start(data, size, kUnreliableDuration | kFuzzing))
  151. return;
  152. Play();
  153. if (PIPELINE_OK != WaitUntilEndedOrError())
  154. return;
  155. Seek(base::TimeDelta());
  156. }
  157. };
  158. class MediaSourcePipelineIntegrationFuzzerTest
  159. : public PipelineIntegrationTestBase {
  160. public:
  161. MediaSourcePipelineIntegrationFuzzerTest() {
  162. set_encrypted_media_init_data_cb(
  163. base::BindRepeating(&OnEncryptedMediaInitData, this));
  164. set_audio_play_delay_cb(
  165. BindToCurrentLoop(base::BindRepeating(&OnAudioPlayDelay, this)));
  166. }
  167. ~MediaSourcePipelineIntegrationFuzzerTest() override = default;
  168. void RunTest(const uint8_t* data, size_t size, const std::string& mimetype) {
  169. if (size == 0)
  170. return;
  171. scoped_refptr<media::DecoderBuffer> buffer(
  172. DecoderBuffer::CopyFrom(data, size));
  173. TestMediaSource source(buffer, mimetype, kAppendWholeFile);
  174. // Prevent timeout in the case of not enough media appended to complete
  175. // demuxer initialization, yet no error in the media appended. The
  176. // following will trigger DEMUXER_ERROR_COULD_NOT_OPEN state transition in
  177. // this case.
  178. source.set_do_eos_after_next_append(true);
  179. source.set_encrypted_media_init_data_cb(
  180. base::BindRepeating(&OnEncryptedMediaInitData, this));
  181. // Allow parsing to either pass or fail without emitting a gtest failure
  182. // from TestMediaSource.
  183. source.set_expected_append_result(
  184. TestMediaSource::ExpectedAppendResult::kSuccessOrFailure);
  185. // TODO(wolenetz): Vary the behavior (abort/remove/seek/endOfStream/Append
  186. // in pieces/append near play-head/vary append mode/etc), perhaps using
  187. // CustomMutator and Seed to insert/update the variation information into/in
  188. // the |data| we process here. See https://crbug.com/750818.
  189. // Use |kFuzzing| test type to allow pipeline start to either pass or fail
  190. // without emitting a gtest failure.
  191. if (PIPELINE_OK != StartPipelineWithMediaSource(&source, kFuzzing, nullptr))
  192. return;
  193. Play();
  194. }
  195. };
  196. } // namespace media
  197. // Disable noisy logging.
  198. struct Environment {
  199. Environment() {
  200. base::CommandLine::Init(0, nullptr);
  201. // |test| instances uses TaskEnvironment, which needs TestTimeouts.
  202. TestTimeouts::Initialize();
  203. media::InitializeMediaLibrary();
  204. // Note, instead of LOG_FATAL, use a value at or below logging::LOG_VERBOSE
  205. // here to assist local debugging.
  206. logging::SetMinLogLevel(logging::LOG_FATAL);
  207. }
  208. };
  209. Environment* env = new Environment();
  210. // Entry point for LibFuzzer.
  211. extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
  212. // Media pipeline starts new threads, which needs AtExitManager.
  213. base::AtExitManager at_exit;
  214. FuzzerVariant variant = PIPELINE_FUZZER_VARIANT;
  215. // These tests use GoogleTest assertions without using the GoogleTest
  216. // framework. While this is the case, tell GoogleTest's stack trace getter
  217. // that GoogleTest is being left now so that there is a basis for traces
  218. // collected upon assertion failure. TODO(https://crbug.com/1039559): use
  219. // RUN_ALL_TESTS() and remove this code.
  220. ::testing::internal::GetUnitTestImpl()
  221. ->os_stack_trace_getter()
  222. ->UponLeavingGTest();
  223. if (variant == SRC) {
  224. media::ProgressivePipelineIntegrationFuzzerTest test;
  225. test.RunTest(data, size);
  226. } else {
  227. media::MediaSourcePipelineIntegrationFuzzerTest test;
  228. test.RunTest(data, size, MseFuzzerVariantEnumToMimeTypeString(variant));
  229. }
  230. return 0;
  231. }