Merge commit 'b8b809908ec547b2609dbac24194f4fd2df61aea'
authorMichael Niedermayer <michaelni@gmx.at>
Thu, 13 Jun 2013 10:21:36 +0000 (12:21 +0200)
committerMichael Niedermayer <michaelni@gmx.at>
Thu, 13 Jun 2013 10:24:00 +0000 (12:24 +0200)
* commit 'b8b809908ec547b2609dbac24194f4fd2df61aea':
  4xm: forward errors from decode_p_block

Conflicts:
libavcodec/4xm.c

Impossible to be false check has been replaced by av_assert0()

Merged-by: Michael Niedermayer <michaelni@gmx.at>
1  2 
libavcodec/4xm.c

diff --combined libavcodec/4xm.c
index 096a8db7f7795759a184a59b38787a717a77806e,4a293ebda2bc0b0f5d29b59055604a4bc9e370f4..dc359c107fb3ddbaa2e1ccce35d33fce7a660774
@@@ -2,20 -2,20 +2,20 @@@
   * 4XM codec
   * Copyright (c) 2003 Michael Niedermayer
   *
 - * This file is part of Libav.
 + * This file is part of FFmpeg.
   *
 - * Libav is free software; you can redistribute it and/or
 + * FFmpeg is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
 - * Libav is distributed in the hope that it will be useful,
 + * FFmpeg is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
 - * License along with Libav; if not, write to the Free Software
 + * License along with FFmpeg; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
   */
  
@@@ -24,7 -24,6 +24,7 @@@
   * 4XM codec.
   */
  
 +#include "libavutil/avassert.h"
  #include "libavutil/frame.h"
  #include "libavutil/intreadwrite.h"
  #include "avcodec.h"
@@@ -33,7 -32,6 +33,7 @@@
  #include "get_bits.h"
  #include "internal.h"
  
 +
  #define BLOCK_TYPE_VLC_BITS 5
  #define ACDC_VLC_BITS 9
  
@@@ -131,7 -129,7 +131,7 @@@ typedef struct CFrameBuffer 
  typedef struct FourXContext {
      AVCodecContext *avctx;
      DSPContext dsp;
 -    AVFrame *last_picture;
 +    AVFrame *current_picture, *last_picture;
      GetBitContext pre_gb;          ///< ac/dc prefix
      GetBitContext gb;
      GetByteContext g;
@@@ -285,7 -283,7 +285,7 @@@ static void init_mv(FourXContext *f, in
      }
  #endif
  
 -static inline void mcdc(uint16_t *dst, uint16_t *src, int log2w,
 +static inline void mcdc(uint16_t *dst, const uint16_t *src, int log2w,
                          int h, int stride, int scale, unsigned dc)
  {
      int i;
          }
          break;
      default:
 -        assert(0);
 +        av_assert2(0);
      }
  }
  
- static void decode_p_block(FourXContext *f, uint16_t *dst, uint16_t *src,
-                            int log2w, int log2h, int stride)
+ static int decode_p_block(FourXContext *f, uint16_t *dst, uint16_t *src,
+                           int log2w, int log2h, int stride)
  {
      const int index = size2index[log2h][log2w];
      const int h     = 1 << log2h;
                                 BLOCK_TYPE_VLC_BITS, 1);
      uint16_t *start = (uint16_t *)f->last_picture->data[0];
      uint16_t *end   = start + stride * (f->avctx->height - h + 1) - (1 << log2w);
+     int ret;
  
-     av_assert2(code >= 0 && code <= 6);
 -    if (code < 0 || code > 6)
 -        return AVERROR_INVALIDDATA;
