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