xref: /aosp_15_r20/external/libgav1/tests/fuzzer/obu_parser_fuzzer.cc (revision 095378508e87ed692bf8dfeb34008b65b3735891)
1 // Copyright 2020 The libgav1 Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <cstddef>
16 #include <cstdint>
17 #include <memory>
18 #include <vector>
19 
20 #include "examples/file_reader.h"
21 #include "examples/file_reader_constants.h"
22 #include "examples/file_reader_interface.h"
23 #include "src/buffer_pool.h"
24 #include "src/decoder_impl.h"
25 #include "src/decoder_state.h"
26 #include "src/internal_frame_buffer_list.h"
27 #include "src/obu_parser.h"
28 #include "tests/fuzzer/fuzzer_temp_file.h"
29 
30 namespace {
31 
32 #if defined(LIBGAV1_EXHAUSTIVE_FUZZING)
33 // Set a large upper bound to give more coverage of a single input; this value
34 // should be larger than most of the frame counts in the corpus.
35 constexpr int kMaxFrames = 100;
36 constexpr size_t kMaxDataSize = 400 * 1024;
37 #else
38 // Restrict the number of frames and obus to improve fuzzer throughput.
39 constexpr int kMaxFrames = 5;
40 constexpr size_t kMaxDataSize = 200 * 1024;
41 #endif
42 
ParseObu(const uint8_t * const data,size_t size)43 inline void ParseObu(const uint8_t* const data, size_t size) {
44   size_t av1c_size;
45   const std::unique_ptr<uint8_t[]> av1c_box =
46       libgav1::ObuParser::GetAV1CodecConfigurationBox(data, size, &av1c_size);
47   static_cast<void>(av1c_box);
48 
49   libgav1::InternalFrameBufferList buffer_list;
50   libgav1::BufferPool buffer_pool(libgav1::OnInternalFrameBufferSizeChanged,
51                                   libgav1::GetInternalFrameBuffer,
52                                   libgav1::ReleaseInternalFrameBuffer,
53                                   &buffer_list);
54   libgav1::DecoderState decoder_state;
55   libgav1::ObuParser parser(data, size, 0, &buffer_pool, &decoder_state);
56   libgav1::RefCountedBufferPtr current_frame;
57   int parsed_frames = 0;
58   while (parser.HasData()) {
59     if (parser.ParseOneFrame(&current_frame) != libgav1::kStatusOk) break;
60     if (++parsed_frames >= kMaxFrames) break;
61   }
62 }
63 
64 }  // namespace
65 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)66 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
67   // Reject large chunks of data to improve fuzzer throughput.
68   if (size > kMaxDataSize) return 0;
69 
70   // Treat the input as a raw OBU stream.
71   ParseObu(data, size);
72 
73   // Use the first frame from an IVF to bypass any read errors from the parser.
74   static constexpr size_t kIvfHeaderSize =
75       libgav1::kIvfFileHeaderSize + libgav1::kIvfFrameHeaderSize;
76   if (size >= kIvfHeaderSize) {
77     ParseObu(data + kIvfHeaderSize, size - kIvfHeaderSize);
78   }
79 
80   FuzzerTemporaryFile tempfile(data, size);
81   auto file_reader =
82       libgav1::FileReader::Open(tempfile.filename(), /*error_tolerant=*/true);
83   if (file_reader == nullptr) return 0;
84 
85   std::vector<uint8_t> buffer;
86   int parsed_frames = 0;
87   do {
88     if (!file_reader->ReadTemporalUnit(&buffer, nullptr)) break;
89     ParseObu(buffer.data(), buffer.size());
90     if (++parsed_frames >= kMaxFrames) break;
91   } while (!file_reader->IsEndOfFile());
92 
93   return 0;
94 }
95