New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
encoding/gob: panic when Encode nil #16204
Comments
Hello there @jadenteng, I am not qualified to answer this bug because I don't know much about encoding/gob but I made something here https://play.golang.org/p/8PB1oN2eFO that perhaps could be useful for comparing behaviors across diferent encoders. They all have different behaviors of course, but I found it encoding/gob can successfully encode a nil map, I also think the nil you are passing in being untyped might be a bit of a problem for encoding/gob. I also came across this documentation from encoding/gob I don't have the different versions of Go built on this machine to test out when it could have started, but from the source code, it seems like the behavior has been in for a long time https://github.com/golang/go/blame/master/src/encoding/gob/encoder.go so a change might break compatibility with older programs?
package main
import (
"bytes"
"encoding/gob"
"encoding/json"
"encoding/xml"
"fmt"
"io"
)
type encoder interface {
Encode(interface{}) error
}
type encoderType int
const (
JSON encoderType = iota
XML
GOB
)
func (e encoderType) String() string {
switch e {
case JSON:
return "json"
case XML:
return "xml"
case GOB:
return "gob"
default:
return "unknown"
}
}
func (et encoderType) encoderProducer() func(io.Writer) encoder {
switch et {
case JSON:
return func(w io.Writer) encoder { return json.NewEncoder(w) }
case GOB:
return func(w io.Writer) encoder { return gob.NewEncoder(w) }
case XML:
return func(w io.Writer) encoder { return xml.NewEncoder(w) }
default:
return nil
}
}
func (et encoderType) nilBehavior(src interface{}) (serializedBytes []byte, err interface{}) {
defer func() {
if rerr := recover(); rerr != nil {
switch rerr := rerr.(type) {
case error:
err = rerr
default:
err = fmt.Errorf("%v", rerr)
}
}
}()
buf := new(bytes.Buffer)
encoderFn := et.encoderProducer()
err = encoderFn(buf).Encode(src)
serializedBytes = buf.Bytes()
return
}
func main() {
var fn func() error = nil
gob.Register(fn)
testCases := [...]struct {
typ encoderType
wantErr error
wantBytes []byte
value interface{}
}{
{JSON, nil, []byte("null\n"), nil},
{JSON, nil, []byte("null\n"), map[string]string(nil)},
{XML, nil, []byte(""), nil},
{GOB, nil, []byte(""), nil},
{GOB, nil, []byte("\x0e\xff\x81\x04\x01\x02\xff\x82\x00\x01\f\x01\f\x00\x00\x04\xff\x82\x00\x00"), map[string]string(nil)},
{GOB, nil, []byte(""), func() (fn func() error) { return }},
{GOB, nil, []byte("\x03\f\x00\x00"), new(string)},
}
for i, tt := range testCases {
gotBytes, gotErr := tt.typ.nilBehavior(tt.value)
if !bytes.Equal(gotBytes, tt.wantBytes) {
fmt.Printf("#%d: %s: gotBytes=%q wantBytes=%q\n", i, tt.typ, gotBytes, tt.wantBytes)
}
if gotErr != tt.wantErr {
fmt.Printf("#%d: %s: gotErr=%v wantErr=%v\n", i, tt.typ, gotErr, tt.wantErr)
}
}
} |
I don't think so. Because all
in your program. There are alternative change should made in the gob:Encode method according to your comment
I like (2). Because it's same with other package Encode methods behavior. |
@jadenteng gotcha. In this diff, I catch that check and then panic with an error directly from gob itself instead of letting it propagate to reflect diff --git a/src/encoding/gob/encoder.go b/src/encoding/gob/encoder.go
index d6c8fdd..14871bc 100644
--- a/src/encoding/gob/encoder.go
+++ b/src/encoding/gob/encoder.go
@@ -215,9 +215,13 @@ func (enc *Encoder) sendTypeId(state *encoderState, ut *userTypeInfo) {
// guaranteeing that all necessary type information has been transmitted first.
// Passing a nil pointer to EncodeValue will panic, as they cannot be transmitted by gob.
func (enc *Encoder) EncodeValue(value reflect.Value) error {
- if value.Kind() == reflect.Ptr && value.IsNil() {
+ kind := value.Kind()
+ if kind == reflect.Ptr && value.IsNil() {
panic("gob: cannot encode nil pointer of type " + value.Type().String())
}
+ if kind == reflect.Invalid {
+ panic("gob: cannot encode an invalid/zero value")
+ }
// Make sure we're single-threaded through here, so multiple
// goroutines can share an encoder. if we decide to instead an error, then we can modify it in this place. |
Please answer these questions before submitting your issue. Thanks!
go version
)?go version go1.6.2 darwin/amd64
Use gob to serialize golang object.
Main Code: https://play.golang.org/p/z0v0O8D_WC
return error.New("Gob: nil given")
panic error
Thank you very much.
The text was updated successfully, but these errors were encountered: