Hi,

the attached patch fixes ticket #3538, which is an off-by-one error.
Unfortunately, I see no way of detecting it as a "correctable"
behavior and not an actual error besides that.

Maybe restricting this to actual off-by-one errors would be better, too.

-- 
Christophe
From 59ea1d72b27272d2a28c680fc87b353f1a88eb36 Mon Sep 17 00:00:00 2001
From: Christophe Gisquet <christophe.gisq...@gmail.com>
Date: Sun, 17 Aug 2014 09:47:46 +0200
Subject: [PATCH] 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.
---
 libavcodec/gifdec.c | 31 ++++++++++++++++++++++---------
 1 file changed, 22 insertions(+), 9 deletions(-)

diff --git a/libavcodec/gifdec.c b/libavcodec/gifdec.c
index 78c8900..22da582 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");
-        return AVERROR_INVALIDDATA;
-    }
     if (width <= 0 || height <= 0) {
         av_log(s->avctx, AV_LOG_ERROR, "Invalid image dimensions.\n");
         return AVERROR_INVALIDDATA;
     }
+    if (width > s->screen_width) {
+        av_log(s->avctx, AV_LOG_ERROR, "Invalid image width.\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)
-- 
1.9.2.msysgit.0

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel

Reply via email to