]> Cypherpunks repositories - gostls13.git/commitdiff
internal/fuzz: allocate memory for mutated strings
authorRoland Shoemaker <roland@golang.org>
Tue, 14 Sep 2021 19:40:10 +0000 (12:40 -0700)
committerRoland Shoemaker <roland@golang.org>
Wed, 22 Sep 2021 15:38:34 +0000 (15:38 +0000)
Rather than directly pointing at the underlying scratch slice, allocate
memory for strings. This prevents mutation of previous values we've
passed to the fuzz function, which may be retained by something that
expects them to be immutable.

Fixes golang/go#48308

Change-Id: Iee9bed1a536fdc4188180e8e7c1c722f641271d2
Reviewed-on: https://go-review.googlesource.com/c/go/+/351312
Trust: Roland Shoemaker <roland@golang.org>
Trust: Katie Hockman <katie@golang.org>
Run-TryBot: Roland Shoemaker <roland@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Jay Conrod <jayconrod@google.com>
Reviewed-by: Katie Hockman <katie@golang.org>
src/internal/fuzz/mutator.go
src/internal/fuzz/mutator_test.go
src/testing/fuzz.go

index 9aa56782b0bd05d435b0f344eb7d3f68f4e879b9..da7200dcbe134341ca753553de24fda34c71f959 100644 (file)
@@ -106,12 +106,7 @@ func (m *mutator) mutate(vals []interface{}, maxBytes int) {
                        copy(m.scratch, v)
                }
                m.mutateBytes(&m.scratch)
-               var s string
-               shdr := (*reflect.StringHeader)(unsafe.Pointer(&s))
-               bhdr := (*reflect.SliceHeader)(unsafe.Pointer(&m.scratch))
-               shdr.Data = bhdr.Data
-               shdr.Len = bhdr.Len
-               vals[i] = s
+               vals[i] = string(m.scratch)
        case []byte:
                if len(v) > maxPerVal {
                        panic(fmt.Sprintf("cannot mutate bytes of length %d", len(v)))
index ee2912dfd218012eb418e531ad2ac9b13bb7fe8d..d8015ce21388331f3ed83cbd016ff6e514409273 100644 (file)
@@ -5,6 +5,7 @@
 package fuzz
 
 import (
+       "bytes"
        "fmt"
        "os"
        "strconv"
@@ -99,3 +100,18 @@ func BenchmarkMutatorAllBasicTypes(b *testing.B) {
                })
        }
 }
+
+func TestStringImmutability(t *testing.T) {
+       v := []interface{}{"hello"}
+       m := newMutator()
+       m.mutate(v, 1024)
+       original := v[0].(string)
+       originalCopy := make([]byte, len(original))
+       copy(originalCopy, []byte(original))
+       for i := 0; i < 25; i++ {
+               m.mutate(v, 1024)
+       }
+       if !bytes.Equal([]byte(original), originalCopy) {
+               t.Fatalf("string was mutated: got %x, want %x", []byte(original), originalCopy)
+       }
+}
index 57ea41803915d06a5869daf703d00941ea8815a3..ddce065783a5d6e74208958567bb867bab12de1c 100644 (file)
@@ -293,7 +293,10 @@ var supportedTypes = map[reflect.Type]bool{
 // f.Fuzz(func(t *testing.T, b []byte, i int) { ... })
 //
 // This function should be fast, deterministic, and stateless.
-// None of the pointers to any input data should be retained between executions.
+//
+// No mutatable input arguments, or pointers to them, should be retained between
+// executions of the fuzz function, as the memory backing them may be mutated
+// during a subsequent invocation.
 //
 // This is a terminal function which will terminate the currently running fuzz
 // target by calling runtime.Goexit.