• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/gav1/decoder.h"
24 #include "tests/fuzzer/fuzzer_temp_file.h"
25 
26 namespace {
27 
28 #if defined(LIBGAV1_EXHAUSTIVE_FUZZING)
29 // Set a large upper bound to give more coverage of a single input; this value
30 // should be larger than most of the frame counts in the corpus.
31 constexpr int kMaxFrames = 100;
32 constexpr size_t kMaxDataSize = 400 * 1024;
33 #else
34 // Restrict the number of frames to improve fuzzer throughput.
35 constexpr int kMaxFrames = 5;
36 constexpr size_t kMaxDataSize = 200 * 1024;
37 #endif
38 
39 constexpr int kFrequencyParseOnly = 10;
40 
Decode(const uint8_t * const data,const size_t size,libgav1::Decoder * const decoder)41 void Decode(const uint8_t* const data, const size_t size,
42             libgav1::Decoder* const decoder) {
43   decoder->EnqueueFrame(data, size, /*user_private_data=*/0,
44                         /*buffer_private_data=*/nullptr);
45   const libgav1::DecoderBuffer* buffer;
46   decoder->DequeueFrame(&buffer);
47 }
48 
49 }  // namespace
50 
51 // Always returns 0. Nonzero return values are reserved by libFuzzer for future
52 // use.
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)53 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
54   // Reject large chunks of data to improve fuzzer throughput.
55   if (size > kMaxDataSize) return 0;
56 
57   libgav1::Decoder decoder;
58   libgav1::DecoderSettings settings = {};
59   // Use the low byte of the width to seed the number of threads.
60   // We use both nibbles of the lower byte as this results in values != 1 much
61   // more quickly than using the lower nibble alone.
62   settings.threads = (size >= 13) ? ((data[12] >> 4 | data[12]) & 0xF) + 1 : 1;
63   settings.parse_only = size % kFrequencyParseOnly == 0;
64   if (decoder.Init(&settings) != libgav1::kStatusOk) return 0;
65 
66   // Treat the input as a raw OBU stream.
67   Decode(data, size, &decoder);
68 
69   // Use the first frame from an IVF to bypass any read errors from the parser.
70   static constexpr size_t kIvfHeaderSize =
71       libgav1::kIvfFileHeaderSize + libgav1::kIvfFrameHeaderSize;
72   if (size >= kIvfHeaderSize) {
73     Decode(data + kIvfHeaderSize, size - kIvfHeaderSize, &decoder);
74   }
75 
76   FuzzerTemporaryFile tempfile(data, size);
77   auto file_reader =
78       libgav1::FileReader::Open(tempfile.filename(), /*error_tolerant=*/true);
79   if (file_reader == nullptr) return 0;
80 
81   std::vector<uint8_t> buffer;
82   int decoded_frames = 0;
83   do {
84     if (!file_reader->ReadTemporalUnit(&buffer, nullptr)) break;
85     Decode(buffer.data(), buffer.size(), &decoder);
86     if (++decoded_frames >= kMaxFrames) break;
87   } while (!file_reader->IsEndOfFile());
88 
89   return 0;
90 }
91