xref: /aosp_15_r20/external/tremolo/fuzzer/vorbis_dec_fuzzer.cpp (revision bda690e46497e1f65c5077173b9c548e6e0cd5a1)
1*bda690e4SXin Li /******************************************************************************
2*bda690e4SXin Li  *
3*bda690e4SXin Li  * Copyright (C) 2020 The Android Open Source Project
4*bda690e4SXin Li  *
5*bda690e4SXin Li  * Licensed under the Apache License, Version 2.0 (the "License");
6*bda690e4SXin Li  * you may not use this file except in compliance with the License.
7*bda690e4SXin Li  * You may obtain a copy of the License at:
8*bda690e4SXin Li  *
9*bda690e4SXin Li  * http://www.apache.org/licenses/LICENSE-2.0
10*bda690e4SXin Li  *
11*bda690e4SXin Li  * Unless required by applicable law or agreed to in writing, software
12*bda690e4SXin Li  * distributed under the License is distributed on an "AS IS" BASIS,
13*bda690e4SXin Li  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*bda690e4SXin Li  * See the License for the specific language governing permissions and
15*bda690e4SXin Li  * limitations under the License.
16*bda690e4SXin Li  *
17*bda690e4SXin Li  *****************************************************************************
18*bda690e4SXin Li  * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
19*bda690e4SXin Li  */
20*bda690e4SXin Li 
21*bda690e4SXin Li #include <stdint.h>
22*bda690e4SXin Li #include <string.h>
23*bda690e4SXin Li extern "C" {
24*bda690e4SXin Li #include <Tremolo/codec_internal.h>
25*bda690e4SXin Li 
26*bda690e4SXin Li int _vorbis_unpack_books(vorbis_info *vi, oggpack_buffer *opb);
27*bda690e4SXin Li int _vorbis_unpack_info(vorbis_info *vi, oggpack_buffer *opb);
28*bda690e4SXin Li int _vorbis_unpack_comment(vorbis_comment *vc, oggpack_buffer *opb);
29*bda690e4SXin Li }
30*bda690e4SXin Li 
31*bda690e4SXin Li constexpr int16_t kMaxNumSamplesPerChannel = 8192;
32*bda690e4SXin Li constexpr size_t kVorbisHeaderlength = 7;
33*bda690e4SXin Li 
34*bda690e4SXin Li class Codec {
35*bda690e4SXin Li  public:
36*bda690e4SXin Li   Codec() = default;
~Codec()37*bda690e4SXin Li   ~Codec() { deInitDecoder(); }
38*bda690e4SXin Li   bool initDecoder();
39*bda690e4SXin Li   void decodeFrames(const uint8_t *data, size_t size);
40*bda690e4SXin Li   void deInitDecoder();
41*bda690e4SXin Li 
42*bda690e4SXin Li  private:
43*bda690e4SXin Li   bool mInfoUnpacked = false;
44*bda690e4SXin Li   bool mBooksUnpacked = false;
45*bda690e4SXin Li   int32_t mNumFramesLeftOnPage = -1;
46*bda690e4SXin Li   vorbis_dsp_state *mState = nullptr;
47*bda690e4SXin Li   vorbis_info *mVi = nullptr;
48*bda690e4SXin Li };
49*bda690e4SXin Li 
initDecoder()50*bda690e4SXin Li bool Codec::initDecoder() {
51*bda690e4SXin Li   mVi = new vorbis_info{};
52*bda690e4SXin Li   if (!mVi) {
53*bda690e4SXin Li     return false;
54*bda690e4SXin Li   }
55*bda690e4SXin Li   vorbis_info_clear(mVi);
56*bda690e4SXin Li 
57*bda690e4SXin Li   mState = new vorbis_dsp_state{};
58*bda690e4SXin Li   if (!mState) {
59*bda690e4SXin Li     return false;
60*bda690e4SXin Li   }
61*bda690e4SXin Li   vorbis_dsp_clear(mState);
62*bda690e4SXin Li 
63*bda690e4SXin Li   mNumFramesLeftOnPage = -1;
64*bda690e4SXin Li   mInfoUnpacked = false;
65*bda690e4SXin Li   mBooksUnpacked = false;
66*bda690e4SXin Li 
67*bda690e4SXin Li   return true;
68*bda690e4SXin Li }
69*bda690e4SXin Li 
makeBitReader(const uint8_t * data,size_t size,ogg_buffer * buf,ogg_reference * ref,oggpack_buffer * bits)70*bda690e4SXin Li static void makeBitReader(const uint8_t *data, size_t size, ogg_buffer *buf, ogg_reference *ref,
71*bda690e4SXin Li                           oggpack_buffer *bits) {
72*bda690e4SXin Li   buf->data = const_cast<uint8_t *>(data);
73*bda690e4SXin Li   buf->size = size;
74*bda690e4SXin Li   buf->refcount = 1;
75*bda690e4SXin Li   buf->ptr.owner = nullptr;
76*bda690e4SXin Li 
77*bda690e4SXin Li   ref->buffer = buf;
78*bda690e4SXin Li   ref->begin = 0;
79*bda690e4SXin Li   ref->length = size;
80*bda690e4SXin Li   ref->next = nullptr;
81*bda690e4SXin Li 
82*bda690e4SXin Li   oggpack_readinit(bits, ref);
83*bda690e4SXin Li }
84*bda690e4SXin Li 
decodeFrames(const uint8_t * data,size_t size)85*bda690e4SXin Li void Codec::decodeFrames(const uint8_t *data, size_t size) {
86*bda690e4SXin Li   /* Decode vorbis headers only once */
87*bda690e4SXin Li   while (size > 0) {
88*bda690e4SXin Li     if (size > kVorbisHeaderlength && (!memcmp(&data[1], "vorbis", 6)) &&
89*bda690e4SXin Li         (!mInfoUnpacked || !mBooksUnpacked)) {
90*bda690e4SXin Li       if ((data[0] == 1) || (data[0] == 5)) {
91*bda690e4SXin Li         ogg_buffer buf;
92*bda690e4SXin Li         ogg_reference ref;
93*bda690e4SXin Li         oggpack_buffer bits;
94*bda690e4SXin Li         /* skip kVorbisHeaderlength <type + "vorbis"> bytes */
95*bda690e4SXin Li         makeBitReader(data + kVorbisHeaderlength, size - kVorbisHeaderlength, &buf, &ref, &bits);
96*bda690e4SXin Li         if (data[0] == 1) {
97*bda690e4SXin Li           // release any memory that vorbis_info_init will blindly overwrite
98*bda690e4SXin Li           vorbis_info_clear(mVi);
99*bda690e4SXin Li           vorbis_info_init(mVi);
100*bda690e4SXin Li           if (0 != _vorbis_unpack_info(mVi, &bits)) {
101*bda690e4SXin Li             return;
102*bda690e4SXin Li           }
103*bda690e4SXin Li           mInfoUnpacked = true;
104*bda690e4SXin Li         } else { /* data[0] == 5*/
105*bda690e4SXin Li           if (!mInfoUnpacked) {
106*bda690e4SXin Li             return;
107*bda690e4SXin Li           }
108*bda690e4SXin Li           if (0 != _vorbis_unpack_books(mVi, &bits)) {
109*bda690e4SXin Li             return;
110*bda690e4SXin Li           }
111*bda690e4SXin Li           // release any memory that vorbis_dsp_init will blindly overwrite
112*bda690e4SXin Li           vorbis_dsp_clear(mState);
113*bda690e4SXin Li           if (0 != vorbis_dsp_init(mState, mVi)) {
114*bda690e4SXin Li             return;
115*bda690e4SXin Li           }
116*bda690e4SXin Li           mBooksUnpacked = true;
117*bda690e4SXin Li           data += kVorbisHeaderlength;
118*bda690e4SXin Li           size -= kVorbisHeaderlength;
119*bda690e4SXin Li           break;
120*bda690e4SXin Li         }
121*bda690e4SXin Li       }
122*bda690e4SXin Li     }
123*bda690e4SXin Li     ++data;
124*bda690e4SXin Li     --size;
125*bda690e4SXin Li   }
126*bda690e4SXin Li 
127*bda690e4SXin Li   if (!mInfoUnpacked || !mBooksUnpacked) {
128*bda690e4SXin Li     return;
129*bda690e4SXin Li   }
130*bda690e4SXin Li 
131*bda690e4SXin Li   int32_t numPageFrames = 0;
132*bda690e4SXin Li   if (size < sizeof(numPageFrames)) {
133*bda690e4SXin Li     return;
134*bda690e4SXin Li   }
135*bda690e4SXin Li   memcpy(&numPageFrames, data + size - sizeof(numPageFrames), sizeof(numPageFrames));
136*bda690e4SXin Li   size -= sizeof(numPageFrames);
137*bda690e4SXin Li   if (numPageFrames >= 0) {
138*bda690e4SXin Li     mNumFramesLeftOnPage = numPageFrames;
139*bda690e4SXin Li   }
140*bda690e4SXin Li 
141*bda690e4SXin Li   ogg_buffer buf;
142*bda690e4SXin Li   buf.data = const_cast<unsigned char *>(data);
143*bda690e4SXin Li   buf.size = size;
144*bda690e4SXin Li   buf.refcount = 1;
145*bda690e4SXin Li   buf.ptr.owner = nullptr;
146*bda690e4SXin Li 
147*bda690e4SXin Li   ogg_reference ref;
148*bda690e4SXin Li   ref.buffer = &buf;
149*bda690e4SXin Li   ref.begin = 0;
150*bda690e4SXin Li   ref.length = buf.size;
151*bda690e4SXin Li   ref.next = nullptr;
152*bda690e4SXin Li 
153*bda690e4SXin Li   ogg_packet pack;
154*bda690e4SXin Li   pack.packet = &ref;
155*bda690e4SXin Li   pack.bytes = ref.length;
156*bda690e4SXin Li   pack.b_o_s = 0;
157*bda690e4SXin Li   pack.e_o_s = 0;
158*bda690e4SXin Li   pack.granulepos = 0;
159*bda690e4SXin Li   pack.packetno = 0;
160*bda690e4SXin Li 
161*bda690e4SXin Li   int ret = vorbis_dsp_synthesis(mState, &pack, 1);
162*bda690e4SXin Li   if (0 == ret) {
163*bda690e4SXin Li     size_t maxSamplesInBuffer = kMaxNumSamplesPerChannel * mVi->channels;
164*bda690e4SXin Li     size_t outCapacity = maxSamplesInBuffer * sizeof(int16_t);
165*bda690e4SXin Li     int16_t outputBuf[outCapacity];
166*bda690e4SXin Li     vorbis_dsp_pcmout(mState, outputBuf, kMaxNumSamplesPerChannel);
167*bda690e4SXin Li   }
168*bda690e4SXin Li }
169*bda690e4SXin Li 
deInitDecoder()170*bda690e4SXin Li void Codec::deInitDecoder() {
171*bda690e4SXin Li   if (mState) {
172*bda690e4SXin Li     vorbis_dsp_clear(mState);
173*bda690e4SXin Li     delete mState;
174*bda690e4SXin Li     mState = nullptr;
175*bda690e4SXin Li   }
176*bda690e4SXin Li 
177*bda690e4SXin Li   if (mVi) {
178*bda690e4SXin Li     vorbis_info_clear(mVi);
179*bda690e4SXin Li     delete mVi;
180*bda690e4SXin Li     mVi = nullptr;
181*bda690e4SXin Li   }
182*bda690e4SXin Li }
183*bda690e4SXin Li 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)184*bda690e4SXin Li extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
185*bda690e4SXin Li   if (size < kVorbisHeaderlength + 1) { /* 7 bytes for header , at least 1 byte for data */
186*bda690e4SXin Li     return 0;
187*bda690e4SXin Li   }
188*bda690e4SXin Li   Codec *codec = new Codec();
189*bda690e4SXin Li   if (!codec) {
190*bda690e4SXin Li     return 0;
191*bda690e4SXin Li   }
192*bda690e4SXin Li   if (codec->initDecoder()) {
193*bda690e4SXin Li     codec->decodeFrames(data, size);
194*bda690e4SXin Li   }
195*bda690e4SXin Li   delete codec;
196*bda690e4SXin Li   return 0;
197*bda690e4SXin Li }
198