]> Cypherpunks repositories - gostls13.git/commitdiff
image/gif: accept an out-of-bounds transparent color index.
authorNigel Tao <nigeltao@golang.org>
Thu, 28 Apr 2016 07:19:31 +0000 (17:19 +1000)
committerNigel Tao <nigeltao@golang.org>
Fri, 29 Apr 2016 00:01:22 +0000 (00:01 +0000)
This is an error according to the spec, but Firefox and Google Chrome
seem OK with this.

Fixes #15059.

Change-Id: I841cf44e96655e91a2481555f38fbd7055a32202
Reviewed-on: https://go-review.googlesource.com/22546
Reviewed-by: Rob Pike <r@golang.org>
src/image/gif/reader.go
src/image/gif/reader_test.go

index 9a0852dbfd814a6c6bd292380dbc38ab83fd3d73..6181a946fad15b5ff651e19d1184cf25114a615e 100644 (file)
@@ -178,12 +178,25 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
                                }
                                m.Palette = d.globalColorTable
                        }
-                       if d.hasTransparentIndex && int(d.transparentIndex) < len(m.Palette) {
+                       if d.hasTransparentIndex {
                                if !useLocalColorTable {
                                        // Clone the global color table.
                                        m.Palette = append(color.Palette(nil), d.globalColorTable...)
                                }
-                               m.Palette[d.transparentIndex] = color.RGBA{}
+                               if ti := int(d.transparentIndex); ti < len(m.Palette) {
+                                       m.Palette[ti] = color.RGBA{}
+                               } else {
+                                       // The transparentIndex is out of range, which is an error
+                                       // according to the spec, but Firefox and Google Chrome
+                                       // seem OK with this, so we enlarge the palette with
+                                       // transparent colors. See golang.org/issue/15059.
+                                       p := make(color.Palette, ti+1)
+                                       copy(p, m.Palette)
+                                       for i := len(m.Palette); i < len(p); i++ {
+                                               p[i] = color.RGBA{}
+                                       }
+                                       m.Palette = p
+                               }
                        }
                        litWidth, err := d.r.ReadByte()
                        if err != nil {
index ee78a4071668d74a09c38594030e75b78d9c2876..90c81493cba5442a792932facf0bd9d1e25a40c8 100644 (file)
@@ -22,12 +22,16 @@ const (
        trailerStr = "\x3b"
 )
 
-// lzwEncode returns an LZW encoding (with 2-bit literals) of n zeroes.
-func lzwEncode(n int) []byte {
+// lzwEncode returns an LZW encoding (with 2-bit literals) of in.
+func lzwEncode(in []byte) []byte {
        b := &bytes.Buffer{}
        w := lzw.NewWriter(b, lzw.LSB, 2)
-       w.Write(make([]byte, n))
-       w.Close()
+       if _, err := w.Write(in); err != nil {
+               panic(err)
+       }
+       if err := w.Close(); err != nil {
+               panic(err)
+       }
        return b.Bytes()
 }
 
@@ -53,7 +57,7 @@ func TestDecode(t *testing.T) {
                // byte, and 2-bit LZW literals.
                b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
                if tc.nPix > 0 {
-                       enc := lzwEncode(tc.nPix)
+                       enc := lzwEncode(make([]byte, tc.nPix))
                        if len(enc) > 0xff {
                                t.Errorf("nPix=%d, extra=%t: compressed length %d is too large", tc.nPix, tc.extra, len(enc))
                                continue
@@ -103,7 +107,7 @@ func TestTransparentIndex(t *testing.T) {
                }
                // Write an image with bounds 2x1, as per TestDecode.
                b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
-               enc := lzwEncode(2)
+               enc := lzwEncode([]byte{0x00, 0x00})
                if len(enc) > 0xff {
                        t.Fatalf("compressed length %d is too large", len(enc))
                }
@@ -196,21 +200,13 @@ func TestNoPalette(t *testing.T) {
        b.WriteString(headerStr[:len(headerStr)-3])
        b.WriteString("\x00\x00\x00") // No global palette.
 
-       // Image descriptor: 2x1, no local palette.
+       // Image descriptor: 2x1, no local palette, and 2-bit LZW literals.
        b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
 
        // Encode the pixels: neither is in range, because there is no palette.
-       pix := []byte{0, 3}
-       enc := &bytes.Buffer{}
-       w := lzw.NewWriter(enc, lzw.LSB, 2)
-       if _, err := w.Write(pix); err != nil {
-               t.Fatalf("Write: %v", err)
-       }
-       if err := w.Close(); err != nil {
-               t.Fatalf("Close: %v", err)
-       }
-       b.WriteByte(byte(len(enc.Bytes())))
-       b.Write(enc.Bytes())
+       enc := lzwEncode([]byte{0x00, 0x03})
+       b.WriteByte(byte(len(enc)))
+       b.Write(enc)
        b.WriteByte(0x00) // An empty block signifies the end of the image data.
 
        b.WriteString(trailerStr)
@@ -226,21 +222,13 @@ func TestPixelOutsidePaletteRange(t *testing.T) {
                b.WriteString(headerStr)
                b.WriteString(paletteStr)
 
-               // Image descriptor: 2x1, no local palette.
+               // Image descriptor: 2x1, no local palette, and 2-bit LZW literals.
                b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
 
                // Encode the pixels; some pvals trigger the expected error.
-               pix := []byte{pval, pval}
-               enc := &bytes.Buffer{}
-               w := lzw.NewWriter(enc, lzw.LSB, 2)
-               if _, err := w.Write(pix); err != nil {
-                       t.Fatalf("Write: %v", err)
-               }
-               if err := w.Close(); err != nil {
-                       t.Fatalf("Close: %v", err)
-               }
-               b.WriteByte(byte(len(enc.Bytes())))
-               b.Write(enc.Bytes())
+               enc := lzwEncode([]byte{pval, pval})
+               b.WriteByte(byte(len(enc)))
+               b.Write(enc)
                b.WriteByte(0x00) // An empty block signifies the end of the image data.
 
                b.WriteString(trailerStr)
@@ -254,6 +242,36 @@ func TestPixelOutsidePaletteRange(t *testing.T) {
        }
 }
 
+func TestTransparentPixelOutsidePaletteRange(t *testing.T) {
+       b := &bytes.Buffer{}
+
+       // Manufacture a GIF with a 2 color palette.
+       b.WriteString(headerStr)
+       b.WriteString(paletteStr)
+
+       // Graphic Control Extension: transparency, transparent color index = 3.
+       //
+       // This index, 3, is out of range of the global palette and there is no
+       // local palette in the subsequent image descriptor. This is an error
+       // according to the spec, but Firefox and Google Chrome seem OK with this.
+       //
+       // See golang.org/issue/15059.
+       b.WriteString("\x21\xf9\x04\x01\x00\x00\x03\x00")
+
+       // Image descriptor: 2x1, no local palette, and 2-bit LZW literals.
+       b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
+
+       // Encode the pixels.
+       enc := lzwEncode([]byte{0x03, 0x03})
+       b.WriteByte(byte(len(enc)))
+       b.Write(enc)
+       b.WriteByte(0x00) // An empty block signifies the end of the image data.
+
+       b.WriteString(trailerStr)
+
+       try(t, b.Bytes(), "")
+}
+
 func TestLoopCount(t *testing.T) {
        data := []byte("GIF89a000\x00000,0\x00\x00\x00\n\x00" +
                "\n\x00\x80000000\x02\b\xf01u\xb9\xfdal\x05\x00;")