mirror of
https://github.com/golang/go
synced 2024-11-25 07:17:56 -07:00
encoding/gob: better handling of nil pointers
- better message for top-level nil - nil inside interface yields error, not panic Fixes #3704. R=golang-dev, dsymonds CC=golang-dev https://golang.org/cl/6304064
This commit is contained in:
parent
2a0fdf6ea0
commit
ea3c3bb3a8
@ -426,6 +426,12 @@ func (enc *Encoder) encodeMap(b *bytes.Buffer, mv reflect.Value, keyOp, elemOp e
|
|||||||
// by the concrete value. A nil value gets sent as the empty string for the name,
|
// by the concrete value. A nil value gets sent as the empty string for the name,
|
||||||
// followed by no value.
|
// followed by no value.
|
||||||
func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv reflect.Value) {
|
func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv reflect.Value) {
|
||||||
|
// Gobs can encode nil interface values but not typed interface
|
||||||
|
// values holding nil pointers, since nil pointers point to no value.
|
||||||
|
elem := iv.Elem()
|
||||||
|
if elem.Kind() == reflect.Ptr && elem.IsNil() {
|
||||||
|
errorf("gob: cannot encode nil pointer of type %s inside interface", iv.Elem().Type())
|
||||||
|
}
|
||||||
state := enc.newEncoderState(b)
|
state := enc.newEncoderState(b)
|
||||||
state.fieldnum = -1
|
state.fieldnum = -1
|
||||||
state.sendZero = true
|
state.sendZero = true
|
||||||
@ -454,7 +460,7 @@ func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv reflect.Value) {
|
|||||||
enc.pushWriter(b)
|
enc.pushWriter(b)
|
||||||
data := new(bytes.Buffer)
|
data := new(bytes.Buffer)
|
||||||
data.Write(spaceForLength)
|
data.Write(spaceForLength)
|
||||||
enc.encode(data, iv.Elem(), ut)
|
enc.encode(data, elem, ut)
|
||||||
if enc.err != nil {
|
if enc.err != nil {
|
||||||
error_(enc.err)
|
error_(enc.err)
|
||||||
}
|
}
|
||||||
|
@ -218,6 +218,12 @@ func (enc *Encoder) sendTypeId(state *encoderState, ut *userTypeInfo) {
|
|||||||
// EncodeValue transmits the data item represented by the reflection value,
|
// EncodeValue transmits the data item represented by the reflection value,
|
||||||
// guaranteeing that all necessary type information has been transmitted first.
|
// guaranteeing that all necessary type information has been transmitted first.
|
||||||
func (enc *Encoder) EncodeValue(value reflect.Value) error {
|
func (enc *Encoder) EncodeValue(value reflect.Value) error {
|
||||||
|
// Gobs contain values. They cannot represent nil pointers, which
|
||||||
|
// have no value to encode.
|
||||||
|
if value.Kind() == reflect.Ptr && value.IsNil() {
|
||||||
|
panic("gob: cannot encode nil pointer of type " + value.Type().String())
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure we're single-threaded through here, so multiple
|
// Make sure we're single-threaded through here, so multiple
|
||||||
// goroutines can share an encoder.
|
// goroutines can share an encoder.
|
||||||
enc.mutex.Lock()
|
enc.mutex.Lock()
|
||||||
|
@ -736,3 +736,47 @@ func TestPtrToMapOfMap(t *testing.T) {
|
|||||||
t.Fatalf("expected %v got %v", data, newData)
|
t.Fatalf("expected %v got %v", data, newData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A top-level nil pointer generates a panic with a helpful string-valued message.
|
||||||
|
func TestTopLevelNilPointer(t *testing.T) {
|
||||||
|
errMsg := topLevelNilPanic(t)
|
||||||
|
if errMsg == "" {
|
||||||
|
t.Fatal("top-level nil pointer did not panic")
|
||||||
|
}
|
||||||
|
if !strings.Contains(errMsg, "nil pointer") {
|
||||||
|
t.Fatal("expected nil pointer error, got:", errMsg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func topLevelNilPanic(t *testing.T) (panicErr string) {
|
||||||
|
defer func() {
|
||||||
|
e := recover()
|
||||||
|
if err, ok := e.(string); ok {
|
||||||
|
panicErr = err
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
var ip *int
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
if err := NewEncoder(buf).Encode(ip); err != nil {
|
||||||
|
t.Fatal("error in encode:", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNilPointerInsideInterface(t *testing.T) {
|
||||||
|
var ip *int
|
||||||
|
si := struct {
|
||||||
|
I interface{}
|
||||||
|
}{
|
||||||
|
I: ip,
|
||||||
|
}
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
err := NewEncoder(buf).Encode(si)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("expected error, got none")
|
||||||
|
}
|
||||||
|
errMsg := err.Error()
|
||||||
|
if !strings.Contains(errMsg, "nil pointer") || !strings.Contains(errMsg, "interface") {
|
||||||
|
t.Fatal("expected error about nil pointer and interface, got:", errMsg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user