Commit e855fcc3 authored by Rob Pike's avatar Rob Pike

encoding/gob: fix data race in Register

Fixes #4214.

R=golang-dev, dsymonds, bradfitz
CC=golang-dev
https://golang.org/cl/6637047
parent e9f0fc88
...@@ -717,7 +717,9 @@ func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, p ui ...@@ -717,7 +717,9 @@ func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, p ui
errorf("name too long (%d bytes): %.20q...", len(name), name) errorf("name too long (%d bytes): %.20q...", len(name), name)
} }
// The concrete type must be registered. // The concrete type must be registered.
registerLock.RLock()
typ, ok := nameToConcreteType[name] typ, ok := nameToConcreteType[name]
registerLock.RUnlock()
if !ok { if !ok {
errorf("name not registered for interface: %q", name) errorf("name not registered for interface: %q", name)
} }
......
...@@ -441,7 +441,9 @@ func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv reflect.Value) { ...@@ -441,7 +441,9 @@ func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv reflect.Value) {
} }
ut := userType(iv.Elem().Type()) ut := userType(iv.Elem().Type())
registerLock.RLock()
name, ok := concreteTypeToName[ut.base] name, ok := concreteTypeToName[ut.base]
registerLock.RUnlock()
if !ok { if !ok {
errorf("type not registered for interface: %s", ut.base) errorf("type not registered for interface: %s", ut.base)
} }
......
...@@ -712,6 +712,7 @@ type GobDecoder interface { ...@@ -712,6 +712,7 @@ type GobDecoder interface {
} }
var ( var (
registerLock sync.RWMutex
nameToConcreteType = make(map[string]reflect.Type) nameToConcreteType = make(map[string]reflect.Type)
concreteTypeToName = make(map[reflect.Type]string) concreteTypeToName = make(map[reflect.Type]string)
) )
...@@ -723,6 +724,8 @@ func RegisterName(name string, value interface{}) { ...@@ -723,6 +724,8 @@ func RegisterName(name string, value interface{}) {
// reserved for nil // reserved for nil
panic("attempt to register empty name") panic("attempt to register empty name")
} }
registerLock.Lock()
defer registerLock.Unlock()
ut := userType(reflect.TypeOf(value)) ut := userType(reflect.TypeOf(value))
// Check for incompatible duplicates. The name must refer to the // Check for incompatible duplicates. The name must refer to the
// same user type, and vice versa. // same user type, and vice versa.
......
...@@ -177,7 +177,10 @@ func TestRegistrationNaming(t *testing.T) { ...@@ -177,7 +177,10 @@ func TestRegistrationNaming(t *testing.T) {
Register(tc.t) Register(tc.t)
tct := reflect.TypeOf(tc.t) tct := reflect.TypeOf(tc.t)
if ct := nameToConcreteType[tc.name]; ct != tct { registerLock.RLock()
ct := nameToConcreteType[tc.name]
registerLock.RUnlock()
if ct != tct {
t.Errorf("nameToConcreteType[%q] = %v, want %v", tc.name, ct, tct) t.Errorf("nameToConcreteType[%q] = %v, want %v", tc.name, ct, tct)
} }
// concreteTypeToName is keyed off the base type. // concreteTypeToName is keyed off the base type.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment