]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/smacker.c
avcodec: Constify AVCodecs
[ffmpeg] / libavcodec / smacker.c
index 27de30f0e1926f41cb671332eafeeab92e668c75..75ab5d71205eb69afa0f7e1c777ca7b4e806cc1d 100644 (file)
 
 #include "libavutil/channel_layout.h"
 
-#define BITSTREAM_READER_LE
 #include "avcodec.h"
-#include "bytestream.h"
-#include "get_bits.h"
-#include "internal.h"
-#include "mathops.h"
 
 #define SMKTREE_BITS 9
 #define SMK_NODE 0x80000000
 
-#define SMKTREE_DECODE_MAX_RECURSION 32
+#define SMKTREE_DECODE_MAX_RECURSION FFMIN(32, 3 * SMKTREE_BITS)
 #define SMKTREE_DECODE_BIG_MAX_RECURSION 500
 
+/* The maximum possible unchecked overread happens in decode_header_trees:
+ * Decoding the MMAP tree can overread by 6 * SMKTREE_BITS + 1, followed by
+ * three get_bits1, followed by at most 2 + 3 * 16 read bits when reading
+ * the TYPE tree before the next check. 64 is because of 64 bit reads. */
+#if (6 * SMKTREE_BITS + 1 + 3 + (2 + 3 * 16) + 64) <= 8 * AV_INPUT_BUFFER_PADDING_SIZE
+#define UNCHECKED_BITSTREAM_READER 1
+#endif
+#define BITSTREAM_READER_LE
+#include "bytestream.h"
+#include "get_bits.h"
+#include "internal.h"
+#include "mathops.h"
+
 typedef struct SmackVContext {
     AVCodecContext *avctx;
     AVFrame *pic;
@@ -54,21 +62,25 @@ typedef struct SmackVContext {
     int mmap_last[3], mclr_last[3], full_last[3], type_last[3];
 } SmackVContext;
 
+typedef struct HuffEntry {
+    uint8_t value;
+    uint8_t length;
+} HuffEntry;
+
 /**
  * Context used for code reconstructing
  */
 typedef struct HuffContext {
-    int length;
     int current;
-    uint32_t *bits;
-    int *lengths;
-    int *values;
+    HuffEntry entries[256];
 } HuffContext;
 
 /* common parameters used for decode_bigtree */
 typedef struct DBCtx {
+    int current, length;
+    int *values;
     VLC *v1, *v2;
-    int *recode1, *recode2;
+    uint8_t vals[2];
     int escapes[3];
     int *last;
 } DBCtx;
@@ -92,8 +104,11 @@ enum SmkBlockTypes {
 
 /**
  * Decode local frame tree
+ *
+ * Can read SMKTREE_DECODE_MAX_RECURSION before the first check;
+ * does not overread gb on success.
  */
-static int smacker_decode_tree(GetBitContext *gb, HuffContext *hc, uint32_t prefix, int length)
+static int smacker_decode_tree(GetBitContext *gb, HuffContext *hc, int length)
 {
     if (length > SMKTREE_DECODE_MAX_RECURSION || length > 3 * SMKTREE_BITS) {
         av_log(NULL, AV_LOG_ERROR, "Maximum tree recursion level exceeded.\n");
@@ -101,35 +116,30 @@ static int smacker_decode_tree(GetBitContext *gb, HuffContext *hc, uint32_t pref
     }
 
     if(!get_bits1(gb)){ //Leaf
-        if(hc->current >= hc->length){
+        if (hc->current >= 256) {
             av_log(NULL, AV_LOG_ERROR, "Tree size exceeded!\n");
             return AVERROR_INVALIDDATA;
         }
-        if(length){
-            hc->bits[hc->current] = prefix;
-            hc->lengths[hc->current] = length;
-        } else {
-            hc->bits[hc->current] = 0;
-            hc->lengths[hc->current] = 0;
-        }
-        hc->values[hc->current] = get_bits(gb, 8);
-        hc->current++;
+        if (get_bits_left(gb) < 8)
+            return AVERROR_INVALIDDATA;
+        hc->entries[hc->current++] = (HuffEntry){ get_bits(gb, 8), length };
         return 0;
     } else { //Node
         int r;
         length++;
-        r = smacker_decode_tree(gb, hc, prefix, length);
+        r = smacker_decode_tree(gb, hc, length);
         if(r)
             return r;
-        return smacker_decode_tree(gb, hc, prefix | (1U << (length - 1)), length);
+        return smacker_decode_tree(gb, hc, length);
     }
 }
 
 /**
  * Decode header tree
+ *
+ * Checks before the first read, can overread by 6 * SMKTREE_BITS on success.
  */
-static int smacker_decode_bigtree(GetBitContext *gb, HuffContext *hc,
-                                  DBCtx *ctx, int length)
+static int smacker_decode_bigtree(GetBitContext *gb, DBCtx *ctx, int length)
 {
     // Larger length can cause segmentation faults due to too deep recursion.
     if (length > SMKTREE_DECODE_BIG_MAX_RECURSION) {
@@ -137,40 +147,42 @@ static int smacker_decode_bigtree(GetBitContext *gb, HuffContext *hc,
         return AVERROR_INVALIDDATA;
     }
 
-    if (hc->current >= hc->length) {
+    if (ctx->current >= ctx->length) {
         av_log(NULL, AV_LOG_ERROR, "Tree size exceeded!\n");
         return AVERROR_INVALIDDATA;
     }
+    if (get_bits_left(gb) <= 0)
+        return AVERROR_INVALIDDATA;
     if(!get_bits1(gb)){ //Leaf
         int val, i1, i2;
-        i1 = ctx->v1->table ? get_vlc2(gb, ctx->v1->table, SMKTREE_BITS, 3) : 0;
-        i2 = ctx->v2->table ? get_vlc2(gb, ctx->v2->table, SMKTREE_BITS, 3) : 0;
-        if (i1 < 0 || i2 < 0)
-            return AVERROR_INVALIDDATA;
-        val = ctx->recode1[i1] | (ctx->recode2[i2] << 8);
+        i1 = ctx->v1->table ? get_vlc2(gb, ctx->v1->table, SMKTREE_BITS, 3)
+                            : ctx->vals[0];
+        i2 = ctx->v2->table ? get_vlc2(gb, ctx->v2->table, SMKTREE_BITS, 3)
+                            : ctx->vals[1];
+        val = i1 | (i2 << 8);
         if(val == ctx->escapes[0]) {
-            ctx->last[0] = hc->current;
+            ctx->last[0] = ctx->current;
             val = 0;
         } else if(val == ctx->escapes[1]) {
-            ctx->last[1] = hc->current;
+            ctx->last[1] = ctx->current;
             val = 0;
         } else if(val == ctx->escapes[2]) {
-            ctx->last[2] = hc->current;
+            ctx->last[2] = ctx->current;
             val = 0;
         }
 
-        hc->values[hc->current++] = val;
+        ctx->values[ctx->current++] = val;
         return 1;
     } else { //Node
         int r = 0, r_new, t;
 
-        t = hc->current++;
-        r = smacker_decode_bigtree(gb, hc, ctx, length + 1);
+        t = ctx->current++;
+        r = smacker_decode_bigtree(gb, ctx, length + 1);
         if(r < 0)
             return r;
-        hc->values[t] = SMK_NODE | r;
+        ctx->values[t] = SMK_NODE | r;
         r++;
-        r_new = smacker_decode_bigtree(gb, hc, ctx, length + 1);
+        r_new = smacker_decode_bigtree(gb, ctx, length + 1);
         if (r_new < 0)
             return r_new;
         return r + r_new;
@@ -179,11 +191,12 @@ static int smacker_decode_bigtree(GetBitContext *gb, HuffContext *hc,
 
 /**
  * Store large tree as FFmpeg's vlc codes
+ *
+ * Can read FFMAX(1 + SMKTREE_DECODE_MAX_RECURSION, 2 + 3 * 16) bits
+ * before the first check; can overread by 6 * SMKTREE_BITS + 1 on success.
  */
 static int smacker_decode_header_tree(SmackVContext *smk, GetBitContext *gb, int **recodes, int *last, int size)
 {
-    HuffContext huff;
-    HuffContext h[2] = { 0 };
     VLC vlc[2] = { { 0 } };
     int escapes[3];
     DBCtx ctx;
@@ -195,34 +208,29 @@ static int smacker_decode_header_tree(SmackVContext *smk, GetBitContext *gb, int
     }
 
     for (int i = 0; i < 2; i++) {
-        h[i].length  = 256;
-        h[i].current = 0;
-        h[i].bits    = av_mallocz(256 * sizeof(h[i].bits[0]));
-        h[i].lengths = av_mallocz(256 * sizeof(h[i].lengths[0]));
-        h[i].values  = av_mallocz(256 * sizeof(h[i].values[0]));
-        if (!h[i].bits || !h[i].lengths || !h[i].values) {
-            err = AVERROR(ENOMEM);
-            goto error;
-        }
+        HuffContext h;
+        h.current = 0;
         if (!get_bits1(gb)) {
+            ctx.vals[i] = 0;
             av_log(smk->avctx, AV_LOG_ERROR, "Skipping %s bytes tree\n",
                    i ? "high" : "low");
             continue;
         }
-        err = smacker_decode_tree(gb, &h[i], 0, 0);
+        err = smacker_decode_tree(gb, &h, 0);
         if (err < 0)
             goto error;
         skip_bits1(gb);
-        if (h[i].current > 1) {
-            err = init_vlc(&vlc[i], SMKTREE_BITS, h[i].current,
-                           INIT_VLC_DEFAULT_SIZES(h[i].lengths),
-                           INIT_VLC_DEFAULT_SIZES(h[i].bits),
-                           INIT_VLC_LE);
+        if (h.current > 1) {
+            err = ff_init_vlc_from_lengths(&vlc[i], SMKTREE_BITS, h.current,
+                                           &h.entries[0].length, sizeof(*h.entries),
+                                           &h.entries[0].value,  sizeof(*h.entries), 1,
+                                           0, INIT_VLC_OUTPUT_LE, smk->avctx);
             if (err < 0) {
                 av_log(smk->avctx, AV_LOG_ERROR, "Cannot build VLC table\n");
                 goto error;
             }
-        }
+        } else
+            ctx.vals[i] = h.entries[0].value;
     }
 
     escapes[0]  = get_bits(gb, 16);
@@ -236,35 +244,28 @@ static int smacker_decode_header_tree(SmackVContext *smk, GetBitContext *gb, int
     ctx.escapes[2] = escapes[2];
     ctx.v1 = &vlc[0];
     ctx.v2 = &vlc[1];
-    ctx.recode1 = h[0].values;
-    ctx.recode2 = h[1].values;
     ctx.last = last;
-
-    huff.length = (size + 3) >> 2;
-    huff.current = 0;
-    huff.values = av_mallocz_array(huff.length + 3, sizeof(huff.values[0]));
-    if (!huff.values) {
+    ctx.length  = (size + 3) >> 2;
+    ctx.current = 0;
+    ctx.values  = av_malloc_array(ctx.length + 3, sizeof(ctx.values[0]));
+    if (!ctx.values) {
         err = AVERROR(ENOMEM);
         goto error;
     }
-    *recodes = huff.values;
+    *recodes = ctx.values;
 
-    err = smacker_decode_bigtree(gb, &huff, &ctx, 0);
+    err = smacker_decode_bigtree(gb, &ctx, 0);
     if (err < 0)
         goto error;
     skip_bits1(gb);
-    if(ctx.last[0] == -1) ctx.last[0] = huff.current++;
-    if(ctx.last[1] == -1) ctx.last[1] = huff.current++;
-    if(ctx.last[2] == -1) ctx.last[2] = huff.current++;
+    if (ctx.last[0] == -1) ctx.last[0] = ctx.current++;
+    if (ctx.last[1] == -1) ctx.last[1] = ctx.current++;
+    if (ctx.last[2] == -1) ctx.last[2] = ctx.current++;
 
     err = 0;
 error:
     for (int i = 0; i < 2; i++) {
-        if (vlc[i].table)
-            ff_free_vlc(&vlc[i]);
-        av_free(h[i].bits);
-        av_free(h[i].lengths);
-        av_free(h[i].values);
+        ff_free_vlc(&vlc[i]);
     }
 
     return err;
@@ -336,7 +337,7 @@ static int decode_header_trees(SmackVContext *smk) {
         if (ret < 0)
             return ret;
     }
-    if (skip == 4)
+    if (skip == 4 || get_bits_left(&gb) < 0)
         return AVERROR_INVALIDDATA;
 
     return 0;
@@ -346,7 +347,8 @@ static av_always_inline void last_reset(int *recode, int *last) {
     recode[last[0]] = recode[last[1]] = recode[last[2]] = 0;
 }
 
-/* get code and update history */
+/* Get code and update history.
+ * Checks before reading, does not overread. */
 static av_always_inline int smk_get_code(GetBitContext *gb, int *recode, int *last) {
     register int *table = recode;
     int v;
@@ -445,6 +447,8 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
         case SMK_BLK_FULL:
             mode = 0;
             if(avctx->codec_tag == MKTAG('S', 'M', 'K', '4')) { // In case of Smacker v4 we have three modes
+                if (get_bits_left(&gb) < 1)
+                    return AVERROR_INVALIDDATA;
                 if(get_bits1(&gb)) mode = 1;
                 else if(get_bits1(&gb)) mode = 2;
             }
@@ -552,7 +556,7 @@ static av_cold int decode_init(AVCodecContext *avctx)
         return AVERROR(ENOMEM);
 
     /* decode huffman trees from extradata */
-    if(avctx->extradata_size < 16){
+    if (avctx->extradata_size <= 16){
         av_log(avctx, AV_LOG_ERROR, "Extradata missing!\n");
         return AVERROR(EINVAL);
     }
@@ -588,15 +592,14 @@ static int smka_decode_frame(AVCodecContext *avctx, void *data,
     const uint8_t *buf = avpkt->data;
     int buf_size = avpkt->size;
     GetBitContext gb;
-    HuffContext h[4] = { { 0 } };
     VLC vlc[4]       = { { 0 } };
     int16_t *samples;
     uint8_t *samples8;
-    int val;
+    uint8_t values[4];
     int i, res, ret;
     int unp_size;
     int bits, stereo;
-    int pred[2] = {0, 0};
+    unsigned pred[2], val;
 
     if (buf_size <= 4) {
         av_log(avctx, AV_LOG_ERROR, "packet is too small\n");
@@ -643,87 +646,48 @@ static int smka_decode_frame(AVCodecContext *avctx, void *data,
 
     // Initialize
     for(i = 0; i < (1 << (bits + stereo)); i++) {
-        h[i].length = 256;
-        h[i].current = 0;
-        h[i].bits = av_mallocz(256 * 4);
-        h[i].lengths = av_mallocz(256 * sizeof(int));
-        h[i].values = av_mallocz(256 * sizeof(int));
-        if (!h[i].bits || !h[i].lengths || !h[i].values) {
-            ret = AVERROR(ENOMEM);
-            goto error;
-        }
+        HuffContext h;
+        h.current = 0;
         skip_bits1(&gb);
-        if ((ret = smacker_decode_tree(&gb, &h[i], 0, 0)) < 0)
+        if ((ret = smacker_decode_tree(&gb, &h, 0)) < 0)
             goto error;
         skip_bits1(&gb);
-        if(h[i].current > 1) {
-            ret = init_vlc(&vlc[i], SMKTREE_BITS, h[i].current,
-                    h[i].lengths, sizeof(int), sizeof(int),
-                    h[i].bits, sizeof(uint32_t), sizeof(uint32_t), INIT_VLC_LE);
+        if (h.current > 1) {
+            ret = ff_init_vlc_from_lengths(&vlc[i], SMKTREE_BITS, h.current,
+                                           &h.entries[0].length, sizeof(*h.entries),
+                                           &h.entries[0].value,  sizeof(*h.entries), 1,
+                                           0, INIT_VLC_OUTPUT_LE, avctx);
             if (ret < 0) {
                 av_log(avctx, AV_LOG_ERROR, "Cannot build VLC table\n");
                 goto error;
             }
-        }
+        } else
+            values[i] = h.entries[0].value;
     }
     /* this codec relies on wraparound instead of clipping audio */
     if(bits) { //decode 16-bit data
         for(i = stereo; i >= 0; i--)
-            pred[i] = sign_extend(av_bswap16(get_bits(&gb, 16)), 16);
+            pred[i] = av_bswap16(get_bits(&gb, 16));
         for(i = 0; i <= stereo; i++)
             *samples++ = pred[i];
         for(; i < unp_size / 2; i++) {
+            unsigned idx = 2 * (i & stereo);
             if (get_bits_left(&gb) < 0) {
                 ret = AVERROR_INVALIDDATA;
                 goto error;
             }
-            if(i & stereo) {
-                if(vlc[2].table)
-                    res = get_vlc2(&gb, vlc[2].table, SMKTREE_BITS, 3);
-                else
-                    res = 0;
-                if (res < 0) {
-                    av_log(avctx, AV_LOG_ERROR, "invalid vlc\n");
-                    ret = AVERROR_INVALIDDATA;
-                    goto error;
-                }
-                val  = h[2].values[res];
-                if(vlc[3].table)
-                    res = get_vlc2(&gb, vlc[3].table, SMKTREE_BITS, 3);
-                else
-                    res = 0;
-                if (res < 0) {
-                    av_log(avctx, AV_LOG_ERROR, "invalid vlc\n");
-                    ret = AVERROR_INVALIDDATA;
-                    goto error;
-                }
-                val |= h[3].values[res] << 8;
-                pred[1] += (unsigned)sign_extend(val, 16);
-                *samples++ = pred[1];
-            } else {
-                if(vlc[0].table)
-                    res = get_vlc2(&gb, vlc[0].table, SMKTREE_BITS, 3);
-                else
-                    res = 0;
-                if (res < 0) {
-                    av_log(avctx, AV_LOG_ERROR, "invalid vlc\n");
-                    ret = AVERROR_INVALIDDATA;
-                    goto error;
-                }
-                val  = h[0].values[res];
-                if(vlc[1].table)
-                    res = get_vlc2(&gb, vlc[1].table, SMKTREE_BITS, 3);
-                else
-                    res = 0;
-                if (res < 0) {
-                    av_log(avctx, AV_LOG_ERROR, "invalid vlc\n");
-                    ret = AVERROR_INVALIDDATA;
-                    goto error;
-                }
-                val |= h[1].values[res] << 8;
-                pred[0] += (unsigned)sign_extend(val, 16);
-                *samples++ = pred[0];
-            }
+            if (vlc[idx].table)
+                res = get_vlc2(&gb, vlc[idx].table, SMKTREE_BITS, 3);
+            else
+                res = values[idx];
+            val  = res;
+            if (vlc[++idx].table)
+                res = get_vlc2(&gb, vlc[idx].table, SMKTREE_BITS, 3);
+            else
+                res = values[idx];
+            val |= res << 8;
+            pred[idx / 2] += val;
+            *samples++ = pred[idx / 2];
         }
     } else { //8-bit data
         for(i = stereo; i >= 0; i--)
@@ -731,35 +695,17 @@ static int smka_decode_frame(AVCodecContext *avctx, void *data,
         for(i = 0; i <= stereo; i++)
             *samples8++ = pred[i];
         for(; i < unp_size; i++) {
+            unsigned idx = i & stereo;
             if (get_bits_left(&gb) < 0) {
                 ret = AVERROR_INVALIDDATA;
                 goto error;
             }
-            if(i & stereo){
-                if(vlc[1].table)
-                    res = get_vlc2(&gb, vlc[1].table, SMKTREE_BITS, 3);
-                else
-                    res = 0;
-                if (res < 0) {
-                    av_log(avctx, AV_LOG_ERROR, "invalid vlc\n");
-                    ret = AVERROR_INVALIDDATA;
-                    goto error;
-                }
-                pred[1] += sign_extend(h[1].values[res], 8);
-                *samples8++ = pred[1];
-            } else {
-                if(vlc[0].table)
-                    res = get_vlc2(&gb, vlc[0].table, SMKTREE_BITS, 3);
-                else
-                    res = 0;
-                if (res < 0) {
-                    av_log(avctx, AV_LOG_ERROR, "invalid vlc\n");
-                    ret = AVERROR_INVALIDDATA;
-                    goto error;
-                }
-                pred[0] += sign_extend(h[0].values[res], 8);
-                *samples8++ = pred[0];
-            }
+            if (vlc[idx].table)
+                val = get_vlc2(&gb, vlc[idx].table, SMKTREE_BITS, 3);
+            else
+                val = values[idx];
+            pred[idx] += val;
+            *samples8++ = pred[idx];
         }
     }
 
@@ -768,17 +714,13 @@ static int smka_decode_frame(AVCodecContext *avctx, void *data,
 
 error:
     for(i = 0; i < 4; i++) {
-        if(vlc[i].table)
-            ff_free_vlc(&vlc[i]);
-        av_free(h[i].bits);
-        av_free(h[i].lengths);
-        av_free(h[i].values);
+        ff_free_vlc(&vlc[i]);
     }
 
     return ret;
 }
 
-AVCodec ff_smacker_decoder = {
+const AVCodec ff_smacker_decoder = {
     .name           = "smackvid",
     .long_name      = NULL_IF_CONFIG_SMALL("Smacker video"),
     .type           = AVMEDIA_TYPE_VIDEO,
@@ -788,10 +730,10 @@ AVCodec ff_smacker_decoder = {
     .close          = decode_end,
     .decode         = decode_frame,
     .capabilities   = AV_CODEC_CAP_DR1,
-    .caps_internal  = FF_CODEC_CAP_INIT_CLEANUP,
+    .caps_internal  = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_INIT_THREADSAFE,
 };
 
-AVCodec ff_smackaud_decoder = {
+const AVCodec ff_smackaud_decoder = {
     .name           = "smackaud",
     .long_name      = NULL_IF_CONFIG_SMALL("Smacker audio"),
     .type           = AVMEDIA_TYPE_AUDIO,
@@ -799,4 +741,5 @@ AVCodec ff_smackaud_decoder = {
     .init           = smka_decode_init,
     .decode         = smka_decode_frame,
     .capabilities   = AV_CODEC_CAP_DR1,
+    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE,
 };