]> Cypherpunks repositories - gostls13.git/commitdiff
image: make RegisterFormat safe for concurrent use
authorTim Cooper <tim.cooper@layeh.com>
Thu, 14 Jun 2018 00:19:22 +0000 (21:19 -0300)
committerBrad Fitzpatrick <bradfitz@golang.org>
Wed, 26 Sep 2018 23:14:57 +0000 (23:14 +0000)
Fixes #25884

Change-Id: I5478846ef78aecac32078ea8c3248db52f1bb534
Reviewed-on: https://go-review.googlesource.com/118755
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/image/format.go

index 3668de4e6858afdf4a1ffd2185bc980b96c996ff..a53b8f9b554882dbc9413f49117296414b42c34f 100644 (file)
@@ -8,6 +8,8 @@ import (
        "bufio"
        "errors"
        "io"
+       "sync"
+       "sync/atomic"
 )
 
 // ErrFormat indicates that decoding encountered an unknown format.
@@ -21,7 +23,10 @@ type format struct {
 }
 
 // Formats is the list of registered formats.
-var formats []format
+var (
+       formatsMu     sync.Mutex
+       atomicFormats atomic.Value
+)
 
 // RegisterFormat registers an image format for use by Decode.
 // Name is the name of the format, like "jpeg" or "png".
@@ -30,7 +35,10 @@ var formats []format
 // Decode is the function that decodes the encoded image.
 // DecodeConfig is the function that decodes just its configuration.
 func RegisterFormat(name, magic string, decode func(io.Reader) (Image, error), decodeConfig func(io.Reader) (Config, error)) {
-       formats = append(formats, format{name, magic, decode, decodeConfig})
+       formatsMu.Lock()
+       formats, _ := atomicFormats.Load().([]format)
+       atomicFormats.Store(append(formats, format{name, magic, decode, decodeConfig}))
+       formatsMu.Unlock()
 }
 
 // A reader is an io.Reader that can also peek ahead.
@@ -62,6 +70,7 @@ func match(magic string, b []byte) bool {
 
 // Sniff determines the format of r's data.
 func sniff(r reader) format {
+       formats, _ := atomicFormats.Load().([]format)
        for _, f := range formats {
                b, err := r.Peek(len(f.magic))
                if err == nil && match(f.magic, b) {