Commit 4ddb3a6d authored by Christophe Gisquet's avatar Christophe Gisquet Committed by Michael Niedermayer

gifdec: use truncated width for image manipulation

Some files seem to have an off-by-one error. In most cases, it appears to
be on the image width. Therefore, if the decoded image doesn't fit in the
screen:
- If it is wider than the screen (and the lzw decoding buffer), reject it;
- Otherwise, decode the indicated amount, but only write a truncated amount
  to the screen.

Fixes ticket #3538.
Signed-off-by: 's avatarMichael Niedermayer <michaelni@gmx.at>
parent 853c1fb6
...@@ -129,7 +129,7 @@ static void gif_copy_img_rect(const uint32_t *src, uint32_t *dst, ...@@ -129,7 +129,7 @@ static void gif_copy_img_rect(const uint32_t *src, uint32_t *dst,
static int gif_read_image(GifState *s, AVFrame *frame) static int gif_read_image(GifState *s, AVFrame *frame)
{ {
int left, top, width, height, bits_per_pixel, code_size, flags; int left, top, width, height, bits_per_pixel, code_size, flags, pw;
int is_interleaved, has_local_palette, y, pass, y1, linesize, pal_size; int is_interleaved, has_local_palette, y, pass, y1, linesize, pal_size;
uint32_t *ptr, *pal, *px, *pr, *ptr1; uint32_t *ptr, *pal, *px, *pr, *ptr1;
int ret; int ret;
...@@ -179,15 +179,28 @@ static int gif_read_image(GifState *s, AVFrame *frame) ...@@ -179,15 +179,28 @@ static int gif_read_image(GifState *s, AVFrame *frame)
} }
/* verify that all the image is inside the screen dimensions */ /* verify that all the image is inside the screen dimensions */
if (left + width > s->screen_width || if (!width || width > s->screen_width || left >= s->screen_width) {
top + height > s->screen_height) { av_log(s->avctx, AV_LOG_ERROR, "Invalid image width.\n");
av_log(s->avctx, AV_LOG_ERROR, "image is outside the screen dimensions.\n");
return AVERROR_INVALIDDATA; return AVERROR_INVALIDDATA;
} }
if (width <= 0 || height <= 0) { if (!height || height > s->screen_height || top >= s->screen_height) {
av_log(s->avctx, AV_LOG_ERROR, "Invalid image dimensions.\n"); av_log(s->avctx, AV_LOG_ERROR, "Invalid image height.\n");
return AVERROR_INVALIDDATA; return AVERROR_INVALIDDATA;
} }
if (left + width > s->screen_width) {
/* width must be kept around to avoid lzw vs line desync */
pw = s->screen_width - left;
av_log(s->avctx, AV_LOG_WARNING, "Image too wide by %d, truncating.\n",
left + width - s->screen_width);
} else {
pw = width;
}
if (top + height > s->screen_height) {
/* we don't care about the extra invisible lines */
av_log(s->avctx, AV_LOG_WARNING, "Image too high by %d, truncating.\n",
top + height - s->screen_height);
height = s->screen_height - top;
}
/* process disposal method */ /* process disposal method */
if (s->gce_prev_disposal == GCE_DISPOSAL_BACKGROUND) { if (s->gce_prev_disposal == GCE_DISPOSAL_BACKGROUND) {
...@@ -201,7 +214,7 @@ static int gif_read_image(GifState *s, AVFrame *frame) ...@@ -201,7 +214,7 @@ static int gif_read_image(GifState *s, AVFrame *frame)
if (s->gce_disposal != GCE_DISPOSAL_NONE) { if (s->gce_disposal != GCE_DISPOSAL_NONE) {
s->gce_l = left; s->gce_t = top; s->gce_l = left; s->gce_t = top;
s->gce_w = width; s->gce_h = height; s->gce_w = pw; s->gce_h = height;
if (s->gce_disposal == GCE_DISPOSAL_BACKGROUND) { if (s->gce_disposal == GCE_DISPOSAL_BACKGROUND) {
if (s->transparent_color_index >= 0) if (s->transparent_color_index >= 0)
...@@ -214,7 +227,7 @@ static int gif_read_image(GifState *s, AVFrame *frame) ...@@ -214,7 +227,7 @@ static int gif_read_image(GifState *s, AVFrame *frame)
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
gif_copy_img_rect((uint32_t *)frame->data[0], s->stored_img, gif_copy_img_rect((uint32_t *)frame->data[0], s->stored_img,
frame->linesize[0] / sizeof(uint32_t), left, top, width, height); frame->linesize[0] / sizeof(uint32_t), left, top, pw, height);
} }
} }
...@@ -244,7 +257,7 @@ static int gif_read_image(GifState *s, AVFrame *frame) ...@@ -244,7 +257,7 @@ static int gif_read_image(GifState *s, AVFrame *frame)
goto decode_tail; goto decode_tail;
} }
pr = ptr + width; pr = ptr + pw;
for (px = ptr, idx = s->idx_line; px < pr; px++, idx++) { for (px = ptr, idx = s->idx_line; px < pr; px++, idx++) {
if (*idx != s->transparent_color_index) if (*idx != s->transparent_color_index)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment