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 <stddef.h>
16 #include <stdlib.h>
17
18 #include "opus.h"
19 #include "opus_multistream.h"
20
21 struct TocInfo {
22 opus_int32 frequency; // in [Hz*1000]
23 int channels; // number of channels; either 1 or 2
24 int frame_len_x2; // in [ms*2]. x2 is to avoid float value of 2.5 ms
25 };
26
extractTocInfo(const uint8_t toc,struct TocInfo * const info)27 void extractTocInfo(const uint8_t toc, struct TocInfo *const info) {
28 const int frame_lengths_x2[3][4] = {
29 {20, 40, 80, 120},
30 {20, 40, 20, 40},
31 {5, 10, 20, 40}
32 };
33
34 info->channels = toc & 4 ? 2 : 1;
35
36 const uint8_t config = toc >> 3;
37
38 int len_index;
39 if (config < 12) {
40 len_index = 0;
41 } else if (config < 16) {
42 len_index = 1;
43 } else {
44 len_index = 2;
45 }
46 info->frame_len_x2 = frame_lengths_x2[len_index][config & 3];
47
48 switch (config >> 2) {
49 case 0: info->frequency = 8; break;
50 case 1: info->frequency = 12; break;
51 case 2: info->frequency = 16; break;
52 case 3: info->frequency = (config < 14) ? 24 : 48; break;
53 case 4: info->frequency = 8; break;
54 case 5: info->frequency = 16; break;
55 case 6: info->frequency = 24; break;
56 default: info->frequency = 48; break;
57 }
58 }
59
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)60 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
61 if (size < 3 || size > 1000000) return 0;
62
63 // Using last byte as a number of streams (instead of rand_r). Each stream
64 // should be at least 3 bytes long hence divmod.
65 int streams = 1 + data[size - 1] % (size / 3);
66 if (streams > 255) streams = 255;
67 unsigned char *mapping = (unsigned char*) malloc(sizeof(unsigned char)*streams);
68 if (!mapping) return 0;
69
70 for (int i = 0; i < streams; ++i) {
71 mapping[i] = i;
72 }
73
74 struct TocInfo info;
75 extractTocInfo(*data, &info);
76
77 int error = 0;
78 OpusMSDecoder *const decoder = opus_multistream_decoder_create(
79 info.frequency * 1000, streams, streams, 0, mapping, &error);
80
81 if (!decoder || error) return 0;
82
83 const int frame_size = (info.frequency * info.frame_len_x2) / 2;
84 opus_int16 *pcm = (opus_int16*) malloc(sizeof(opus_int16)*frame_size*streams);
85 if (!pcm) goto exit;
86
87 // opus_decode wants us to use its return value, but we don't really care.
88 const int foo =
89 opus_multistream_decode(decoder, data, size, pcm, frame_size, 0);
90 (void)foo;
91
92 opus_multistream_decoder_destroy(decoder);
93
94 free(pcm);
95
96 exit:
97 free(mapping);
98 return 0;
99 }
100