#include "libavcodec/bytestream.h"
#include "libavformat/avformat.h"
+//For FF_SANE_NB_CHANNELS, so we dont waste energy testing things that will get instantly rejected
+#include "libavcodec/internal.h"
+
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
extern AVCodec * codec_list[];
return ret;
}
-// Class to handle buffer allocation and resize for each frame
-typedef struct FuzzDataBuffer {
- size_t size_;
- uint8_t *data_;
-} FuzzDataBuffer;
-
-static void FDBCreate(FuzzDataBuffer *FDB) {
- FDB->size_ = 0x1000;
- FDB->data_ = av_malloc(FDB->size_);
- if (!FDB->data_)
- error("Failed memory allocation");
-}
-
-static void FDBDesroy(FuzzDataBuffer *FDB) { av_free(FDB->data_); }
-
-static void FDBRealloc(FuzzDataBuffer *FDB, size_t size) {
- size_t needed = size + AV_INPUT_BUFFER_PADDING_SIZE;
- av_assert0(needed > size);
- if (needed > FDB->size_) {
- av_free(FDB->data_);
- FDB->size_ = needed;
- FDB->data_ = av_malloc(FDB->size_);
- if (!FDB->data_)
- error("Failed memory allocation");
- }
-}
-
-static void FDBPrepare(FuzzDataBuffer *FDB, AVPacket *dst, const uint8_t *data,
- size_t size)
-{
- FDBRealloc(FDB, size);
- memcpy(FDB->data_, data, size);
- size_t padd = FDB->size_ - size;
- if (padd > AV_INPUT_BUFFER_PADDING_SIZE)
- padd = AV_INPUT_BUFFER_PADDING_SIZE;
- memset(FDB->data_ + size, 0, padd);
- av_init_packet(dst);
- dst->data = FDB->data_;
- dst->size = size;
-}
-
// Ensure we don't loop forever
const uint32_t maxiteration = 8096;
+const uint64_t maxpixels_per_frame = 4096 * 4096;
+uint64_t maxpixels;
+
+const uint64_t maxsamples_per_frame = 256*1024*32;
+uint64_t maxsamples;
static const uint64_t FUZZ_TAG = 0x4741542D5A5A5546ULL;
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
const uint64_t fuzz_tag = FUZZ_TAG;
- FuzzDataBuffer buffer;
const uint8_t *last = data;
const uint8_t *end = data + size;
uint32_t it = 0;
+ uint64_t ec_pixels = 0;
+ uint64_t nb_samples = 0;
int (*decode_handler)(AVCodecContext *avctx, AVFrame *picture,
int *got_picture_ptr,
const AVPacket *avpkt) = NULL;
case AVMEDIA_TYPE_VIDEO : decode_handler = avcodec_decode_video2; break;
case AVMEDIA_TYPE_SUBTITLE: decode_handler = subtitle_handler ; break;
}
+ maxpixels = maxpixels_per_frame * maxiteration;
+ maxsamples = maxsamples_per_frame * maxiteration;
+ switch (c->id) {
+ // Allows a small input to generate gigantic output
+ case AV_CODEC_ID_BINKVIDEO: maxpixels /= 32; break;
+ case AV_CODEC_ID_DIRAC: maxpixels /= 8192; break;
+ case AV_CODEC_ID_MSRLE: maxpixels /= 16; break;
+ case AV_CODEC_ID_QTRLE: maxpixels /= 16; break;
+ case AV_CODEC_ID_SANM: maxpixels /= 16; break;
+ case AV_CODEC_ID_GIF: maxpixels /= 16; break;
+ // Performs slow frame rescaling in C
+ case AV_CODEC_ID_GDV: maxpixels /= 512; break;
+ // Postprocessing in C
+ case AV_CODEC_ID_HNM4_VIDEO:maxpixels /= 128; break;
+ // Cliping in C, generally slow even with small input
+ case AV_CODEC_ID_INDEO4: maxpixels /= 128; break;
+ case AV_CODEC_ID_LSCR: maxpixels /= 16; break;
+ case AV_CODEC_ID_MOTIONPIXELS:maxpixels /= 256; break;
+ case AV_CODEC_ID_MSS2: maxpixels /= 16384; break;
+ case AV_CODEC_ID_SNOW: maxpixels /= 128; break;
+ case AV_CODEC_ID_TRUEMOTION2: maxpixels /= 1024; break;
+ case AV_CODEC_ID_VP7: maxpixels /= 256; break;
+ }
- AVCodecContext* ctx = avcodec_alloc_context3(NULL);
+
+ AVCodecContext* ctx = avcodec_alloc_context3(c);
AVCodecContext* parser_avctx = avcodec_alloc_context3(NULL);
if (!ctx || !parser_avctx)
error("Failed memory allocation");
- ctx->max_pixels = 4096 * 4096; //To reduce false positive OOM and hangs
+ if (ctx->max_pixels == 0 || ctx->max_pixels > maxpixels_per_frame)
+ ctx->max_pixels = maxpixels_per_frame; //To reduce false positive OOM and hangs
+ ctx->refcounted_frames = 1; //To reduce false positive timeouts and focus testing on the refcounted API
+
+ ctx->max_samples = maxsamples_per_frame;
if (size > 1024) {
GetByteContext gbc;
- bytestream2_init(&gbc, data + size - 1024, 1024);
+ int extradata_size;
+ size -= 1024;
+ bytestream2_init(&gbc, data + size, 1024);
ctx->width = bytestream2_get_le32(&gbc);
ctx->height = bytestream2_get_le32(&gbc);
ctx->bit_rate = bytestream2_get_le64(&gbc);
// Try to initialize a parser for this codec, note, this may fail which just means we test without one
if (bytestream2_get_byte(&gbc) & 1)
parser = av_parser_init(c->id);
+
+ extradata_size = bytestream2_get_le32(&gbc);
+
+ ctx->sample_rate = bytestream2_get_le32(&gbc);
+ ctx->channels = (unsigned)bytestream2_get_le32(&gbc) % FF_SANE_NB_CHANNELS;
+
+ if (extradata_size < size) {
+ ctx->extradata = av_mallocz(extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
+ if (ctx->extradata) {
+ ctx->extradata_size = extradata_size;
+ size -= ctx->extradata_size;
+ memcpy(ctx->extradata, data + size, ctx->extradata_size);
+ }
+ }
if (av_image_check_size(ctx->width, ctx->height, 0, ctx))
ctx->width = ctx->height = 0;
- size -= 1024;
}
int res = avcodec_open2(ctx, c, NULL);
if (res < 0) {
- av_free(ctx);
+ avcodec_free_context(&ctx);
av_free(parser_avctx);
+ av_parser_close(parser);
return 0; // Failure of avcodec_open2() does not imply that a issue was found
}
parser_avctx->codec_id = ctx->codec_id;
- FDBCreate(&buffer);
int got_frame;
AVFrame *frame = av_frame_alloc();
if (!frame)
// Read very simple container
AVPacket avpkt, parsepkt;
+ av_init_packet(&avpkt);
+ av_init_packet(&parsepkt);
while (data < end && it < maxiteration) {
// Search for the TAG
while (data + sizeof(fuzz_tag) < end) {
if (data + sizeof(fuzz_tag) > end)
data = end;
- FDBPrepare(&buffer, &parsepkt, last, data - last);
+ res = av_new_packet(&parsepkt, data - last);
+ if (res < 0)
+ error("Failed memory allocation");
+ memcpy(parsepkt.data, last, data - last);
data += sizeof(fuzz_tag);
last = data;
int ret = av_parser_parse2(parser, parser_avctx, &avpkt.data, &avpkt.size,
parsepkt.data, parsepkt.size,
parsepkt.pts, parsepkt.dts, parsepkt.pos);
+ if (avpkt.data == parsepkt.data) {
+ avpkt.buf = av_buffer_ref(parsepkt.buf);
+ if (!avpkt.buf)
+ error("Failed memory allocation");
+ } else {
+ if (av_packet_make_refcounted(&avpkt) < 0)
+ error("Failed memory allocation");
+ }
parsepkt.data += ret;
parsepkt.size -= ret;
parsepkt.pos += ret;
avpkt.flags |= AV_PKT_FLAG_KEY;
avpkt.flags |= parsepkt.flags & AV_PKT_FLAG_DISCARD;
} else {
- avpkt = parsepkt;
- parsepkt.size = 0;
+ av_packet_move_ref(&avpkt, &parsepkt);
}
// Iterate through all data
av_frame_unref(frame);
int ret = decode_handler(ctx, frame, &got_frame, &avpkt);
- if (it > 20)
+ ec_pixels += (ctx->width + 32LL) * (ctx->height + 32LL);
+ if (it > 20 || ec_pixels > 4 * ctx->max_pixels)
ctx->error_concealment = 0;
+ if (ec_pixels > maxpixels)
+ goto maximums_reached;
+
+ nb_samples += frame->nb_samples;
+ if (nb_samples > maxsamples)
+ goto maximums_reached;
if (ret <= 0 || ret > avpkt.size)
break;
avpkt.data += ret;
avpkt.size -= ret;
}
+ av_packet_unref(&avpkt);
}
+ av_packet_unref(&parsepkt);
}
+maximums_reached:
- av_init_packet(&avpkt);
- avpkt.data = NULL;
- avpkt.size = 0;
+ av_packet_unref(&avpkt);
do {
got_frame = 0;
+ av_frame_unref(frame);
decode_handler(ctx, frame, &got_frame, &avpkt);
} while (got_frame == 1 && it++ < maxiteration);
+ fprintf(stderr, "pixels decoded: %"PRId64", samples decoded: %"PRId64", iterations: %d\n", ec_pixels, nb_samples, it);
+
av_frame_free(&frame);
avcodec_free_context(&ctx);
- av_freep(&ctx);
avcodec_free_context(&parser_avctx);
- av_freep(&parser_avctx);
av_parser_close(parser);
- FDBDesroy(&buffer);
+ av_packet_unref(&parsepkt);
return 0;
}