]> Cypherpunks repositories - gostls13.git/commitdiff
math/big: fix nil bug in GobEncode
authorRob Pike <r@golang.org>
Mon, 19 Aug 2013 01:22:09 +0000 (11:22 +1000)
committerRob Pike <r@golang.org>
Mon, 19 Aug 2013 01:22:09 +0000 (11:22 +1000)
Update #5305.
This handles the case where the nil pointers are inside a slice.
A top-level nil pointer is harder, maybe fundamentally broken by gob's model.
Thinking required.
However, a slice is the important case since people don't expect to be sending
top-level nils much, but they can arise easily in slices.

R=golang-dev, josharian, adg
CC=golang-dev
https://golang.org/cl/13042044

src/pkg/math/big/int.go
src/pkg/math/big/int_test.go
src/pkg/math/big/rat.go
src/pkg/math/big/rat_test.go

index 09051f82ed828d0936c8547df8a3272914a43a28..23c8bfeb2377a8cdf55f861e8bc422db951fd687 100644 (file)
@@ -952,6 +952,9 @@ const intGobVersion byte = 1
 
 // GobEncode implements the gob.GobEncoder interface.
 func (x *Int) GobEncode() ([]byte, error) {
+       if x == nil {
+               return nil, nil
+       }
        buf := make([]byte, 1+len(x.abs)*_S) // extra byte for version and sign bit
        i := x.abs.bytes(buf) - 1            // i >= 0
        b := intGobVersion << 1              // make space for sign bit
@@ -965,7 +968,9 @@ func (x *Int) GobEncode() ([]byte, error) {
 // GobDecode implements the gob.GobDecoder interface.
 func (z *Int) GobDecode(buf []byte) error {
        if len(buf) == 0 {
-               return errors.New("Int.GobDecode: no data")
+               // Other side sent a nil or default value.
+               *z = Int{}
+               return nil
        }
        b := buf[0]
        if b>>1 != intGobVersion {
index 6c981e7752e462fc82ecffa167912eec25310737..01d5d4e4dc0c987a319f123124a71069108235e4 100644 (file)
@@ -1484,6 +1484,32 @@ func TestIntGobEncoding(t *testing.T) {
        }
 }
 
+// Sending a nil Int pointer (inside a slice) on a round trip through gob should yield a zero.
+// TODO: top-level nils.
+func TestGobEncodingNilIntInSlice(t *testing.T) {
+       buf := new(bytes.Buffer)
+       enc := gob.NewEncoder(buf)
+       dec := gob.NewDecoder(buf)
+
+       var in = make([]*Int, 1)
+       err := enc.Encode(&in)
+       if err != nil {
+               t.Errorf("gob encode failed: %q", err)
+       }
+       var out []*Int
+       err = dec.Decode(&out)
+       if err != nil {
+               t.Fatalf("gob decode failed: %q", err)
+       }
+       if len(out) != 1 {
+               t.Fatalf("wrong len; want 1 got %d", len(out))
+       }
+       var zero Int
+       if out[0].Cmp(&zero) != 0 {
+               t.Errorf("transmission of (*Int)(nill) failed: got %s want 0", out)
+       }
+}
+
 func TestIntJSONEncoding(t *testing.T) {
        for _, test := range encodingTests {
                var tx Int
index 39791ec6d88440e8e5cd720759670ced78c2a0d2..7faee61a465c64b67a8215357f711916ee307b0a 100644 (file)
@@ -546,6 +546,9 @@ const ratGobVersion byte = 1
 
 // GobEncode implements the gob.GobEncoder interface.
 func (x *Rat) GobEncode() ([]byte, error) {
+       if x == nil {
+               return nil, nil
+       }
        buf := make([]byte, 1+4+(len(x.a.abs)+len(x.b.abs))*_S) // extra bytes for version and sign bit (1), and numerator length (4)
        i := x.b.abs.bytes(buf)
        j := x.a.abs.bytes(buf[0:i])
@@ -567,7 +570,9 @@ func (x *Rat) GobEncode() ([]byte, error) {
 // GobDecode implements the gob.GobDecoder interface.
 func (z *Rat) GobDecode(buf []byte) error {
        if len(buf) == 0 {
-               return errors.New("Rat.GobDecode: no data")
+               // Other side sent a nil or default value.
+               *z = Rat{}
+               return nil
        }
        b := buf[0]
        if b>>1 != ratGobVersion {
index 1c2c642379c09bb7d664c8adaee2041898fdacf3..0d432637ba19764d65d7ef4f138d72bd652c1c84 100644 (file)
@@ -407,6 +407,32 @@ func TestRatGobEncoding(t *testing.T) {
        }
 }
 
+// Sending a nil Rat pointer (inside a slice) on a round trip through gob should yield a zero.
+// TODO: top-level nils.
+func TestGobEncodingNilRatInSlice(t *testing.T) {
+       buf := new(bytes.Buffer)
+       enc := gob.NewEncoder(buf)
+       dec := gob.NewDecoder(buf)
+
+       var in = make([]*Rat, 1)
+       err := enc.Encode(&in)
+       if err != nil {
+               t.Errorf("gob encode failed: %q", err)
+       }
+       var out []*Rat
+       err = dec.Decode(&out)
+       if err != nil {
+               t.Fatalf("gob decode failed: %q", err)
+       }
+       if len(out) != 1 {
+               t.Fatalf("wrong len; want 1 got %d", len(out))
+       }
+       var zero Rat
+       if out[0].Cmp(&zero) != 0 {
+               t.Errorf("transmission of (*Int)(nill) failed: got %s want 0", out)
+       }
+}
+
 func TestIssue2379(t *testing.T) {
        // 1) no aliasing
        q := NewRat(3, 2)