1 /*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <fuzzer/FuzzedDataProvider.h>
18
19 #include "../g722_enc_dec.h"
20
21 namespace {
22
get_rate_from_fdp(FuzzedDataProvider * fdp)23 uint32_t get_rate_from_fdp(FuzzedDataProvider* fdp) {
24 uint32_t rate = fdp->ConsumeIntegralInRange<uint32_t>(
25 0, 3); // Currently 3 different bit rates are available in G.722 codec
26 switch (rate) {
27 case 0:
28 return 48000;
29 case 1:
30 return 56000;
31 default:
32 return 64000;
33 }
34 }
35
fuzz_encode(FuzzedDataProvider * fdp)36 void fuzz_encode(FuzzedDataProvider* fdp) {
37 uint32_t rate = get_rate_from_fdp(fdp);
38 std::vector<uint8_t> buff = fdp->ConsumeRemainingBytes<uint8_t>();
39
40 int num_samples = buff.size() / (2 /*bytes_per_sample*/ * 2 /*number of channels*/);
41
42 // The G.722 codec accept only even number of samples for encoding
43 if (num_samples % 2 != 0) {
44 num_samples--;
45 }
46
47 // Making channel data from buffer
48 std::vector<uint16_t> channel_data;
49
50 for (int i = 0; i < num_samples; i++) {
51 const uint8_t* sample = buff.data() + i * 2;
52 int16_t left = (int16_t)((*(sample + 1) << 8) + *sample) >> 1;
53
54 sample += 2;
55 int16_t right = (int16_t)((*(sample + 1) << 8) + *sample) >> 1;
56
57 uint16_t mono_data = (int16_t)(((uint32_t)left + (uint32_t)right) >> 1);
58 channel_data.push_back(mono_data);
59 }
60
61 // Encoder Initialization
62 g722_encode_state_t* encoder_state = nullptr;
63 encoder_state = g722_encode_init(nullptr, rate, G722_PACKED);
64
65 // Encode
66 std::vector<uint8_t> encoded_data;
67 // Magic number is used in api, It should basically fit the number generated
68 // by this formula : num_channels * sample_rate * data_interval_ms
69 // * (bit_rate / 8)) / 1000 as mentioned in hearing_aid.cc And if we fit all
70 // the values in the above formula, the max value we can get is 1920. And I
71 // used "size" of the input that libfuzzer generates as the initial
72 // parameter to resize
73 encoded_data.resize(buff.size());
74 int encoded_size = g722_encode(encoder_state, encoded_data.data(),
75 (const int16_t*)channel_data.data(), channel_data.size());
76 encoded_data.resize(encoded_size);
77
78 // Encoder release
79 if (encoder_state != nullptr) {
80 g722_encode_release(encoder_state);
81 encoder_state = nullptr;
82 }
83 }
84
fuzz_decode(FuzzedDataProvider * fdp)85 void fuzz_decode(FuzzedDataProvider* fdp) {
86 // Get values for primitive types from fdp
87 uint32_t rate = get_rate_from_fdp(fdp);
88 int options = fdp->ConsumeIntegral<int>();
89 uint16_t gain = fdp->ConsumeIntegral<uint16_t>();
90
91 // Decoder Initialization
92 g722_decode_state_t* decoder_state = nullptr;
93 decoder_state = g722_decode_init(decoder_state, rate, options);
94
95 std::vector<uint8_t> encoded_input = fdp->ConsumeRemainingBytes<uint8_t>();
96 int out_len = encoded_input.size() * 2 /*bytes_per_sample*/ * 2 /*number of channels*/;
97
98 // Decode
99 std::vector<int16_t> decoded_output;
100 decoded_output.resize(out_len);
101 int decoded_size = g722_decode(decoder_state, decoded_output.data(),
102 (const uint8_t*)encoded_input.data(), encoded_input.size(), gain);
103 if (decoded_size > decoded_output.size()) {
104 abort();
105 }
106
107 // Encoder release
108 if (decoder_state != nullptr) {
109 g722_decode_release(decoder_state);
110 decoder_state = nullptr;
111 }
112 }
113 } // namespace
114
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)115 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
116 FuzzedDataProvider fdp(data, size);
117 fdp.ConsumeBool() ? fuzz_encode(&fdp) : fuzz_decode(&fdp);
118 return 0;
119 }
120