++    av_assert0(code >= 0 && code <= 6);
  
      if (code == 0) {
 -        src += f->mv[bytestream2_get_byte(&f->g)];
 +        if (bytestream2_get_bytes_left(&f->g) < 1) {
 +            av_log(f->avctx, AV_LOG_ERROR, "bytestream overread\n");
-             return;
++            return AVERROR_INVALIDDATA;
 +        }
 +        src += f->mv[bytestream2_get_byteu(&f->g)];
          if (start > src || src > end) {
              av_log(f->avctx, AV_LOG_ERROR, "mv out of pic\n");
-             return;
+             return AVERROR_INVALIDDATA;
          }
          mcdc(dst, src, log2w, h, stride, 1, 0);
      } else if (code == 1) {
          log2h--;
-         decode_p_block(f, dst, src, log2w, log2h, stride);
-         decode_p_block(f, dst + (stride << log2h),
-                           src + (stride << log2h), log2w, log2h, stride);
+         if ((ret = decode_p_block(f, dst, src, log2w, log2h, stride)) < 0)
+             return ret;
+         if ((ret = decode_p_block(f, dst + (stride << log2h),
+                                   src + (stride << log2h),
+                                   log2w, log2h, stride)) < 0)
+             return ret;
      } else if (code == 2) {
          log2w--;
-         decode_p_block(f, dst , src, log2w, log2h, stride);
-         decode_p_block(f, dst + (1 << log2w),
-                           src + (1 << log2w), log2w, log2h, stride);
+         if ((ret = decode_p_block(f, dst , src, log2w, log2h, stride)) < 0)
+             return ret;
+         if ((ret = decode_p_block(f, dst + (1 << log2w),
+                                   src + (1 << log2w),
+                                   log2w, log2h, stride)) < 0)
+             return ret;
      } else if (code == 3 && f->version < 2) {
          mcdc(dst, src, log2w, h, stride, 1, 0);
      } else if (code == 4) {
 -        src += f->mv[bytestream2_get_byte(&f->g)];
 +        if (bytestream2_get_bytes_left(&f->g) < 1) {
 +            av_log(f->avctx, AV_LOG_ERROR, "bytestream overread\n");
-             return;
++            return AVERROR_INVALIDDATA;
 +        }
 +        src += f->mv[bytestream2_get_byteu(&f->g)];
          if (start > src || src > end) {
              av_log(f->avctx, AV_LOG_ERROR, "mv out of pic\n");
-             return;
+             return AVERROR_INVALIDDATA;
          }
 -        mcdc(dst, src, log2w, h, stride, 1, bytestream2_get_le16(&f->g2));
 +        if (bytestream2_get_bytes_left(&f->g2) < 2){
 +            av_log(f->avctx, AV_LOG_ERROR, "wordstream overread\n");
-             return;
++            return AVERROR_INVALIDDATA;
 +        }
 +        mcdc(dst, src, log2w, h, stride, 1, bytestream2_get_le16u(&f->g2));
      } else if (code == 5) {
 -        mcdc(dst, src, log2w, h, stride, 0, bytestream2_get_le16(&f->g2));
 +        if (bytestream2_get_bytes_left(&f->g2) < 2) {
 +            av_log(f->avctx, AV_LOG_ERROR, "wordstream overread\n");
-             return;
++            return AVERROR_INVALIDDATA;
 +        }
 +        mcdc(dst, src, log2w, h, stride, 0, bytestream2_get_le16u(&f->g2));
      } else if (code == 6) {
-             return;
 +        if (bytestream2_get_bytes_left(&f->g2) < 4) {
 +            av_log(f->avctx, AV_LOG_ERROR, "wordstream overread\n");
++            return AVERROR_INVALIDDATA;
 +        }
          if (log2w) {
 -            dst[0]      = bytestream2_get_le16(&f->g2);
 -            dst[1]      = bytestream2_get_le16(&f->g2);
 +            dst[0]      = bytestream2_get_le16u(&f->g2);
 +            dst[1]      = bytestream2_get_le16u(&f->g2);
          } else {
 -            dst[0]      = bytestream2_get_le16(&f->g2);
 -            dst[stride] = bytestream2_get_le16(&f->g2);
 +            dst[0]      = bytestream2_get_le16u(&f->g2);
 +            dst[stride] = bytestream2_get_le16u(&f->g2);
          }
      }
