Clip std/gif output to the image rect
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index 4dd0e55..bdd505e 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -11104,6 +11104,7 @@
                                          wuffs_base__slice_u8 a_src) {
   wuffs_base__slice_u8 v_dst = {0};
   wuffs_base__slice_u8 v_src = {0};
+  uint64_t v_width_in_bytes = 0;
   uint64_t v_n = 0;
   uint64_t v_src_ri = 0;
   uint32_t v_bytes_per_pixel = 0;
@@ -11125,6 +11126,8 @@
   } else {
     return wuffs_base__error__unsupported_option;
   }
+  v_width_in_bytes = (((uint64_t)(self->private_impl.f_width)) *
+                      ((uint64_t)(v_bytes_per_pixel)));
   v_tab = wuffs_base__pixel_buffer__plane(a_pb, 0);
 label_0_continue:;
   while (v_src_ri < ((uint64_t)(a_src.len))) {
@@ -11136,6 +11139,11 @@
       return wuffs_base__error__too_much_data;
     }
     v_dst = wuffs_base__table_u8__row(v_tab, self->private_impl.f_dst_y);
+    if (self->private_impl.f_dst_y >= self->private_impl.f_height) {
+      v_dst = wuffs_base__slice_u8__subslice_j(v_dst, 0);
+    } else if (v_width_in_bytes < ((uint64_t)(v_dst.len))) {
+      v_dst = wuffs_base__slice_u8__subslice_j(v_dst, v_width_in_bytes);
+    }
     v_i = (((uint64_t)(self->private_impl.f_dst_x)) *
            ((uint64_t)(v_bytes_per_pixel)));
     if (v_i < ((uint64_t)(v_dst.len))) {
diff --git a/std/gif/decode_gif.wuffs b/std/gif/decode_gif.wuffs
index be2064f..83e6d25 100644
--- a/std/gif/decode_gif.wuffs
+++ b/std/gif/decode_gif.wuffs
@@ -1096,6 +1096,7 @@
 	// TODO: don't assume an interleaved pixel format.
 	var dst             slice base.u8
 	var src             slice base.u8
+	var width_in_bytes  base.u64
 	var n               base.u64
 	var src_ri          base.u64
 	var bytes_per_pixel base.u32[..64]
@@ -1120,6 +1121,7 @@
 		return base."#unsupported option"
 	}
 
+	width_in_bytes = (this.width as base.u64) * (bytes_per_pixel as base.u64)
 	tab = args.pb.plane(p:0)
 	while src_ri < args.src.length() {
 		src = args.src[src_ri:]
@@ -1132,9 +1134,15 @@
 		}
 
 		// First, copy from src to that part of the frame rect that is inside
-		// args.pb's bounds.
+		// args.pb's bounds (clipped to the image bounds).
 
 		dst = tab.row(y:this.dst_y)
+		if this.dst_y >= this.height {
+			dst = dst[:0]
+		} else if width_in_bytes < dst.length() {
+			dst = dst[:width_in_bytes]
+		}
+
 		i = (this.dst_x as base.u64) * (bytes_per_pixel as base.u64)
 		if i < dst.length() {
 			j = (this.frame_rect_x1 as base.u64) * (bytes_per_pixel as base.u64)
diff --git a/test/c/std/gif.c b/test/c/std/gif.c
index e30c3c2..57763d6 100644
--- a/test/c/std/gif.c
+++ b/test/c/std/gif.c
@@ -996,8 +996,12 @@
                   wuffs_base__pixel_config__height(&ic.pixcfg), height);
     }
 
+    wuffs_base__pixel_config five_by_five = ((wuffs_base__pixel_config){});
+    wuffs_base__pixel_config__set(
+        &five_by_five, wuffs_base__pixel_config__pixel_format(&ic.pixcfg),
+        wuffs_base__pixel_config__pixel_subsampling(&ic.pixcfg), 5, 5);
     wuffs_base__pixel_buffer pb = ((wuffs_base__pixel_buffer){});
-    status = wuffs_base__pixel_buffer__set_from_slice(&pb, &ic.pixcfg,
+    status = wuffs_base__pixel_buffer__set_from_slice(&pb, &five_by_five,
                                                       global_pixel_slice);
     if (status) {
       RETURN_FAIL("q=%d: set_from_slice: \"%s\"", q, status);
@@ -1053,6 +1057,11 @@
       {
         wuffs_base__table_u8 p = wuffs_base__pixel_buffer__plane(&pb, 0);
         uint32_t y, x;
+        for (y = 0; y < 5; y++) {
+          for (x = 0; x < 5; x++) {
+            p.ptr[(y * p.stride) + x] = 0xEE;
+          }
+        }
         for (y = 0; y < height; y++) {
           for (x = 0; x < width; x++) {
             p.ptr[(y * p.stride) + x] = 0;
@@ -1066,6 +1075,20 @@
                       status);
         }
 
+        for (y = 0; y < 5; y++) {
+          for (x = 0; x < 5; x++) {
+            if ((x < width) && (y < height)) {
+              continue;
+            }
+            if (p.ptr[(y * p.stride) + x] != 0xEE) {
+              RETURN_FAIL("q=%d: decode_frame #%" PRIu32
+                          ": dirty pixel (%" PRIu32 ", %" PRIu32
+                          ") outside of image bounds",
+                          q, i, x, y);
+            }
+          }
+        }
+
         wuffs_base__rect_ie_u32 frame_rect =
             wuffs_base__frame_config__bounds(&fc);
         wuffs_base__rect_ie_u32 dirty_rect =