]> Cypherpunks repositories - gostls13.git/commitdiff
image/gif: don't panic on large or nil-containing color.Palettes.
authorNigel Tao <nigeltao@golang.org>
Fri, 5 May 2017 06:44:42 +0000 (16:44 +1000)
committerNigel Tao <nigeltao@golang.org>
Sat, 6 May 2017 00:37:43 +0000 (00:37 +0000)
Fixes #20249

Change-Id: I5dceaef31de96345f8e6c155e12775dc4cc31bfb
Reviewed-on: https://go-review.googlesource.com/42790
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
src/image/gif/writer.go
src/image/gif/writer_test.go

index 1918196884df0f0eba2b7dd39a957cc9bb921f2b..e68f7a4ed5c8a541c72e7caf12740f5edbaa6723 100644 (file)
@@ -132,7 +132,12 @@ func (e *encoder) writeHeader() {
                e.buf[1] = e.g.BackgroundIndex
                e.buf[2] = 0x00 // Pixel Aspect Ratio.
                e.write(e.buf[:3])
-               e.globalCT = encodeColorTable(e.globalColorTable[:], p, paddedSize)
+               var err error
+               e.globalCT, err = encodeColorTable(e.globalColorTable[:], p, paddedSize)
+               if err != nil && e.err == nil {
+                       e.err = err
+                       return
+               }
                e.write(e.globalColorTable[:e.globalCT])
        } else {
                // All frames have a local color table, so a global color table
@@ -149,8 +154,9 @@ func (e *encoder) writeHeader() {
                e.buf[1] = 0xff // Application Label.
                e.buf[2] = 0x0b // Block Size.
                e.write(e.buf[:3])
-               _, e.err = io.WriteString(e.w, "NETSCAPE2.0") // Application Identifier.
-               if e.err != nil {
+               _, err := io.WriteString(e.w, "NETSCAPE2.0") // Application Identifier.
+               if err != nil && e.err == nil {
+                       e.err = err
                        return
                }
                e.buf[0] = 0x03 // Block Size.
@@ -161,11 +167,18 @@ func (e *encoder) writeHeader() {
        }
 }
 
-func encodeColorTable(dst []byte, p color.Palette, size int) int {
+func encodeColorTable(dst []byte, p color.Palette, size int) (int, error) {
+       if uint(size) >= uint(len(log2Lookup)) {
+               return 0, errors.New("gif: cannot encode color table with more than 256 entries")
+       }
        n := log2Lookup[size]
        for i := 0; i < n; i++ {
                if i < len(p) {
-                       r, g, b, _ := p[i].RGBA()
+                       c := p[i]
+                       if c == nil {
+                               return 0, errors.New("gif: cannot encode color table with nil entries")
+                       }
+                       r, g, b, _ := c.RGBA()
                        dst[3*i+0] = uint8(r >> 8)
                        dst[3*i+1] = uint8(g >> 8)
                        dst[3*i+2] = uint8(b >> 8)
@@ -176,7 +189,7 @@ func encodeColorTable(dst []byte, p color.Palette, size int) int {
                        dst[3*i+2] = 0x00
                }
        }
-       return 3 * n
+       return 3 * n, nil
 }
 
 func (e *encoder) writeImageBlock(pm *image.Paletted, delay int, disposal byte) {
@@ -201,6 +214,10 @@ func (e *encoder) writeImageBlock(pm *image.Paletted, delay int, disposal byte)
 
        transparentIndex := -1
        for i, c := range pm.Palette {
+               if c == nil {
+                       e.err = errors.New("gif: cannot encode color table with nil entries")
+                       return
+               }
                if _, _, _, a := c.RGBA(); a == 0 {
                        transparentIndex = i
                        break
@@ -235,8 +252,12 @@ func (e *encoder) writeImageBlock(pm *image.Paletted, delay int, disposal byte)
        e.write(e.buf[:9])
 
        paddedSize := log2(len(pm.Palette)) // Size of Local Color Table: 2^(1+n).
-       ct := encodeColorTable(e.localColorTable[:], pm.Palette, paddedSize)
-       if ct != e.globalCT || !bytes.Equal(e.globalColorTable[:ct], e.localColorTable[:ct]) {
+       if ct, err := encodeColorTable(e.localColorTable[:], pm.Palette, paddedSize); err != nil {
+               if e.err == nil {
+                       e.err = err
+               }
+               return
+       } else if ct != e.globalCT || !bytes.Equal(e.globalColorTable[:ct], e.localColorTable[:ct]) {
                // Use a local color table.
                e.writeByte(fColorTable | uint8(paddedSize))
                e.write(e.localColorTable[:ct])
index 775ccea31dcf655fc7cb603dfed88f8e46b75c47..bbedbfc36e6a3c66c6266cc01184788f7917cf5c 100644 (file)
@@ -438,6 +438,39 @@ func TestEncodePalettes(t *testing.T) {
        }
 }
 
+func TestEncodeBadPalettes(t *testing.T) {
+       const w, h = 5, 5
+       for _, n := range []int{256, 257} {
+               for _, nilColors := range []bool{false, true} {
+                       pal := make(color.Palette, n)
+                       if !nilColors {
+                               for i := range pal {
+                                       pal[i] = color.Black
+                               }
+                       }
+
+                       err := EncodeAll(ioutil.Discard, &GIF{
+                               Image: []*image.Paletted{
+                                       image.NewPaletted(image.Rect(0, 0, w, h), pal),
+                               },
+                               Delay:    make([]int, 1),
+                               Disposal: make([]byte, 1),
+                               Config: image.Config{
+                                       ColorModel: pal,
+                                       Width:      w,
+                                       Height:     h,
+                               },
+                       })
+
+                       got := err != nil
+                       want := n > 256 || nilColors
+                       if got != want {
+                               t.Errorf("n=%d, nilColors=%t: err != nil: got %t, want %t", n, nilColors, got, want)
+                       }
+               }
+       }
+}
+
 func BenchmarkEncode(b *testing.B) {
        b.StopTimer()