diff --git a/libavcodec/rpza.c b/libavcodec/rpza.c index f365a06fb9..d1c959d6e1 100644 --- a/libavcodec/rpza.c +++ b/libavcodec/rpza.c @@ -52,23 +52,25 @@ typedef struct RpzaContext { GetByteContext gb; } RpzaContext; -#define ADVANCE_BLOCK() \ -{ \ - pixel_ptr += 4; \ - if (pixel_ptr >= width) \ - { \ - pixel_ptr = 0; \ - row_ptr += stride * 4; \ - } \ - total_blocks--; \ - if (total_blocks < 0) \ - { \ - av_log(s->avctx, AV_LOG_ERROR, "warning: block counter just went negative (this should not happen)\n"); \ - return; \ - } \ -} +#define CHECK_BLOCK() \ + if (total_blocks < 1) { \ + av_log(s->avctx, AV_LOG_ERROR, \ + "Block counter just went negative (this should not happen)\n"); \ + return AVERROR_INVALIDDATA; \ + } \ -static void rpza_decode_stream(RpzaContext *s) +#define ADVANCE_BLOCK() \ + { \ + pixel_ptr += 4; \ + if (pixel_ptr >= width) \ + { \ + pixel_ptr = 0; \ + row_ptr += stride * 4; \ + } \ + total_blocks--; \ + } + +static int rpza_decode_stream(RpzaContext *s) { int width = s->avctx->width; int stride = s->frame->linesize[0] / 2; @@ -126,7 +128,8 @@ static void rpza_decode_stream(RpzaContext *s) /* Skip blocks */ case 0x80: while (n_blocks--) { - ADVANCE_BLOCK(); + CHECK_BLOCK(); + ADVANCE_BLOCK(); } break; @@ -134,6 +137,7 @@ static void rpza_decode_stream(RpzaContext *s) case 0xa0: colorA = bytestream2_get_be16(&s->gb); while (n_blocks--) { + CHECK_BLOCK(); block_ptr = row_ptr + pixel_ptr; for (pixel_y = 0; pixel_y < 4; pixel_y++) { for (pixel_x = 0; pixel_x < 4; pixel_x++){ @@ -177,8 +181,9 @@ static void rpza_decode_stream(RpzaContext *s) color4[2] |= ((21 * ta + 11 * tb) >> 5); if (bytestream2_get_bytes_left(&s->gb) < n_blocks * 4) - return; + return AVERROR_INVALIDDATA; while (n_blocks--) { + CHECK_BLOCK(); block_ptr = row_ptr + pixel_ptr; for (pixel_y = 0; pixel_y < 4; pixel_y++) { uint8_t index = bytestream2_get_byteu(&s->gb); @@ -196,7 +201,8 @@ static void rpza_decode_stream(RpzaContext *s) /* Fill block with 16 colors */ case 0x00: if (bytestream2_get_bytes_left(&s->gb) < 30) - return; + return AVERROR_INVALIDDATA; + CHECK_BLOCK(); block_ptr = row_ptr + pixel_ptr; for (pixel_y = 0; pixel_y < 4; pixel_y++) { for (pixel_x = 0; pixel_x < 4; pixel_x++){ @@ -216,9 +222,11 @@ static void rpza_decode_stream(RpzaContext *s) av_log(s->avctx, AV_LOG_ERROR, "Unknown opcode %d in rpza chunk." " Skip remaining %d bytes of chunk data.\n", opcode, bytestream2_get_bytes_left(&s->gb)); - return; + return AVERROR_INVALIDDATA; } /* Opcode switch */ } + + return 0; } static av_cold int rpza_decode_init(AVCodecContext *avctx) @@ -249,7 +257,9 @@ static int rpza_decode_frame(AVCodecContext *avctx, return ret; } - rpza_decode_stream(s); + ret = rpza_decode_stream(s); + if (ret < 0) + return ret; if ((ret = av_frame_ref(data, s->frame)) < 0) return ret;