Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/xiph/speex.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTristan Matthews <tmatth@videolan.org>2017-02-28 08:58:52 +0300
committerTristan Matthews <tmatth@videolan.org>2019-06-19 05:33:47 +0300
commit56baf7ca631480fb8b7427333d317593c8f38488 (patch)
treeb0a0b978f2a473834f3adaf974f4fa14a7cd6035
parentc1f82d214872cae4a60c2594cc8c53d11246e3a9 (diff)
Add oss-fuzz decoder target
Co-Authored by Tyson Smith <twsmith@mozilla.com>
-rw-r--r--contrib/oss-fuzz/speexdec_fuzzer.cc331
1 files changed, 331 insertions, 0 deletions
diff --git a/contrib/oss-fuzz/speexdec_fuzzer.cc b/contrib/oss-fuzz/speexdec_fuzzer.cc
new file mode 100644
index 0000000..a9e2ebe
--- /dev/null
+++ b/contrib/oss-fuzz/speexdec_fuzzer.cc
@@ -0,0 +1,331 @@
+/* Copyright (C) 2019 Tristan Matthews
+ File: speexdec_fuzzer.cc (based on speexdec.c)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ - Neither the name of the Xiph.org Foundation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <ogg/ogg.h>
+
+#include <limits.h>
+#include <math.h>
+
+#include <string.h>
+#include "speex/speex_header.h"
+#include "speex/speex_stereo.h"
+#include "speex/speex_callbacks.h"
+
+#define MAX_FRAME_SIZE 2000
+
+#ifndef DISABLE_FLOAT_API
+ typedef float output_type;
+ #define speex_decode_func(a, b, c) speex_decode(a, b, c)
+ #define speex_decode_stereo_func(a, b, c) speex_decode_stereo(a, b, c)
+#else
+ typedef spx_int16_t output_type;
+ #define speex_decode_func(a, b, c) speex_decode_int(a, b, c)
+ #define speex_decode_stereo_func(a, b, c) speex_decode_stereo_int(a, b, c)
+#endif
+
+static void *process_header(ogg_packet *op, spx_int32_t enh_enabled, spx_int32_t *frame_size, int *granule_frame_size, spx_int32_t *rate, int *nframes, int *channels, SpeexStereoState *stereo, int *extra_headers)
+{
+ void *st;
+ const SpeexMode *mode;
+ SpeexHeader *header;
+ int modeID;
+ SpeexCallback callback;
+
+ header = speex_packet_to_header((char*)op->packet, op->bytes);
+ if (!header)
+ {
+ return NULL;
+ }
+ if (header->mode >= SPEEX_NB_MODES || header->mode<0)
+ {
+ free(header);
+ return NULL;
+ }
+
+ modeID = header->mode;
+
+ mode = speex_lib_get_mode (modeID);
+
+ if (header->speex_version_id > 1)
+ {
+ free(header);
+ return NULL;
+ }
+
+ if (mode->bitstream_version < header->mode_bitstream_version)
+ {
+ free(header);
+ return NULL;
+ }
+ if (mode->bitstream_version > header->mode_bitstream_version)
+ {
+ free(header);
+ return NULL;
+ }
+
+ st = speex_decoder_init(mode);
+ if (!st)
+ {
+ free(header);
+ return NULL;
+ }
+ speex_decoder_ctl(st, SPEEX_SET_ENH, &enh_enabled);
+ speex_decoder_ctl(st, SPEEX_GET_FRAME_SIZE, frame_size);
+ if (*frame_size < 0 || *frame_size > 2*320)
+ {
+ free(header);
+ return NULL;
+ }
+ *granule_frame_size = *frame_size;
+
+ if (!*rate)
+ *rate = header->rate;
+
+ speex_decoder_ctl(st, SPEEX_SET_SAMPLING_RATE, rate);
+
+ if (header->frames_per_packet < 1 || header->frames_per_packet > 10)
+ {
+ free(header);
+ return NULL;
+ }
+ *nframes = header->frames_per_packet;
+
+ if (*channels==-1)
+ *channels = header->nb_channels;
+
+ if (!(*channels==1))
+ {
+ *channels = 2;
+ callback.callback_id = SPEEX_INBAND_STEREO;
+ callback.func = speex_std_stereo_request_handler;
+ callback.data = stereo;
+ speex_decoder_ctl(st, SPEEX_SET_HANDLER, &callback);
+ }
+
+ if (header->extra_headers > INT_MAX - 1)
+ {
+ free(header);
+ return NULL;
+ }
+ *extra_headers = header->extra_headers;
+
+ free(header);
+ return st;
+}
+
+static void cleanup(void *st, SpeexBits *bits, int stream_init, ogg_stream_state *os, ogg_sync_state *oy)
+{
+ if (st)
+ speex_decoder_destroy(st);
+
+ speex_bits_destroy(bits);
+ if (stream_init)
+ ogg_stream_clear(os);
+ ogg_sync_clear(oy);
+}
+
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *fuzz_data, size_t fuzz_size)
+{
+ output_type output[MAX_FRAME_SIZE];
+ int frame_size=0, granule_frame_size=0;
+ void *st=NULL;
+ SpeexBits bits;
+ int packet_count=0;
+ int stream_init = 0;
+ ogg_int64_t page_granule=0, last_granule=0;
+ int skip_samples=0, page_nb_packets;
+ ogg_sync_state oy;
+ ogg_page og;
+ ogg_packet op;
+ ogg_stream_state os;
+ int enh_enabled;
+ int nframes=2;
+ int eos=0;
+ SpeexStereoState stereo = SPEEX_STEREO_STATE_INIT;
+ int channels=-1;
+ int rate=0;
+ int extra_headers=0;
+ int lookahead;
+ int speex_serialno = -1;
+
+ enh_enabled = 1;
+
+ /*Init Ogg data struct*/
+ ogg_sync_init(&oy);
+
+ speex_bits_init(&bits);
+ /*Main decoding loop*/
+
+ ssize_t bytes_remaining = fuzz_size;
+ while (1)
+ {
+ char *data;
+ int j, nb_read;
+ /*Get the ogg buffer for writing*/
+ nb_read = bytes_remaining > 200 ? 200 : bytes_remaining;
+ data = ogg_sync_buffer(&oy, nb_read);
+ /*Read bitstream from data*/
+ memcpy(data, fuzz_data, nb_read);
+ ogg_sync_wrote(&oy, nb_read);
+ bytes_remaining -= nb_read;
+
+ /*Loop for all complete pages we got (most likely only one)*/
+ while (ogg_sync_pageout(&oy, &og)==1)
+ {
+ int packet_no;
+
+ if (stream_init == 0) {
+ ogg_stream_init(&os, ogg_page_serialno(&og));
+ stream_init = 1;
+ }
+ if (ogg_page_serialno(&og) != os.serialno) {
+ /* so all streams are read. */
+ ogg_stream_reset_serialno(&os, ogg_page_serialno(&og));
+ }
+
+ /*Add page to the bitstream*/
+ ogg_stream_pagein(&os, &og);
+ page_granule = ogg_page_granulepos(&og);
+ page_nb_packets = ogg_page_packets(&og);
+ if (page_granule>0 && frame_size)
+ {
+ /* FIXME: shift the granule values if --force-* is specified */
+ int64_t a = page_nb_packets*granule_frame_size*(int64_t)nframes;
+ int64_t b = page_granule - last_granule;
+ if (b > a || (a - b) > INT64_MAX/640)
+ {
+ cleanup(st, &bits, stream_init, &os, &oy);
+ return 0;
+ }
+ skip_samples = frame_size*(int64_t)(a - b)/granule_frame_size;
+ if (ogg_page_eos(&og))
+ skip_samples = -skip_samples;
+ /*else if (!ogg_page_bos(&og))
+ skip_samples = 0;*/
+ } else if (page_granule<-1) {
+ cleanup(st, &bits, stream_init, &os, &oy);
+ return 0;
+ } else {
+ skip_samples = 0;
+ }
+ last_granule = page_granule;
+ /*Extract all available packets*/
+ packet_no=0;
+ while (!eos && ogg_stream_packetout(&os, &op) == 1)
+ {
+ if (op.bytes>=5 && !memcmp(op.packet, "Speex", 5)) {
+ speex_serialno = os.serialno;
+ }
+ if (speex_serialno == -1 || os.serialno != speex_serialno)
+ break;
+ /*If first packet, process as Speex header*/
+ if (packet_count==0)
+ {
+ st = process_header(&op, enh_enabled, &frame_size, &granule_frame_size, &rate, &nframes, &channels, &stereo, &extra_headers);
+ if (!st)
+ {
+ cleanup(st, &bits, stream_init, &os, &oy);
+ return 0;
+ }
+ speex_decoder_ctl(st, SPEEX_GET_LOOKAHEAD, &lookahead);
+ if (!nframes)
+ nframes=1;
+
+ } else if (packet_count<=1+extra_headers)
+ {
+ /* Ignore extra headers */
+ } else {
+ packet_no++;
+
+ /*End of stream condition*/
+ if (op.e_o_s && os.serialno == speex_serialno) /* don't care for anything except speex eos */
+ eos=1;
+
+ /*Copy Ogg packet to Speex bitstream*/
+ speex_bits_read_from(&bits, (char*)op.packet, op.bytes);
+ for (j=0;j!=nframes;j++)
+ {
+ int ret;
+ /*Decode frame*/
+ ret = speex_decode_func(st, &bits, output);
+
+ if (ret==-1)
+ break;
+ if (ret==-2)
+ {
+ break;
+ }
+ if (speex_bits_remaining(&bits)<0)
+ {
+ break;
+ }
+ if (channels==2)
+ speex_decode_stereo_func(output, frame_size, &stereo);
+
+ {
+ int new_frame_size = frame_size;
+ if (packet_no == 1 && j==0 && skip_samples > 0)
+ {
+ new_frame_size -= skip_samples+lookahead;
+ }
+ if (packet_no == page_nb_packets && skip_samples < 0)
+ {
+ int packet_length = nframes*frame_size+skip_samples+lookahead;
+ new_frame_size = packet_length - j*frame_size;
+ if (new_frame_size<0)
+ new_frame_size = 0;
+ if (new_frame_size>frame_size)
+ new_frame_size = frame_size;
+ }
+ }
+ }
+ }
+ packet_count++;
+ }
+ }
+ if (bytes_remaining <= 0)
+ break;
+ }
+
+ cleanup(st, &bits, stream_init, &os, &oy);
+
+ return 0;
+}