]> Cypherpunks repositories - gostls13.git/commitdiff
gob: fuzz testing, plus a fix for very large type names.
authorDavid Symonds <dsymonds@golang.org>
Mon, 6 Feb 2012 03:02:12 +0000 (14:02 +1100)
committerDavid Symonds <dsymonds@golang.org>
Mon, 6 Feb 2012 03:02:12 +0000 (14:02 +1100)
Fixes #2689.

R=r
CC=golang-dev
https://golang.org/cl/5616063

src/pkg/encoding/gob/codec_test.go
src/pkg/encoding/gob/decode.go
src/pkg/encoding/gob/error.go

index 73844b920c14bfa00fced5fd73ffc80df749ec73..d365f82634553912242a3d27d8b657434d3ce179 100644 (file)
@@ -8,9 +8,11 @@ import (
        "bytes"
        "errors"
        "math"
+       "math/rand"
        "reflect"
        "strings"
        "testing"
+       "time"
        "unsafe"
 )
 
@@ -1407,3 +1409,60 @@ func TestDebugStruct(t *testing.T) {
        }
        debugFunc(debugBuffer)
 }
+
+func encFuzzDec(rng *rand.Rand, in interface{}) error {
+       buf := new(bytes.Buffer)
+       enc := NewEncoder(buf)
+       if err := enc.Encode(&in); err != nil {
+               return err
+       }
+
+       b := buf.Bytes()
+       for i, bi := range b {
+               if rng.Intn(10) < 3 {
+                       b[i] = bi + uint8(rng.Intn(256))
+               }
+       }
+
+       dec := NewDecoder(buf)
+       var e interface{}
+       if err := dec.Decode(&e); err != nil {
+               return err
+       }
+       return nil
+}
+
+// This does some "fuzz testing" by attempting to decode a sequence of random bytes.
+func TestFuzz(t *testing.T) {
+       if testing.Short() {
+               return
+       }
+
+       // all possible inputs
+       input := []interface{}{
+               new(int),
+               new(float32),
+               new(float64),
+               new(complex128),
+               &ByteStruct{255},
+               &ArrayStruct{},
+               &StringStruct{"hello"},
+               &GobTest1{0, &StringStruct{"hello"}},
+       }
+       testFuzz(t, time.Now().UnixNano(), 100, input...)
+}
+
+func TestFuzzRegressions(t *testing.T) {
+       // An instance triggering a type name of length ~102 GB.
+       testFuzz(t, 1328492090837718000, 100, new(float32))
+}
+
+func testFuzz(t *testing.T, seed int64, n int, input ...interface{}) {
+       t.Logf("seed=%d n=%d\n", seed, n)
+       for _, e := range input {
+               rng := rand.New(rand.NewSource(seed))
+               for i := 0; i < n; i++ {
+                       encFuzzDec(rng, e)
+               }
+       }
+}
index 4d1325d176c61cc0455047559e36725c17cfb1ed..8191062d30930303a85086c539c6b962735316bd 100644 (file)
@@ -690,7 +690,11 @@ func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, p ui
        // Create a writable interface reflect.Value.  We need one even for the nil case.
        ivalue := allocValue(ityp)
        // Read the name of the concrete type.
-       b := make([]byte, state.decodeUint())
+       nr := state.decodeUint()
+       if nr < 0 || nr > 1<<31 { // zero is permissible for anonymous types
+               errorf("invalid type name length %d", nr)
+       }
+       b := make([]byte, nr)
        state.b.Read(b)
        name := string(b)
        if name == "" {
index fbae8b683da74038a930e055219246e278b6ee88..92cc0c615e3bd94bd286700ac510705c5b1cac2a 100644 (file)
@@ -33,7 +33,11 @@ func error_(err error) {
 // plain error.  It overwrites the error return of the function that deferred its call.
 func catchError(err *error) {
        if e := recover(); e != nil {
-               *err = e.(gobError).err // Will re-panic if not one of our errors, such as a runtime error.
+               ge, ok := e.(gobError)
+               if !ok {
+                       panic(e)
+               }
+               *err = ge.err
        }
        return
 }