+     return 0;
  }
  
  static int decode_p_frame(FourXContext *f, AVFrame *frame,
      if (!f->last_picture->data[0]) {
          if ((ret = ff_get_buffer(f->avctx, f->last_picture,
                                   AV_GET_BUFFER_FLAG_REF)) < 0) {
 -            av_log(f->avctx, AV_LOG_ERROR, "get_buffer() failed\n");
              return ret;
          }
 -        memset(f->last_picture->data[0], 0,
 -               f->avctx->height * FFABS(f->last_picture->linesize[0]));
 +        for (y=0; y<f->avctx->height; y++)
 +            memset(f->last_picture->data[0] + y*f->last_picture->linesize[0], 0, 2*f->avctx->width);
      }
  
      src = (uint16_t *)f->last_picture->data[0];
  
      if (f->version > 1) {
          extra           = 20;
 +        if (length < extra)
 +            return -1;
          bitstream_size  = AV_RL32(buf + 8);
          wordstream_size = AV_RL32(buf + 12);
          bytestream_size = AV_RL32(buf + 16);
          bytestream_size = FFMAX(length - bitstream_size - wordstream_size, 0);
      }
  
 -    if (bitstream_size + bytestream_size + wordstream_size + extra != length
 -        || bitstream_size  > (1 << 26)
 -        || bytestream_size > (1 << 26)
 -        || wordstream_size > (1 << 26)) {
 -        av_log(f->avctx, AV_LOG_ERROR, "lengths %d %d %d %d\n",
 -               bitstream_size, bytestream_size, wordstream_size,
 -               bitstream_size + bytestream_size + wordstream_size - length);
 +    if (bitstream_size > length || bitstream_size >= INT_MAX/8 ||
 +        bytestream_size > length - bitstream_size ||
 +        wordstream_size > length - bytestream_size - bitstream_size ||
 +        extra > length - bytestream_size - bitstream_size - wordstream_size) {
 +        av_log(f->avctx, AV_LOG_ERROR, "lengths %d %d %d %d\n", bitstream_size, bytestream_size, wordstream_size,
 +        bitstream_size+ bytestream_size+ wordstream_size - length);
          return AVERROR_INVALIDDATA;
      }
  
  
      for (y = 0; y < height; y += 8) {
          for (x = 0; x < width; x += 8)
-             decode_p_block(f, dst + x, src + x, 3, 3, stride);
+             if ((ret = decode_p_block(f, dst + x, src + x, 3, 3, stride)) < 0)
+                 return ret;
          src += 8 * stride;
          dst += 8 * stride;
      }
@@@ -489,11 -477,6 +498,11 @@@ static int decode_i_block(FourXContext 
  {
      int code, i, j, level, val;
  
 +    if (get_bits_left(&f->gb) < 2){
 +        av_log(f->avctx, AV_LOG_ERROR, "%d bits left before decode_i_block()\n", get_bits_left(&f->gb));
 +        return -1;
 +    }
 +
      /* DC coef */
      val = get_vlc2(&f->pre_gb, f->pre_vlc.table, ACDC_VLC_BITS, 3);
      if (val >> 4)
@@@ -594,7 -577,7 +603,7 @@@ static int decode_i_mb(FourXContext *f
  }
  
  static const uint8_t *read_huffman_tables(FourXContext *f,
 -                                          const uint8_t * const buf)
 +                                          const uint8_t * const buf, int buf_size)
  {
      int frequency[512] = { 0 };
      uint8_t flag[512];
      int bits_tab[257];
      int start, end;
      const uint8_t *ptr = buf;
 +    const uint8_t *ptr_end = buf + buf_size;
      int j;
  
      memset(up, -1, sizeof(up));
      for (;;) {
          int i;
  
 +        if (ptr_end - ptr < FFMAX(end - start + 1, 0) + 1) {
 +            av_log(f->avctx, AV_LOG_ERROR, "invalid data in read_huffman_tables\n");
 +            return NULL;
 +        }
          for (i = start; i <= end; i++)
              frequency[i] = *ptr++;
          start = *ptr++;
      while ((ptr - buf) & 3)
          ptr++; // 4byte align
  
 +    if (ptr > ptr_end) {
 +        av_log(f->avctx, AV_LOG_ERROR, "ptr overflow in read_huffman_tables\n");
 +        return NULL;
 +    }
 +
      for (j = 257; j < 512; j++) {
          int min_freq[2] = { 256 * 256, 256 * 256 };
          int smallest[2] = { 0, 0 };
@@@ -704,7 -677,6 +713,7 @@@ static int decode_i2_frame(FourXContex
      const int mbs    = (FFALIGN(width, 16) >> 4) * (FFALIGN(height, 16) >> 4);
      uint16_t *dst    = (uint16_t*)frame->data[0];
      const int stride =            frame->linesize[0]>>1;
 +    const uint8_t *buf_end = buf + length;
      GetByteContext g3;
  
      if (length < mbs * 8) {
      for (y = 0; y < height; y += 16) {
          for (x = 0; x < width; x += 16) {
              unsigned int color[4] = { 0 }, bits;
 +            if (buf_end - buf < 8)
 +                return -1;
              // warning following is purely guessed ...
              color[0] = bytestream2_get_le16u(&g3);
              color[1] = bytestream2_get_le16u(&g3);
@@@ -751,14 -721,16 +760,14 @@@ static int decode_i_frame(FourXContext 
      const int width  = f->avctx->width;
      const int height = f->avctx->height;
      const unsigned int bitstream_size = AV_RL32(buf);
 -    int token_count av_unused;
      unsigned int prestream_size;
      const uint8_t *prestream;
  
 -    if (length < bitstream_size + 12) {
 +    if (bitstream_size > (1<<26) || length < bitstream_size + 12) {
          av_log(f->avctx, AV_LOG_ERROR, "packet size too small\n");
          return AVERROR_INVALIDDATA;
      }
  
 -    token_count    =     AV_RL32(buf + bitstream_size + 8);
      prestream_size = 4 * AV_RL32(buf + bitstream_size + 4);
      prestream      =             buf + bitstream_size + 12;
  
          return AVERROR_INVALIDDATA;
      }
  
 -    prestream = read_huffman_tables(f, prestream);
 +    prestream = read_huffman_tables(f, prestream, buf + length - prestream);
      if (!prestream) {
          av_log(f->avctx, AV_LOG_ERROR, "Error reading Huffman tables.\n");
          return AVERROR_INVALIDDATA;
      }
  
 +    av_assert0(prestream <= buf + length);
 +
      init_get_bits(&f->gb, buf + 4, 8 * bitstream_size);
  
      prestream_size = length + buf - prestream;
@@@ -818,8 -788,6 +827,8 @@@ static int decode_frame(AVCodecContext 
      AVFrame *picture      = data;
      int i, frame_4cc, frame_size, ret;
  
 +    if (buf_size < 12)
 +        return AVERROR_INVALIDDATA;
      frame_4cc = AV_RL32(buf);
      if (buf_size != AV_RL32(buf + 4) + 8 || buf_size < 20)
          av_log(f->avctx, AV_LOG_ERROR, "size mismatch %d %d\n",
          const int whole_size = AV_RL32(buf + 16);
          CFrameBuffer *cfrm;
  
 +        if (data_size < 0 || whole_size < 0) {
 +            av_log(f->avctx, AV_LOG_ERROR, "sizes invalid\n");
 +            return AVERROR_INVALIDDATA;
 +        }
 +
 +        if (f->version <= 1) {
 +            av_log(f->avctx, AV_LOG_ERROR, "cfrm in version %d\n", f->version);
 +            return AVERROR_INVALIDDATA;
 +        }
 +
          for (i = 0; i < CFRAME_BUFFER_COUNT; i++)
              if (f->cfrm[i].id && f->cfrm[i].id < avctx->frame_number)
                  av_log(f->avctx, AV_LOG_ERROR, "lost c frame %d\n",
          }
          cfrm = &f->cfrm[i];
  
 +        if (data_size > UINT_MAX -  cfrm->size - FF_INPUT_BUFFER_PADDING_SIZE)
 +            return AVERROR_INVALIDDATA;
 +
          cfrm->data = av_fast_realloc(cfrm->data, &cfrm->allocated_size,
                                       cfrm->size + data_size + FF_INPUT_BUFFER_PADDING_SIZE);
          // explicit check needed as memcpy below might not catch a NULL
          if (!cfrm->data) {
 -            av_log(f->avctx, AV_LOG_ERROR, "realloc failure");
 +            av_log(f->avctx, AV_LOG_ERROR, "realloc failure\n");
              return AVERROR(ENOMEM);
          }
  
          frame_size = buf_size - 12;
      }
  
 +    FFSWAP(AVFrame*, f->current_picture, f->last_picture);
 +
      // alternatively we would have to use our own buffer management
      avctx->flags |= CODEC_FLAG_EMU_EDGE;
  
 -    if ((ret = ff_get_buffer(avctx, picture, AV_GET_BUFFER_FLAG_REF)) < 0) {
 -        av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
 +    if ((ret = ff_reget_buffer(avctx, f->current_picture)) < 0)
          return ret;
 -    }
  
      if (frame_4cc == AV_RL32("ifr2")) {
 -        picture->pict_type = AV_PICTURE_TYPE_I;
 -        if ((ret = decode_i2_frame(f, picture, buf - 4, frame_size + 4)) < 0)
 +        f->current_picture->pict_type = AV_PICTURE_TYPE_I;
 +        if ((ret = decode_i2_frame(f, f->current_picture, buf - 4, frame_size + 4)) < 0) {
 +            av_log(f->avctx, AV_LOG_ERROR, "decode i2 frame failed\n");
              return ret;
 +        }
      } else if (frame_4cc == AV_RL32("ifrm")) {
 -        picture->pict_type = AV_PICTURE_TYPE_I;
 -        if ((ret = decode_i_frame(f, picture, buf, frame_size)) < 0)
 +        f->current_picture->pict_type = AV_PICTURE_TYPE_I;
 +        if ((ret = decode_i_frame(f, f->current_picture, buf, frame_size)) < 0) {
 +            av_log(f->avctx, AV_LOG_ERROR, "decode i frame failed\n");
              return ret;
 +        }
      } else if (frame_4cc == AV_RL32("pfrm") || frame_4cc == AV_RL32("pfr2")) {
 -        picture->pict_type = AV_PICTURE_TYPE_P;
 -        if ((ret = decode_p_frame(f, picture, buf, frame_size)) < 0)
 +        f->current_picture->pict_type = AV_PICTURE_TYPE_P;
 +        if ((ret = decode_p_frame(f, f->current_picture, buf, frame_size)) < 0) {
 +            av_log(f->avctx, AV_LOG_ERROR, "decode p frame failed\n");
              return ret;
 +        }
      } else if (frame_4cc == AV_RL32("snd_")) {
          av_log(avctx, AV_LOG_ERROR, "ignoring snd_ chunk length:%d\n",
                 buf_size);
                 buf_size);
      }
  
 -    picture->key_frame = picture->pict_type == AV_PICTURE_TYPE_I;
 +    f->current_picture->key_frame = f->current_picture->pict_type == AV_PICTURE_TYPE_I;
  
 -    av_frame_unref(f->last_picture);
 -    if ((ret = av_frame_ref(f->last_picture, picture)) < 0)
 +    if ((ret = av_frame_ref(picture, f->current_picture)) < 0)
          return ret;
      *got_frame = 1;
  
@@@ -942,11 -892,7 +951,11 @@@ static av_cold int decode_init(AVCodecC
  
      if (avctx->extradata_size != 4 || !avctx->extradata) {
          av_log(avctx, AV_LOG_ERROR, "extradata wrong or missing\n");
 -        return 1;
 +        return AVERROR_INVALIDDATA;
 +    }
 +    if((avctx->width % 16) || (avctx->height % 16)) {
 +        av_log(avctx, AV_LOG_ERROR, "unsupported width/height\n");
 +        return AVERROR_INVALIDDATA;
      }
  
      f->version = AV_RL32(avctx->extradata) >> 16;
      else
          avctx->pix_fmt = AV_PIX_FMT_BGR555;
  
 -    f->last_picture = av_frame_alloc();
 -    if (!f->last_picture)
 +    f->current_picture = av_frame_alloc();
 +    f->last_picture    = av_frame_alloc();
 +    if (!f->current_picture  || !f->last_picture)
          return AVERROR(ENOMEM);
  
      return 0;
@@@ -980,7 -925,6 +989,7 @@@ static av_cold int decode_end(AVCodecCo
          f->cfrm[i].allocated_size = 0;
      }
      ff_free_vlc(&f->pre_vlc);
 +    av_frame_free(&f->current_picture);
      av_frame_free(&f->last_picture);
  
      return 0;