xref: /aosp_15_r20/external/libwebm/testing/mkvparser_fuzzer.cc (revision 103e46e4cd4b6efcf6001f23fa8665fb110abf8d)
1 // Copyright (c) 2022 The WebM project authors. All Rights Reserved.
2 //
3 // Use of this source code is governed by a BSD-style license
4 // that can be found in the LICENSE file in the root of the source
5 // tree. An additional intellectual property rights grant can be found
6 // in the file PATENTS.  All contributing project authors may
7 // be found in the AUTHORS file in the root of the source tree.
8 #include <cstddef>
9 #include <cstdint>
10 #include <cstdlib>
11 #include <cstring>
12 #include <functional>
13 #include <memory>
14 #include <new>
15 
16 #include "mkvparser/mkvparser.h"
17 #include "mkvparser/mkvreader.h"
18 
19 namespace {
20 
21 class MemoryReader : public mkvparser::IMkvReader {
22  public:
MemoryReader(const uint8_t * data,size_t size)23   MemoryReader(const uint8_t* data, size_t size) : data_(data), size_(size) {}
24 
Read(long long pos,long len,unsigned char * buf)25   int Read(long long pos, long len, unsigned char* buf) override {
26     if (pos < 0 || len < 0) {
27       abort();
28     }
29     if (pos >= size_ || size_ - pos < len) {
30       return -1;
31     }
32     memcpy(buf, data_ + pos, len);
33     return 0;
34   }
35 
Length(long long * total,long long * available)36   int Length(long long* total, long long* available) override {
37     if (total != nullptr) {
38       *total = size_;
39     }
40     if (available != nullptr) {
41       *available = size_;
42     }
43     return 0;
44   }
45 
46  private:
47   const uint8_t* data_;
48   size_t size_;
49 };
50 
ParseCues(const mkvparser::Segment & segment)51 void ParseCues(const mkvparser::Segment& segment) {
52   const mkvparser::Cues* const cues = segment.GetCues();
53   if (cues == nullptr) {
54     return;
55   }
56 
57   while (!cues->DoneParsing()) {
58     cues->LoadCuePoint();
59   }
60 }
61 
GetBlockEntryFromCues(const void * ctx,const mkvparser::CuePoint * cue,const mkvparser::CuePoint::TrackPosition * track_pos)62 const mkvparser::BlockEntry* GetBlockEntryFromCues(
63     const void* ctx, const mkvparser::CuePoint* cue,
64     const mkvparser::CuePoint::TrackPosition* track_pos) {
65   const auto* const cues = static_cast<const mkvparser::Cues*>(ctx);
66   return cues->GetBlock(cue, track_pos);
67 }
68 
GetBlockEntryFromCluster(const void * ctx,const mkvparser::CuePoint * cue,const mkvparser::CuePoint::TrackPosition * track_pos)69 const mkvparser::BlockEntry* GetBlockEntryFromCluster(
70     const void* ctx, const mkvparser::CuePoint* cue,
71     const mkvparser::CuePoint::TrackPosition* track_pos) {
72   if (track_pos == nullptr) {
73     return nullptr;
74   }
75   const auto* const cluster = static_cast<const mkvparser::Cluster*>(ctx);
76   const mkvparser::BlockEntry* block_entry =
77       cluster->GetEntry(*cue, *track_pos);
78   return block_entry;
79 }
80 
WalkCues(const mkvparser::Segment & segment,std::function<const mkvparser::BlockEntry * (const void *,const mkvparser::CuePoint *,const mkvparser::CuePoint::TrackPosition *)> get_block_entry,const void * ctx)81 void WalkCues(const mkvparser::Segment& segment,
82               std::function<const mkvparser::BlockEntry*(
83                   const void*, const mkvparser::CuePoint*,
84                   const mkvparser::CuePoint::TrackPosition*)>
85                   get_block_entry,
86               const void* ctx) {
87   const mkvparser::Cues* const cues = segment.GetCues();
88   const mkvparser::Tracks* tracks = segment.GetTracks();
89   if (cues == nullptr || tracks == nullptr) {
90     return;
91   }
92   const unsigned long num_tracks = tracks->GetTracksCount();
93 
94   for (const mkvparser::CuePoint* cue = cues->GetFirst(); cue != nullptr;
95        cue = cues->GetNext(cue)) {
96     for (unsigned long track_num = 0; track_num < num_tracks; ++track_num) {
97       const mkvparser::Track* const track = tracks->GetTrackByIndex(track_num);
98       const mkvparser::CuePoint::TrackPosition* const track_pos =
99           cue->Find(track);
100       const mkvparser::BlockEntry* block_entry =
101           get_block_entry(ctx, cue, track_pos);
102       static_cast<void>(block_entry);
103     }
104   }
105 }
106 
ParseCluster(const mkvparser::Cluster & cluster)107 void ParseCluster(const mkvparser::Cluster& cluster) {
108   const mkvparser::BlockEntry* block_entry;
109   long status = cluster.GetFirst(block_entry);
110   if (status != 0) {
111     return;
112   }
113 
114   while (block_entry != nullptr && !block_entry->EOS()) {
115     const mkvparser::Block* const block = block_entry->GetBlock();
116     if (block == nullptr) {
117       return;
118     }
119 
120     status = cluster.GetNext(block_entry, block_entry);
121     if (status != 0) {
122       return;
123     }
124   }
125 }
126 
127 }  // namespace
128 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)129 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
130   MemoryReader reader(data, size);
131 
132   long long int pos = 0;
133   std::unique_ptr<mkvparser::EBMLHeader> ebml_header(
134       new (std::nothrow) mkvparser::EBMLHeader());  // NOLINT
135   if (ebml_header->Parse(&reader, pos) < 0) {
136     return 0;
137   }
138 
139   mkvparser::Segment* temp_segment;
140   if (mkvparser::Segment::CreateInstance(&reader, pos, temp_segment) != 0) {
141     return 0;
142   }
143   std::unique_ptr<mkvparser::Segment> segment(temp_segment);
144 
145   if (segment->Load() < 0) {
146     return 0;
147   }
148 
149   ParseCues(*segment);
150   WalkCues(*segment, GetBlockEntryFromCues, segment->GetCues());
151 
152   const mkvparser::Cluster* cluster = segment->GetFirst();
153   while (cluster != nullptr && !cluster->EOS()) {
154     ParseCluster(*cluster);
155     WalkCues(*segment, GetBlockEntryFromCluster, cluster);
156     cluster = segment->GetNext(cluster);
157   }
158 
159   return 0;
160 }
161