1 // Copyright 2020 Google LLC
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 <errno.h>
16 #include <stdint.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20
21 #include "opusfile/config.h"
22 #include "opusfile/include/opusfile.h"
23
24 // Opusfile fuzzing wrapper to help with automated fuzz testing. It's based on
25 // https://github.com/xiph/opusfile/blob/master/examples/opusfile_example.c
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)26 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
27 int ret, tmp;
28 OggOpusFile *of = op_open_memory(data, size, &ret);
29 if (!of)
30 return 0;
31
32 op_link_count(of);
33
34 int link_index = -1;
35 op_pcm_total(of, link_index);
36 op_raw_total(of, link_index);
37 op_pcm_tell(of);
38 op_raw_tell(of);
39
40 ogg_int64_t total_sample_count = 0;
41 const int pcm_size = 120 * 48 * 2; // 120ms/ch@48kHz is recommended
42 opus_int16 pcm[pcm_size];
43 for (;;) {
44 ret = op_read_stereo(of, pcm, pcm_size);
45 if (ret < 0) {
46 break;
47 }
48
49 if (op_current_link(of) != link_index) {
50 link_index = op_current_link(of);
51 op_pcm_total(of, link_index);
52 op_raw_total(of, link_index);
53 op_pcm_tell(of);
54 op_raw_tell(of);
55 op_bitrate_instant(of);
56 tmp = op_head(of, link_index)->version;
57
58 const OpusTags *tags = op_tags(of, link_index);
59 for (int i = 0; i < tags->comments; ++i) {
60 // Note: The compare also touches memory allocated for user_comments[i].
61 // This is a desired side effect and should be kept even if this
62 // comparison is removed.
63 if (opus_tagncompare("METADATA_BLOCK_PICTURE", 22,
64 tags->user_comments[i]) == 0) {
65 OpusPictureTag pic;
66 if (opus_picture_tag_parse(&pic, tags->user_comments[i]) >= 0) {
67 opus_picture_tag_clear(&pic);
68 }
69 }
70 }
71
72 if (tags->vendor) {
73 tmp = tags->vendor[0];
74 }
75
76 int binary_suffix_len;
77 opus_tags_get_binary_suffix(tags, &binary_suffix_len);
78 }
79
80 if (ret == 0) {
81 break;
82 }
83
84 total_sample_count += ret;
85 }
86
87 if (total_sample_count > 0) {
88 // Try random-access PCM reads. The number of tests is arbitrary and the
89 // offset is designed to be pseudo-random, but deterministic - this is
90 // implemented using Lehmer RNG with a minor hack that probably breaks some
91 // properties of the RNG (but that is acceptable).
92 ogg_int64_t rng_seed = 1307832949LL;
93 for (int i = 0; i < 32; ++i) {
94 // Derive the next deterministic offset to test and iterate the RNG.
95 rng_seed = (rng_seed * 279470273LL);
96 const ogg_int64_t offset = rng_seed % total_sample_count;
97 rng_seed = rng_seed % 4294967291LL;
98
99 if (op_pcm_seek(of, offset) == 0) {
100 tmp = op_read_stereo(of, pcm, pcm_size);
101 }
102 }
103 }
104
105 op_free(of);
106 return 0;
107 }
108