// by the concrete value. A nil value gets sent as the empty string for the name,
// followed by no 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.fieldnum = -1
state.sendZero = true
enc.pushWriter(b)
data := new(bytes.Buffer)
data.Write(spaceForLength)
- enc.encode(data, iv.Elem(), ut)
+ enc.encode(data, elem, ut)
if enc.err != nil {
error_(enc.err)
}
// EncodeValue transmits the data item represented by the reflection value,
// guaranteeing that all necessary type information has been transmitted first.
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
// goroutines can share an encoder.
enc.mutex.Lock()
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)
+ }
+}