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