summaryrefslogtreecommitdiff
path: root/libavcodec/gifdec.c
diff options
context:
space:
mode:
authorChristophe Gisquet <christophe.gisquet@gmail.com>2014-08-17 09:47:46 +0200
committerMichael Niedermayer <michaelni@gmx.at>2014-08-18 09:49:01 +0200
commit4ddb3a6df0f6ad053c8455e074c1e6688b051272 (patch)
tree18784a98ada57123f637d8aa5ebc134f0e1d856b /libavcodec/gifdec.c
parent853c1fb66835123c87178420816cff58c18548ed (diff)
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: Michael Niedermayer <michaelni@gmx.at>
Diffstat (limited to 'libavcodec/gifdec.c')
-rw-r--r--libavcodec/gifdec.c31
1 files changed, 22 insertions, 9 deletions
diff --git a/libavcodec/gifdec.c b/libavcodec/gifdec.c
index 78c8900628..dee48f56af 100644
--- a/libavcodec/gifdec.c
+++ b/libavcodec/gifdec.c
@@ -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)
{
- 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;
uint32_t *ptr, *pal, *px, *pr, *ptr1;
int ret;
@@ -179,15 +179,28 @@ static int gif_read_image(GifState *s, AVFrame *frame)
}
/* verify that all the image is inside the screen dimensions */
- if (left + width > s->screen_width ||
- top + height > s->screen_height) {
- av_log(s->avctx, AV_LOG_ERROR, "image is outside the screen dimensions.\n");
+ if (!width || width > s->screen_width || left >= s->screen_width) {
+ av_log(s->avctx, AV_LOG_ERROR, "Invalid image width.\n");
return AVERROR_INVALIDDATA;
}
- if (width <= 0 || height <= 0) {
- av_log(s->avctx, AV_LOG_ERROR, "Invalid image dimensions.\n");
+ if (!height || height > s->screen_height || top >= s->screen_height) {
+ av_log(s->avctx, AV_LOG_ERROR, "Invalid image height.\n");
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 */
if (s->gce_prev_disposal == GCE_DISPOSAL_BACKGROUND) {
@@ -201,7 +214,7 @@ static int gif_read_image(GifState *s, AVFrame *frame)
if (s->gce_disposal != GCE_DISPOSAL_NONE) {
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->transparent_color_index >= 0)
@@ -214,7 +227,7 @@ static int gif_read_image(GifState *s, AVFrame *frame)
return AVERROR(ENOMEM);
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)
goto decode_tail;
}
- pr = ptr + width;
+ pr = ptr + pw;
for (px = ptr, idx = s->idx_line; px < pr; px++, idx++) {
if (*idx != s->transparent_color_index)