Text file src/cmd/go/testdata/script/test_fuzz_mutate_crash.txt

     1  [!fuzz] skip
     2  
     3  # Tests that a crash caused by a mutator-discovered input writes the bad input
     4  # to testdata, and fails+reports correctly. This tests the end-to-end behavior
     5  # of the mutator finding a crash while fuzzing, adding it as a regression test
     6  # to the seed corpus in testdata, and failing the next time the test is run.
     7  
     8  [short] skip
     9  env GOCACHE=$WORK/cache
    10  
    11  # Running the seed corpus for all of the targets should pass the first
    12  # time, since nothing in the seed corpus will cause a crash.
    13  go test
    14  
    15  # Running the fuzzer should find a crashing input quickly.
    16  ! go test -fuzz=FuzzWithBug -fuzztime=100x -fuzzminimizetime=1000x
    17  stdout 'testdata[/\\]fuzz[/\\]FuzzWithBug[/\\]'
    18  stdout 'this input caused a crash!'
    19  go run check_testdata.go FuzzWithBug
    20  
    21  # Now, the failing bytes should have been added to the seed corpus for
    22  # the target, and should fail when run without fuzzing.
    23  ! go test
    24  stdout 'FuzzWithBug/[a-f0-9]{16}'
    25  stdout 'this input caused a crash!'
    26  
    27  ! go test -run=FuzzWithNilPanic -fuzz=FuzzWithNilPanic -fuzztime=100x -fuzzminimizetime=1000x
    28  stdout 'testdata[/\\]fuzz[/\\]FuzzWithNilPanic[/\\]'
    29  stdout 'panic called with nil argument|test executed panic.nil. or runtime.Goexit'
    30  go run check_testdata.go FuzzWithNilPanic
    31  
    32  ! go test -run=FuzzWithGoexit -fuzz=FuzzWithGoexit -fuzztime=100x -fuzzminimizetime=1000x
    33  stdout 'testdata[/\\]fuzz[/\\]FuzzWithGoexit[/\\]'
    34  stdout 'runtime.Goexit'
    35  go run check_testdata.go FuzzWithGoexit
    36  
    37  ! go test -run=FuzzWithFail -fuzz=FuzzWithFail -fuzztime=100x -fuzzminimizetime=1000x
    38  stdout 'testdata[/\\]fuzz[/\\]FuzzWithFail[/\\]'
    39  go run check_testdata.go FuzzWithFail
    40  
    41  ! go test -run=FuzzWithLogFail -fuzz=FuzzWithLogFail -fuzztime=100x -fuzzminimizetime=1000x
    42  stdout 'testdata[/\\]fuzz[/\\]FuzzWithLogFail[/\\]'
    43  stdout 'logged something'
    44  go run check_testdata.go FuzzWithLogFail
    45  
    46  ! go test -run=FuzzWithErrorf -fuzz=FuzzWithErrorf -fuzztime=100x -fuzzminimizetime=1000x
    47  stdout 'testdata[/\\]fuzz[/\\]FuzzWithErrorf[/\\]'
    48  stdout 'errorf was called here'
    49  go run check_testdata.go FuzzWithErrorf
    50  
    51  ! go test -run=FuzzWithFatalf -fuzz=FuzzWithFatalf -fuzztime=100x -fuzzminimizetime=1000x
    52  stdout 'testdata[/\\]fuzz[/\\]FuzzWithFatalf[/\\]'
    53  stdout 'fatalf was called here'
    54  go run check_testdata.go FuzzWithFatalf
    55  
    56  ! go test -run=FuzzWithBadExit -fuzz=FuzzWithBadExit -fuzztime=100x -fuzzminimizetime=1000x
    57  stdout 'testdata[/\\]fuzz[/\\]FuzzWithBadExit[/\\]'
    58  stdout '^\s+fuzzing process hung or terminated unexpectedly: exit status'
    59  go run check_testdata.go FuzzWithBadExit
    60  
    61  ! go test -run=FuzzDeadlock -fuzz=FuzzDeadlock -fuzztime=100x -fuzzminimizetime=0x
    62  stdout 'testdata[/\\]fuzz[/\\]FuzzDeadlock[/\\]'
    63  stdout '^\s+fuzzing process hung or terminated unexpectedly: exit status'
    64  go run check_testdata.go FuzzDeadlock
    65  
    66  # Running the fuzzer should find a crashing input quickly for fuzzing two types.
    67  ! go test -run=FuzzWithTwoTypes -fuzz=FuzzWithTwoTypes -fuzztime=100x -fuzzminimizetime=1000x
    68  stdout 'testdata[/\\]fuzz[/\\]FuzzWithTwoTypes[/\\]'
    69  stdout 'these inputs caused a crash!'
    70  go run check_testdata.go FuzzWithTwoTypes
    71  
    72  # Running the fuzzer should find a crashing input quickly for an integer.
    73  ! go test -run=FuzzInt -fuzz=FuzzInt -fuzztime=100x -fuzzminimizetime=1000x
    74  stdout 'testdata[/\\]fuzz[/\\]FuzzInt[/\\]'
    75  stdout 'this input caused a crash!'
    76  go run check_testdata.go FuzzInt
    77  
    78  ! go test -run=FuzzUint -fuzz=FuzzUint -fuzztime=100x -fuzzminimizetime=1000x
    79  stdout 'testdata[/\\]fuzz[/\\]FuzzUint[/\\]'
    80  stdout 'this input caused a crash!'
    81  go run check_testdata.go FuzzUint
    82  
    83  # Running the fuzzer should find a crashing input quickly for a bool.
    84  ! go test -run=FuzzBool -fuzz=FuzzBool -fuzztime=100x -fuzzminimizetime=1000x
    85  stdout 'testdata[/\\]fuzz[/\\]FuzzBool[/\\]'
    86  stdout 'this input caused a crash!'
    87  go run check_testdata.go FuzzBool
    88  
    89  # Running the fuzzer should find a crashing input quickly for a float.
    90  ! go test -run=FuzzFloat -fuzz=FuzzFloat -fuzztime=100x -fuzzminimizetime=1000x
    91  stdout 'testdata[/\\]fuzz[/\\]FuzzFloat[/\\]'
    92  stdout 'this input caused a crash!'
    93  go run check_testdata.go FuzzFloat
    94  
    95  # Running the fuzzer should find a crashing input quickly for a byte.
    96  ! go test -run=FuzzByte -fuzz=FuzzByte -fuzztime=100x -fuzzminimizetime=1000x
    97  stdout 'testdata[/\\]fuzz[/\\]FuzzByte[/\\]'
    98  stdout 'this input caused a crash!'
    99  go run check_testdata.go FuzzByte
   100  
   101  # Running the fuzzer should find a crashing input quickly for a rune.
   102  ! go test -run=FuzzRune -fuzz=FuzzRune -fuzztime=100x -fuzzminimizetime=1000x
   103  stdout 'testdata[/\\]fuzz[/\\]FuzzRune[/\\]'
   104  stdout 'this input caused a crash!'
   105  go run check_testdata.go FuzzRune
   106  
   107  # Running the fuzzer should find a crashing input quickly for a string.
   108  ! go test -run=FuzzString -fuzz=FuzzString -fuzztime=100x -fuzzminimizetime=1000x
   109  stdout 'testdata[/\\]fuzz[/\\]FuzzString[/\\]'
   110  stdout 'this input caused a crash!'
   111  go run check_testdata.go FuzzString
   112  
   113  -- go.mod --
   114  module m
   115  
   116  go 1.16
   117  -- fuzz_crash_test.go --
   118  package fuzz_crash
   119  
   120  import (
   121  	"os"
   122  	"runtime"
   123  	"testing"
   124  )
   125  
   126  func FuzzWithBug(f *testing.F) {
   127  	f.Add([]byte("aa"))
   128  	f.Fuzz(func(t *testing.T, b []byte) {
   129  		if string(b) != "aa" {
   130  			panic("this input caused a crash!")
   131  		}
   132  	})
   133  }
   134  
   135  func FuzzWithNilPanic(f *testing.F) {
   136  	f.Add([]byte("aa"))
   137  	f.Fuzz(func(t *testing.T, b []byte) {
   138  		if string(b) != "aa" {
   139  			panic(nil)
   140  		}
   141  	})
   142  }
   143  
   144  func FuzzWithGoexit(f *testing.F) {
   145  	f.Add([]byte("aa"))
   146  	f.Fuzz(func(t *testing.T, b []byte) {
   147  		if string(b) != "aa" {
   148  			runtime.Goexit()
   149  		}
   150  	})
   151  }
   152  
   153  func FuzzWithFail(f *testing.F) {
   154  	f.Add([]byte("aa"))
   155  	f.Fuzz(func(t *testing.T, b []byte) {
   156  		if string(b) != "aa" {
   157  			t.Fail()
   158  		}
   159  	})
   160  }
   161  
   162  func FuzzWithLogFail(f *testing.F) {
   163  	f.Add([]byte("aa"))
   164  	f.Fuzz(func(t *testing.T, b []byte) {
   165  		if string(b) != "aa" {
   166  			t.Log("logged something")
   167  			t.Fail()
   168  		}
   169  	})
   170  }
   171  
   172  func FuzzWithErrorf(f *testing.F) {
   173  	f.Add([]byte("aa"))
   174  	f.Fuzz(func(t *testing.T, b []byte) {
   175  		if string(b) != "aa" {
   176  			t.Errorf("errorf was called here")
   177  		}
   178  	})
   179  }
   180  
   181  func FuzzWithFatalf(f *testing.F) {
   182  	f.Add([]byte("aa"))
   183  	f.Fuzz(func(t *testing.T, b []byte) {
   184  		if string(b) != "aa" {
   185  			t.Fatalf("fatalf was called here")
   186  		}
   187  	})
   188  }
   189  
   190  func FuzzWithBadExit(f *testing.F) {
   191  	f.Add([]byte("aa"))
   192  	f.Fuzz(func(t *testing.T, b []byte) {
   193  		if string(b) != "aa" {
   194  			os.Exit(1)
   195  		}
   196  	})
   197  }
   198  
   199  func FuzzDeadlock(f *testing.F) {
   200  	f.Add(int(0))
   201  	f.Fuzz(func(t *testing.T, n int) {
   202  		if n != 0 {
   203  			select {}
   204  		}
   205  	})
   206  }
   207  
   208  func FuzzWithTwoTypes(f *testing.F) {
   209  	f.Fuzz(func(t *testing.T, a, b []byte) {
   210  		if len(a) > 0 && len(b) > 0 {
   211  			panic("these inputs caused a crash!")
   212  		}
   213  	})
   214  }
   215  
   216  func FuzzInt(f *testing.F) {
   217  	f.Add(0)
   218  	f.Fuzz(func(t *testing.T, a int) {
   219  		if a != 0 {
   220  			panic("this input caused a crash!")
   221  		}
   222  	})
   223  }
   224  
   225  func FuzzUint(f *testing.F) {
   226  	f.Add(uint(0))
   227  	f.Fuzz(func(t *testing.T, a uint) {
   228  		if a != 0 {
   229  			panic("this input caused a crash!")
   230  		}
   231  	})
   232  }
   233  
   234  func FuzzBool(f *testing.F) {
   235  	f.Add(false)
   236  	f.Fuzz(func(t *testing.T, a bool) {
   237  		if a {
   238  			panic("this input caused a crash!")
   239  		}
   240  	})
   241  }
   242  
   243  func FuzzFloat(f *testing.F) {
   244  	f.Fuzz(func(t *testing.T, a float64) {
   245  		if a != 0 {
   246  			panic("this input caused a crash!")
   247  		}
   248  	})
   249  }
   250  
   251  func FuzzByte(f *testing.F) {
   252  	f.Add(byte(0))
   253  	f.Fuzz(func(t *testing.T, a byte) {
   254  		if a != 0 {
   255  			panic("this input caused a crash!")
   256  		}
   257  	})
   258  }
   259  
   260  func FuzzRune(f *testing.F) {
   261  	f.Add(rune(0))
   262  	f.Fuzz(func(t *testing.T, a rune) {
   263  		if a != 0 {
   264  			panic("this input caused a crash!")
   265  		}
   266  	})
   267  }
   268  
   269  func FuzzString(f *testing.F) {
   270  	f.Add("")
   271  	f.Fuzz(func(t *testing.T, a string) {
   272  		if a != "" {
   273  			panic("this input caused a crash!")
   274  		}
   275  	})
   276  }
   277  
   278  -- check_testdata.go --
   279  // +build ignore
   280  
   281  package main
   282  
   283  import (
   284  	"bytes"
   285  	"crypto/sha256"
   286  	"fmt"
   287  	"io/ioutil"
   288  	"os"
   289  	"path/filepath"
   290  )
   291  
   292  func main() {
   293  	target := os.Args[1]
   294  	dir := filepath.Join("testdata/fuzz", target)
   295  
   296  	files, err := ioutil.ReadDir(dir)
   297  	if err != nil {
   298  		fmt.Fprintln(os.Stderr, err)
   299  		os.Exit(1)
   300  	}
   301  
   302  	if len(files) == 0 {
   303  		fmt.Fprintf(os.Stderr, "expect at least one new mutation to be written to testdata\n")
   304  		os.Exit(1)
   305  	}
   306  
   307  	fname := files[0].Name()
   308  	contents, err := ioutil.ReadFile(filepath.Join(dir, fname))
   309  	if err != nil {
   310  		fmt.Fprintln(os.Stderr, err)
   311  		os.Exit(1)
   312  	}
   313  	if bytes.Equal(contents, []byte("aa")) {
   314  		fmt.Fprintf(os.Stderr, "newly written testdata entry was not mutated\n")
   315  		os.Exit(1)
   316  	}
   317  	// The hash of the bytes in the file should match the filename.
   318  	h := []byte(fmt.Sprintf("%x", sha256.Sum256(contents)))
   319  	if !bytes.HasPrefix(h, []byte(fname)) {
   320  		fmt.Fprintf(os.Stderr, "hash of bytes %q does not match filename %q\n", h, fname)
   321  		os.Exit(1)
   322  	}
   323  }
   324  

View as plain text