From: Katie Hockman Date: Mon, 28 Jun 2021 16:43:12 +0000 (-0400) Subject: [dev.fuzz] all: merge master (c95464f) into dev.fuzz X-Git-Tag: go1.18beta1~1282^2~34 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=0cf1e16bac137735ad7af45ac84df3b0afb312e3;p=gostls13.git [dev.fuzz] all: merge master (c95464f) into dev.fuzz The new SetEnv method for *testing.T and *testing.B types was automatically supported by *testing.F since it was added to the *testing.common type. This function is not appropriate for *testing.F since fuzzing is run in parallel by default. Conflicts: - api/next.txt Merge List: + 2021-06-27 c95464f0ea internal/buildcfg: refactor GOEXPERIMENT parsing code somewhat + 2021-06-25 ed01ceaf48 runtime/race: use race build tag on syso_test.go + 2021-06-25 d1916e5e84 go/types: in TestCheck/issues.src, import regexp/syntax instead of cmd/compile/internal/syntax + 2021-06-25 5160896c69 go/types: in TestStdlib, import from source instead of export data + 2021-06-25 d01bc571f7 runtime: make ncgocall a global counter + 2021-06-25 37f9a8f69d go/types: fix a bug in package qualification logic + 2021-06-24 c309c89db5 reflect: document that InterfaceData is a low-entropy RNG + 2021-06-24 cce621431a cmd/compile: fix wrong type in SSA generation for OSLICE2ARRPTR + 2021-06-24 600a2a4ffb cmd/go: don't try to add replaced versions that won't be selected + 2021-06-24 a9bb38222a net: remove hard-coded timeout in dialClosedPort test helper + 2021-06-24 86d72fa2cb time: handle invalid UTF-8 byte sequences in quote to prevent panic + 2021-06-24 44a12e5f33 cmd/go: search breadth-first instead of depth-first for test dependency cycles + 2021-06-24 73496e0df0 net: use absDomainName in the Windows lookupPTR test helper + 2021-06-24 222ed1b38a os: enable TestFifoEOF on openbsd + 2021-06-22 0ebd5a8de0 cmd/go: update ToolTags based on GOARCH value + 2021-06-22 5bd09e5efc spec: unsafe.Add/Slice are not permitted in statement context + 2021-06-22 666315b4d3 runtime/internal/atomic: remove incorrect pointer indirection in comment + 2021-06-22 63daa774b5 go/types: guard against checking instantiation when generics is disabled + 2021-06-22 197a5ee2ab cmd/gofmt: remove stale documentation for the -G flag + 2021-06-22 9afd158eb2 go/parser: parse an ast.IndexExpr for a[] + 2021-06-21 1bd5a20e3c cmd/go: add a -go flag to 'go mod graph' + 2021-06-21 761edf71f6 cmd/internal/moddeps: use a temporary directory for GOMODCACHE if needed + 2021-06-21 a0400420ad cmd/internal/moddeps: use -mod=readonly instead of -mod=mod + 2021-06-21 3f9ec83b10 cmd/go: document GOPPC64 environment variable + 2021-06-21 20bdfba325 go/scanner: fall back to next() when encountering 0 bytes in parseIdentifier + 2021-06-21 44f9a3566c database/sql: fix deadlock test in prepare statement + 2021-06-21 16e82be454 runtime: fix crash during VDSO calls on PowerPC + 2021-06-21 2e542c3c06 runtime/pprof: deflake TestMorestack more + 2021-06-21 ced0fdbad0 doc/go1.17: note deprecation of 'go get' for installing commands + 2021-06-21 7a5e7047a4 doc/go1.17: add Go 1.18 pre-announcements + 2021-06-21 85a2e24afd doc/go1.17: add security-related release notes + 2021-06-21 1de332996c doc/go1.17: document go/parser.SkipObjectResolution + 2021-06-21 117ebe0f52 cmd/go: do not require the module cache to exist for 'go mod edit' + 2021-06-20 460900a7b5 os/signal: test with a significantly longer fatal timeout + 2021-06-19 b73cc4b02b database/sql: do not rely on timeout for deadlock test + 2021-06-18 86743e7d86 image: add RGBA64Image interface + 2021-06-18 9401172166 runtime: clarify Frames.Next documentation + 2021-06-18 57aaa19aae runtime: disable CPU profiling before removing the SIGPROF handler + 2021-06-18 6f22d2c682 doc/go1.17: fix typo + 2021-06-17 45f251ad6c cmd/pprof,runtime/pprof: disable test on more broken platforms + 2021-06-17 ed834853ad cmd/go: replace a TODO with an explanatory comment + 2021-06-17 4dede02550 cmd/pprof: make ObjAddr a no-op + 2021-06-17 97cee43c93 testing: drop unusual characters from TempDir directory name + 2021-06-17 b0355a3e72 time: fix receiver for Time.IsDST method + 2021-06-17 881b6ea7ba doc/go1.17: fix redundant space + 2021-06-16 0e67ce3d28 cmd/go: in lazy modules, add transitive imports for 'go get' arguments + 2021-06-16 6ea2af0890 cmd/go: add a regression test for #45979 + 2021-06-16 a294e4e798 math/rand: mention half-open intervals explicitly + 2021-06-16 a6a853f94c cmd/asm: restore supporting of *1 scaling on ARM64 + 2021-06-16 785a8f677f cmd/compile: better error message for invalid untyped operation + 2021-06-16 a752bc0746 syscall: fix TestGroupCleanupUserNamespace test failure on Fedora + 2021-06-15 d77f4c0c5c net/http: improve some server docs + 2021-06-15 219fe9d547 cmd/go: ignore UTF8 BOM when reading source code + 2021-06-15 723f199edd cmd/link: set correct flags in .dynamic for PIE buildmode + 2021-06-15 4d2d89ff42 cmd/go, go/build: update docs to use //go:build syntax + 2021-06-15 033d885315 doc/go1.17: document go run pkg@version + 2021-06-15 ea8612ef42 syscall: disable c-shared test when no cgo, for windows/arm + 2021-06-15 abc56fd1a0 internal/bytealg: remove duplicate go:build line + 2021-06-15 4061d3463b syscall: rewrite handle inheritance test to use C rather than Powershell + 2021-06-15 cf4e3e3d3b reflect: explain why convertible or comparable types may still panic + 2021-06-14 7841cb14d9 doc/go1.17: assorted fixes + 2021-06-14 8a5a6f46dc debug/elf: don't apply DWARF relocations for ET_EXEC binaries + 2021-06-14 9d13f8d43e runtime: update the variable name in comment + 2021-06-14 0fd20ed5b6 reflect: use same conversion panic in reflect and runtime + 2021-06-14 6bbb0a9d4a cmd/internal/sys: mark windows/arm64 as c-shared-capable + 2021-06-14 d4f34f8c63 doc/go1.17: reword "results" in stack trace printing + 2021-06-14 fdab5be159 doc/go1.17: further revise OpenBSD release notes + 2021-06-14 326ea438bb cmd/compile: rewrite a, b = f() to use temporaries when type not identical + 2021-06-14 3249b645c9 cmd/compile: factor out rewrite multi-valued f() + 2021-06-13 14305bf0b9 misc/cgo: generate Windows import libraries for clang + 2021-06-13 24cff0f044 cmd/go, misc/cgo: skip test if no .edata + 2021-06-13 67b1b6a2e3 cmd/compile: allow ir.OSLICE2ARRPTR in mayCall + 2021-06-12 1ed0d129e9 runtime: testprogcgo: don't call exported Go functions directly from Go + 2021-06-12 9d46ee5ac4 reflect: handle stack-to-register translation in callMethod + 2021-06-11 e552a6d312 cmd/go: remove hint when no module is suggested + 2021-06-11 16b5d766d8 syscall: do not load native libraries on non-native powershell on arm + 2021-06-11 77aa209b38 runtime: loop on EINTR in macOS sigNoteSleep + 2021-06-11 e2dc6dd5c9 doc/go1.17: clean up formatting of gofmt section + 2021-06-11 2f1128461d cmd/go: match Windows paths in TestScript/mod_invalid_version + 2021-06-11 2721da2608 doc/go1.17: fix formatting near httptest + 2021-06-10 770f1de8c5 net/http: remove test-only private key from production binaries + 2021-06-10 8d11b1d117 cmd/go: report the imports of CompiledGoFiles in ImportMap + 2021-06-10 dc00dc6c6b crypto/tls: let HTTP/1.1 clients connect to servers with NextProtos "h2" + 2021-06-09 27f83723e9 api: promote next to go1.17 + 2021-06-09 182157c81a doc/go1.17: remove lingering TODO + 2021-06-09 a5bc060b42 doc/go1.17: document strconv changes for Go 1.17 + 2021-06-09 1402b27d46 strconv: document parsing of leading +/- + 2021-06-09 df35ade067 doc/go1.17: document //go:build lines + 2021-06-09 e4e7807d24 net/http: add AllowQuerySemicolons + 2021-06-09 ec3026d032 doc/go1.17: remove TODO for ports section + 2021-06-09 e6dda19888 net/url: reject query values with semicolons + 2021-06-09 139e935d3c math/big: comment division + 2021-06-09 aa5540cd82 cmd/compile: make map.zero symbol content-addressable + 2021-06-09 07ca28d529 cmd/link: fix bug in -strictdups checking of BSS symbols + 2021-06-08 bcecae2af6 doc/go1.17: mention new possibility of type conversion panicking + 2021-06-08 63dcab2e91 doc/go1.17: mention new vet checks sigchanyzer and stdmethods. + 2021-06-08 6551763a60 doc/go1.17: mention block profile bias fix + 2021-06-08 cb80937bf6 Revert "doc/go1.17: mention block profile bias fix" + 2021-06-08 d3e3d03666 net: reject leading zeros in IP address parsers + 2021-06-08 da4a640141 doc/go1.17: revise OpenBSD release notes + 2021-06-08 689f4c7415 doc/go1.17: mention block profile bias fix + 2021-06-08 9afe071c60 doc/go1.17: remove TODO for Tools section + 2021-06-08 f753d7223e doc/go1.17: resolve TODO for cmd/cover + 2021-06-08 9498b0155d cmd/go: in Go 1.17+ modules, add indirect go.mod dependencies separately from direct ones + 2021-06-08 949f00cebe doc/go1.17: add release notes for crypto packages + 2021-06-08 0fb3e2c184 doc/go1.17: add a release note for the '-compat' flag to 'go mod tidy' + 2021-06-08 2169deb352 cmd/compile: use t.AllMethods when sorting typesByString + 2021-06-08 c20bcb6488 runtime: remove out-of-date comments about frame skipping + 2021-06-07 39c39ae52f doc: document Go 1.17 language changes + 2021-06-07 dc8b558951 cmd/dist: pass -Wno-lto-type-mismatch in swig_callback_lto + 2021-06-07 909dd5e010 strconv: ParseFloat: always return ErrSyntax for bad syntax + 2021-06-07 8212707871 crypto/elliptic: update P-521 docs to say it's constant-time + 2021-06-07 7406180012 fmt: split package documentation into more sections + 2021-06-07 e3176bbc3e crypto/tls: fix typo in Config.NextProtos docs + 2021-06-05 e1fa26026d spec: improve wording consistency by eliminating "specifier" + 2021-06-05 f490134126 spec: improve wording by choosing an official term "keyword" + 2021-06-05 e3cb381704 go/internal/gcimporter: don't waste CPU copying bytes in `io.ReadAll` + 2021-06-05 9d669ed47a misc/cgo/errors: use expected column numbers + 2021-06-04 95939e8de7 cmd/compile/internal/abi: fix typo in comment + 2021-06-04 831f9376d8 net/http: fix ResponseWriter.ReadFrom with short reads + 2021-06-04 3a9d906edc os: avoid finalizer race in windows process object + 2021-06-04 105c5b50e0 os: terminate windows processes via handle directly + 2021-06-04 79cd407f88 syscall: regenerate zsyscall_windows.go + 2021-06-04 c6b6211229 doc/go1.17: document testing changes for Go 1.17 + 2021-06-04 0214440075 syscall: do not pass console handles to PROC_THREAD_ATTRIBUTE_HANDLE_LIST on Windows 7 + 2021-06-04 962d5c997a cmd/compile,go/types: restrict use of unsafe.{Add,Slice} to go1.17 or newer + 2021-06-04 b29b123e07 cmd/compile: remove spurious ir.Dump + 2021-06-03 6d98301114 cmd/link: use correct alignment in PE DWARF sections + 2021-06-03 e0d029f758 runtime: avoid gp.lockedm race in exitsyscall0 Change-Id: I00216c3c36e64814c44c79f25d1f38e4df6c1f24 --- 0cf1e16bac137735ad7af45ac84df3b0afb312e3 diff --cc api/next.txt index 564f672c69,e69de29bb2..6b568e2857 --- a/api/next.txt +++ b/api/next.txt @@@ -1,133 -1,0 +1,133 @@@ +pkg compress/lzw, method (*Reader) Close() error +pkg compress/lzw, method (*Reader) Read([]uint8) (int, error) +pkg compress/lzw, method (*Reader) Reset(io.Reader, Order, int) +pkg compress/lzw, method (*Writer) Close() error +pkg compress/lzw, method (*Writer) Reset(io.Writer, Order, int) +pkg compress/lzw, method (*Writer) Write([]uint8) (int, error) +pkg compress/lzw, type Reader struct +pkg compress/lzw, type Writer struct +pkg crypto/tls, method (*CertificateRequestInfo) Context() context.Context +pkg crypto/tls, method (*ClientHelloInfo) Context() context.Context +pkg crypto/tls, method (*Conn) HandshakeContext(context.Context) error +pkg debug/elf, const SHT_MIPS_ABIFLAGS = 1879048234 +pkg debug/elf, const SHT_MIPS_ABIFLAGS SectionType +pkg encoding/csv, method (*Reader) FieldPos(int) (int, int) +pkg go/ast, method (*FuncDecl) IsMethod() bool +pkg go/build, type Context struct, ToolTags []string +pkg go/parser, const SkipObjectResolution = 64 +pkg go/parser, const SkipObjectResolution Mode +pkg go/types, type Config struct, GoVersion string +pkg io/fs, func FileInfoToDirEntry(FileInfo) DirEntry +pkg net, method (*ParseError) Temporary() bool +pkg net, method (*ParseError) Timeout() bool +pkg net, method (IP) IsPrivate() bool +pkg reflect, func VisibleFields(Type) []StructField +pkg reflect, method (Method) IsExported() bool +pkg reflect, method (StructField) IsExported() bool +pkg runtime/cgo (darwin-amd64-cgo), func NewHandle(interface{}) Handle +pkg runtime/cgo (darwin-amd64-cgo), method (Handle) Delete() +pkg runtime/cgo (darwin-amd64-cgo), method (Handle) Value() interface{} +pkg runtime/cgo (darwin-amd64-cgo), type Handle uintptr +pkg runtime/cgo (freebsd-386-cgo), func NewHandle(interface{}) Handle +pkg runtime/cgo (freebsd-386-cgo), method (Handle) Delete() +pkg runtime/cgo (freebsd-386-cgo), method (Handle) Value() interface{} +pkg runtime/cgo (freebsd-386-cgo), type Handle uintptr +pkg runtime/cgo (freebsd-amd64-cgo), func NewHandle(interface{}) Handle +pkg runtime/cgo (freebsd-amd64-cgo), method (Handle) Delete() +pkg runtime/cgo (freebsd-amd64-cgo), method (Handle) Value() interface{} +pkg runtime/cgo (freebsd-amd64-cgo), type Handle uintptr +pkg runtime/cgo (freebsd-arm-cgo), func NewHandle(interface{}) Handle +pkg runtime/cgo (freebsd-arm-cgo), method (Handle) Delete() +pkg runtime/cgo (freebsd-arm-cgo), method (Handle) Value() interface{} +pkg runtime/cgo (freebsd-arm-cgo), type Handle uintptr +pkg runtime/cgo (linux-386-cgo), func NewHandle(interface{}) Handle +pkg runtime/cgo (linux-386-cgo), method (Handle) Delete() +pkg runtime/cgo (linux-386-cgo), method (Handle) Value() interface{} +pkg runtime/cgo (linux-386-cgo), type Handle uintptr +pkg runtime/cgo (linux-amd64-cgo), func NewHandle(interface{}) Handle +pkg runtime/cgo (linux-amd64-cgo), method (Handle) Delete() +pkg runtime/cgo (linux-amd64-cgo), method (Handle) Value() interface{} +pkg runtime/cgo (linux-amd64-cgo), type Handle uintptr +pkg runtime/cgo (linux-arm-cgo), func NewHandle(interface{}) Handle +pkg runtime/cgo (linux-arm-cgo), method (Handle) Delete() +pkg runtime/cgo (linux-arm-cgo), method (Handle) Value() interface{} +pkg runtime/cgo (linux-arm-cgo), type Handle uintptr +pkg runtime/cgo (netbsd-386-cgo), func NewHandle(interface{}) Handle +pkg runtime/cgo (netbsd-386-cgo), method (Handle) Delete() +pkg runtime/cgo (netbsd-386-cgo), method (Handle) Value() interface{} +pkg runtime/cgo (netbsd-386-cgo), type Handle uintptr +pkg runtime/cgo (netbsd-amd64-cgo), func NewHandle(interface{}) Handle +pkg runtime/cgo (netbsd-amd64-cgo), method (Handle) Delete() +pkg runtime/cgo (netbsd-amd64-cgo), method (Handle) Value() interface{} +pkg runtime/cgo (netbsd-amd64-cgo), type Handle uintptr +pkg runtime/cgo (netbsd-arm-cgo), func NewHandle(interface{}) Handle +pkg runtime/cgo (netbsd-arm-cgo), method (Handle) Delete() +pkg runtime/cgo (netbsd-arm-cgo), method (Handle) Value() interface{} +pkg runtime/cgo (netbsd-arm-cgo), type Handle uintptr +pkg runtime/cgo (netbsd-arm64-cgo), func NewHandle(interface{}) Handle +pkg runtime/cgo (netbsd-arm64-cgo), method (Handle) Delete() +pkg runtime/cgo (netbsd-arm64-cgo), method (Handle) Value() interface{} +pkg runtime/cgo (netbsd-arm64-cgo), type Handle uintptr +pkg runtime/cgo (openbsd-386-cgo), func NewHandle(interface{}) Handle +pkg runtime/cgo (openbsd-386-cgo), method (Handle) Delete() +pkg runtime/cgo (openbsd-386-cgo), method (Handle) Value() interface{} +pkg runtime/cgo (openbsd-386-cgo), type Handle uintptr +pkg runtime/cgo (openbsd-amd64-cgo), func NewHandle(interface{}) Handle +pkg runtime/cgo (openbsd-amd64-cgo), method (Handle) Delete() +pkg runtime/cgo (openbsd-amd64-cgo), method (Handle) Value() interface{} +pkg runtime/cgo (openbsd-amd64-cgo), type Handle uintptr +pkg syscall (openbsd-386), const MSG_CMSG_CLOEXEC = 2048 +pkg syscall (openbsd-386), const MSG_CMSG_CLOEXEC ideal-int +pkg syscall (openbsd-386-cgo), const MSG_CMSG_CLOEXEC = 2048 +pkg syscall (openbsd-386-cgo), const MSG_CMSG_CLOEXEC ideal-int +pkg syscall (openbsd-amd64), const MSG_CMSG_CLOEXEC = 2048 +pkg syscall (openbsd-amd64), const MSG_CMSG_CLOEXEC ideal-int +pkg syscall (openbsd-amd64-cgo), const MSG_CMSG_CLOEXEC = 2048 +pkg syscall (openbsd-amd64-cgo), const MSG_CMSG_CLOEXEC ideal-int +pkg syscall (windows-386), type SysProcAttr struct, AdditionalInheritedHandles []Handle +pkg syscall (windows-386), type SysProcAttr struct, ParentProcess Handle +pkg syscall (windows-amd64), type SysProcAttr struct, AdditionalInheritedHandles []Handle +pkg syscall (windows-amd64), type SysProcAttr struct, ParentProcess Handle - pkg testing, method (*B) Setenv(string, string) +pkg testing, func Fuzz(func(*F)) FuzzResult +pkg testing, func MainStart(testDeps, []InternalTest, []InternalBenchmark, []InternalFuzzTarget, []InternalExample) *M +pkg testing, func RunFuzzTargets(func(string, string) (bool, error), []InternalFuzzTarget) bool +pkg testing, func RunFuzzing(func(string, string) (bool, error), []InternalFuzzTarget) bool ++pkg testing, method (*B) Setenv(string, string) +pkg testing, method (*F) Add(...interface{}) +pkg testing, method (*F) Cleanup(func()) +pkg testing, method (*F) Error(...interface{}) +pkg testing, method (*F) Errorf(string, ...interface{}) +pkg testing, method (*F) Fail() +pkg testing, method (*F) FailNow() +pkg testing, method (*F) Failed() bool +pkg testing, method (*F) Fatal(...interface{}) +pkg testing, method (*F) Fatalf(string, ...interface{}) +pkg testing, method (*F) Fuzz(interface{}) +pkg testing, method (*F) Helper() +pkg testing, method (*F) Log(...interface{}) +pkg testing, method (*F) Logf(string, ...interface{}) +pkg testing, method (*F) Name() string ++pkg testing, method (*F) Setenv(string, string) +pkg testing, method (*F) Skip(...interface{}) +pkg testing, method (*F) SkipNow() +pkg testing, method (*F) Skipf(string, ...interface{}) +pkg testing, method (*F) Skipped() bool +pkg testing, method (*F) TempDir() string +pkg testing, method (*T) Setenv(string, string) +pkg testing, method (FuzzResult) String() string +pkg testing, type F struct +pkg testing, type FuzzResult struct +pkg testing, type FuzzResult struct, Crasher entry +pkg testing, type FuzzResult struct, Error error +pkg testing, type FuzzResult struct, N int +pkg testing, type FuzzResult struct, T time.Duration +pkg testing, type InternalFuzzTarget struct +pkg testing, type InternalFuzzTarget struct, Fn func(*F) +pkg testing, type InternalFuzzTarget struct, Name string +pkg text/template/parse, const SkipFuncCheck = 2 +pkg text/template/parse, const SkipFuncCheck Mode +pkg time, func UnixMicro(int64) Time +pkg time, func UnixMilli(int64) Time +pkg time, method (*Time) IsDST() bool +pkg time, method (Time) UnixMicro() int64 +pkg time, method (Time) UnixMilli() int64 - >>>>>>> origin/master diff --cc src/testing/fuzz.go index d62eb55dec,0000000000..6f5cdcc389 mode 100644,000000..100644 --- a/src/testing/fuzz.go +++ b/src/testing/fuzz.go @@@ -1,732 -1,0 +1,737 @@@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package testing + +import ( + "errors" + "flag" + "fmt" + "io" + "os" + "path/filepath" + "reflect" + "runtime" + "sync/atomic" + "time" +) + +func initFuzzFlags() { + matchFuzz = flag.String("test.fuzz", "", "run the fuzz target matching `regexp`") + flag.Var(&fuzzDuration, "test.fuzztime", "time to spend fuzzing; default is to run indefinitely") + flag.Var(&minimizeDuration, "test.fuzzminimizetime", "time to spend minimizing a value after finding a crash") + fuzzCacheDir = flag.String("test.fuzzcachedir", "", "directory where interesting fuzzing inputs are stored") + isFuzzWorker = flag.Bool("test.fuzzworker", false, "coordinate with the parent process to fuzz random values") +} + +var ( + matchFuzz *string + fuzzDuration durationOrCountFlag + minimizeDuration = durationOrCountFlag{d: 60 * time.Second} + fuzzCacheDir *string + isFuzzWorker *bool + + // corpusDir is the parent directory of the target's seed corpus within + // the package. + corpusDir = "testdata/corpus" +) + +// fuzzWorkerExitCode is used as an exit code by fuzz worker processes after an internal error. +// This distinguishes internal errors from uncontrolled panics and other crashes. +// Keep in sync with internal/fuzz.workerExitCode. +const fuzzWorkerExitCode = 70 + +// InternalFuzzTarget is an internal type but exported because it is cross-package; +// it is part of the implementation of the "go test" command. +type InternalFuzzTarget struct { + Name string + Fn func(f *F) +} + +// F is a type passed to fuzz targets for fuzz testing. +type F struct { + common + fuzzContext *fuzzContext + testContext *testContext + inFuzzFn bool // set to true when fuzz function is running + corpus []corpusEntry // corpus is the in-memory corpus + result FuzzResult // result is the result of running the fuzz target + fuzzCalled bool +} + +var _ TB = (*F)(nil) + +// corpusEntry is an alias to the same type as internal/fuzz.CorpusEntry. +// We use a type alias because we don't want to export this type, and we can't +// importing internal/fuzz from testing. +type corpusEntry = struct { + Parent string + Name string + Data []byte + Values []interface{} + Generation int +} + +// Cleanup registers a function to be called when the test and all its +// subtests complete. Cleanup functions will be called in last added, +// first called order. +func (f *F) Cleanup(fn func()) { + if f.inFuzzFn { + panic("testing: f.Cleanup was called inside the f.Fuzz function, use t.Cleanup instead") + } + f.common.Helper() + f.common.Cleanup(fn) +} + +// Error is equivalent to Log followed by Fail. +func (f *F) Error(args ...interface{}) { + if f.inFuzzFn { + panic("testing: f.Error was called inside the f.Fuzz function, use t.Error instead") + } + f.common.Helper() + f.common.Error(args...) +} + +// Errorf is equivalent to Logf followed by Fail. +func (f *F) Errorf(format string, args ...interface{}) { + if f.inFuzzFn { + panic("testing: f.Errorf was called inside the f.Fuzz function, use t.Errorf instead") + } + f.common.Helper() + f.common.Errorf(format, args...) +} + +// Fail marks the function as having failed but continues execution. +func (f *F) Fail() { + if f.inFuzzFn { + panic("testing: f.Fail was called inside the f.Fuzz function, use t.Fail instead") + } + f.common.Helper() + f.common.Fail() +} + +// FailNow marks the function as having failed and stops its execution +// by calling runtime.Goexit (which then runs all deferred calls in the +// current goroutine). +// Execution will continue at the next test or benchmark. +// FailNow must be called from the goroutine running the +// test or benchmark function, not from other goroutines +// created during the test. Calling FailNow does not stop +// those other goroutines. +func (f *F) FailNow() { + if f.inFuzzFn { + panic("testing: f.FailNow was called inside the f.Fuzz function, use t.FailNow instead") + } + f.common.Helper() + f.common.FailNow() +} + +// Fatal is equivalent to Log followed by FailNow. +func (f *F) Fatal(args ...interface{}) { + if f.inFuzzFn { + panic("testing: f.Fatal was called inside the f.Fuzz function, use t.Fatal instead") + } + f.common.Helper() + f.common.Fatal(args...) +} + +// Fatalf is equivalent to Logf followed by FailNow. +func (f *F) Fatalf(format string, args ...interface{}) { + if f.inFuzzFn { + panic("testing: f.Fatalf was called inside the f.Fuzz function, use t.Fatalf instead") + } + f.common.Helper() + f.common.Fatalf(format, args...) +} + +// Helper marks the calling function as a test helper function. +// When printing file and line information, that function will be skipped. +// Helper may be called simultaneously from multiple goroutines. +func (f *F) Helper() { + if f.inFuzzFn { + panic("testing: f.Helper was called inside the f.Fuzz function, use t.Helper instead") + } + + // common.Helper is inlined here. + // If we called it, it would mark F.Helper as the helper + // instead of the caller. + f.mu.Lock() + defer f.mu.Unlock() + if f.helperPCs == nil { + f.helperPCs = make(map[uintptr]struct{}) + } + // repeating code from callerName here to save walking a stack frame + var pc [1]uintptr + n := runtime.Callers(2, pc[:]) // skip runtime.Callers + Helper + if n == 0 { + panic("testing: zero callers found") + } + if _, found := f.helperPCs[pc[0]]; !found { + f.helperPCs[pc[0]] = struct{}{} + f.helperNames = nil // map will be recreated next time it is needed + } +} + ++// Setenv is not supported since fuzzing runs in parallel. ++func (f *F) Setenv(key, value string) { ++ panic("testing: f.Setenv is not supported") ++} ++ +// Skip is equivalent to Log followed by SkipNow. +func (f *F) Skip(args ...interface{}) { + if f.inFuzzFn { + panic("testing: f.Skip was called inside the f.Fuzz function, use t.Skip instead") + } + f.common.Helper() + f.common.Skip(args...) +} + +// SkipNow marks the test as having been skipped and stops its execution +// by calling runtime.Goexit. +// If a test fails (see Error, Errorf, Fail) and is then skipped, +// it is still considered to have failed. +// Execution will continue at the next test or benchmark. See also FailNow. +// SkipNow must be called from the goroutine running the test, not from +// other goroutines created during the test. Calling SkipNow does not stop +// those other goroutines. +func (f *F) SkipNow() { + if f.inFuzzFn { + panic("testing: f.SkipNow was called inside the f.Fuzz function, use t.SkipNow instead") + } + f.common.Helper() + f.common.SkipNow() +} + +// Skipf is equivalent to Logf followed by SkipNow. +func (f *F) Skipf(format string, args ...interface{}) { + if f.inFuzzFn { + panic("testing: f.Skipf was called inside the f.Fuzz function, use t.Skipf instead") + } + f.common.Helper() + f.common.Skipf(format, args...) +} + +// TempDir returns a temporary directory for the test to use. +// The directory is automatically removed by Cleanup when the test and +// all its subtests complete. +// Each subsequent call to t.TempDir returns a unique directory; +// if the directory creation fails, TempDir terminates the test by calling Fatal. +func (f *F) TempDir() string { + if f.inFuzzFn { + panic("testing: f.TempDir was called inside the f.Fuzz function, use t.TempDir instead") + } + f.common.Helper() + return f.common.TempDir() +} + +// Add will add the arguments to the seed corpus for the fuzz target. This will +// be a no-op if called after or within the Fuzz function. The args must match +// or be convertible to those in the Fuzz function. +func (f *F) Add(args ...interface{}) { + var values []interface{} + for i := range args { + if t := reflect.TypeOf(args[i]); !supportedTypes[t] { + panic(fmt.Sprintf("testing: unsupported type to Add %v", t)) + } + values = append(values, args[i]) + } + f.corpus = append(f.corpus, corpusEntry{Values: values, Name: fmt.Sprintf("seed#%d", len(f.corpus))}) +} + +// supportedTypes represents all of the supported types which can be fuzzed. +var supportedTypes = map[reflect.Type]bool{ + reflect.TypeOf(([]byte)("")): true, + reflect.TypeOf((string)("")): true, + reflect.TypeOf((bool)(false)): true, + reflect.TypeOf((byte)(0)): true, + reflect.TypeOf((rune)(0)): true, + reflect.TypeOf((float32)(0)): true, + reflect.TypeOf((float64)(0)): true, + reflect.TypeOf((int)(0)): true, + reflect.TypeOf((int8)(0)): true, + reflect.TypeOf((int16)(0)): true, + reflect.TypeOf((int32)(0)): true, + reflect.TypeOf((int64)(0)): true, + reflect.TypeOf((uint)(0)): true, + reflect.TypeOf((uint8)(0)): true, + reflect.TypeOf((uint16)(0)): true, + reflect.TypeOf((uint32)(0)): true, + reflect.TypeOf((uint64)(0)): true, +} + +// Fuzz runs the fuzz function, ff, for fuzz testing. If ff fails for a set of +// arguments, those arguments will be added to the seed corpus. +// +// ff must be a function with no return value whose first argument is *T and +// whose remaining arguments are the types to be fuzzed. +// For example: +// +// 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. +// +// This is a terminal function which will terminate the currently running fuzz +// target by calling runtime.Goexit. +// To run any code after fuzzing stops, use (*F).Cleanup. +func (f *F) Fuzz(ff interface{}) { + if f.fuzzCalled { + panic("testing: F.Fuzz called more than once") + } + f.fuzzCalled = true + if f.failed { + return + } + f.Helper() + + // ff should be in the form func(*testing.T, ...interface{}) + fn := reflect.ValueOf(ff) + fnType := fn.Type() + if fnType.Kind() != reflect.Func { + panic("testing: F.Fuzz must receive a function") + } + if fnType.NumIn() < 2 || fnType.In(0) != reflect.TypeOf((*T)(nil)) { + panic("testing: F.Fuzz function must receive at least two arguments, where the first argument is a *T") + } + + // Save the types of the function to compare against the corpus. + var types []reflect.Type + for i := 1; i < fnType.NumIn(); i++ { + t := fnType.In(i) + if !supportedTypes[t] { + panic(fmt.Sprintf("testing: unsupported type for fuzzing %v", t)) + } + types = append(types, t) + } + + // Check the corpus provided by f.Add + for _, c := range f.corpus { + if err := f.fuzzContext.checkCorpus(c.Values, types); err != nil { + // TODO: Is there a way to save which line number is associated + // with the f.Add call that failed? + f.Fatal(err) + } + } + + // Load seed corpus + c, err := f.fuzzContext.readCorpus(filepath.Join(corpusDir, f.name), types) + if err != nil { + f.Fatal(err) + } + f.corpus = append(f.corpus, c...) + + // run calls fn on a given input, as a subtest with its own T. + // run is analogous to T.Run. The test filtering and cleanup works similarly. + // fn is called in its own goroutine. + // + // TODO(jayconrod,katiehockman): dedupe testdata corpus with entries from f.Add + run := func(e corpusEntry) error { + if e.Values == nil { + // Every code path should have already unmarshaled Data into Values. + // It's our fault if it didn't. + panic(fmt.Sprintf("corpus file %q was not unmarshaled", e.Name)) + } + if shouldFailFast() { + return nil + } + testName := f.common.name + if e.Name != "" { + testName = fmt.Sprintf("%s/%s", testName, e.Name) + } + + // Record the stack trace at the point of this call so that if the subtest + // function - which runs in a separate stack - is marked as a helper, we can + // continue walking the stack into the parent test. + var pc [maxStackLen]uintptr + n := runtime.Callers(2, pc[:]) + t := &T{ + common: common{ + barrier: make(chan bool), + signal: make(chan bool), + name: testName, + parent: &f.common, + level: f.level + 1, + creator: pc[:n], + chatty: f.chatty, + fuzzing: true, + }, + context: f.testContext, + } + t.w = indenter{&t.common} + if t.chatty != nil { + t.chatty.Updatef(t.name, "=== RUN %s\n", t.name) + } + f.inFuzzFn = true + go tRunner(t, func(t *T) { + args := []reflect.Value{reflect.ValueOf(t)} + for _, v := range e.Values { + args = append(args, reflect.ValueOf(v)) + } + // Before reseting the current coverage, defer the snapshot so that we + // make sure it is called right before the tRunner function exits, + // regardless of whether it was executed cleanly, panicked, or if the + // fuzzFn called t.Fatal. + defer f.fuzzContext.snapshotCoverage() + f.fuzzContext.resetCoverage() + fn.Call(args) + }) + <-t.signal + f.inFuzzFn = false + if t.Failed() { + return errors.New(string(f.output)) + } + return nil + } + + switch { + case f.fuzzContext.coordinateFuzzing != nil: + // Fuzzing is enabled, and this is the test process started by 'go test'. + // Act as the coordinator process, and coordinate workers to perform the + // actual fuzzing. + corpusTargetDir := filepath.Join(corpusDir, f.name) + cacheTargetDir := filepath.Join(*fuzzCacheDir, f.name) + err := f.fuzzContext.coordinateFuzzing( + fuzzDuration.d, + int64(fuzzDuration.n), + minimizeDuration.d, + int64(minimizeDuration.n), + *parallel, + f.corpus, + types, + corpusTargetDir, + cacheTargetDir) + if err != nil { + f.result = FuzzResult{Error: err} + f.Fail() + fmt.Fprintf(f.w, "%v\n", err) + if crashErr, ok := err.(fuzzCrashError); ok { + crashName := crashErr.CrashName() + fmt.Fprintf(f.w, "Crash written to %s\n", filepath.Join("testdata/corpus", f.name, crashName)) + fmt.Fprintf(f.w, "To re-run:\ngo test %s -run=%s/%s\n", f.fuzzContext.importPath(), f.name, crashName) + } + } + // TODO(jayconrod,katiehockman): Aggregate statistics across workers + // and add to FuzzResult (ie. time taken, num iterations) + + case f.fuzzContext.runFuzzWorker != nil: + // Fuzzing is enabled, and this is a worker process. Follow instructions + // from the coordinator. + if err := f.fuzzContext.runFuzzWorker(run); err != nil { + // Internal errors are marked with f.Fail; user code may call this too, before F.Fuzz. + // The worker will exit with fuzzWorkerExitCode, indicating this is a failure + // (and 'go test' should exit non-zero) but a crasher should not be recorded. + f.Errorf("communicating with fuzzing coordinator: %v", err) + } + + default: + // Fuzzing is not enabled, or will be done later. Only run the seed + // corpus now. + for _, e := range f.corpus { + run(e) + } + } + + // Record that the fuzz function (or coordinateFuzzing or runFuzzWorker) + // returned normally. This is used to distinguish runtime.Goexit below + // from panic(nil). + f.finished = true + + // Terminate the goroutine. F.Fuzz should not return. + // We cannot call runtime.Goexit from a deferred function: if there is a + // panic, that would replace the panic value with nil. + runtime.Goexit() +} + +func (f *F) report() { + if *isFuzzWorker || f.parent == nil { + return + } + dstr := fmtDuration(f.duration) + format := "--- %s: %s (%s)\n" + if f.Failed() { + f.flushToParent(f.name, format, "FAIL", f.name, dstr) + } else if f.chatty != nil { + if f.Skipped() { + f.flushToParent(f.name, format, "SKIP", f.name, dstr) + } else { + f.flushToParent(f.name, format, "PASS", f.name, dstr) + } + } +} + +// FuzzResult contains the results of a fuzz run. +type FuzzResult struct { + N int // The number of iterations. + T time.Duration // The total time taken. + Error error // Error is the error from the crash +} + +func (r FuzzResult) String() string { + s := "" + if r.Error == nil { + return s + } + s = fmt.Sprintf("%s", r.Error.Error()) + return s +} + +// fuzzCrashError is satisfied by a crash detected within the fuzz function. +// These errors are written to the seed corpus and can be re-run with 'go test'. +// Errors within the fuzzing framework (like I/O errors between coordinator +// and worker processes) don't satisfy this interface. +type fuzzCrashError interface { + error + Unwrap() error + + // CrashName returns the name of the subtest that corresponds to the saved + // crash input file in the seed corpus. The test can be re-run with + // go test $pkg -run=$target/$name where $pkg is the package's import path, + // $target is the fuzz target name, and $name is the string returned here. + CrashName() string +} + +// fuzzContext holds all fields that are common to all fuzz targets. +type fuzzContext struct { + importPath func() string + coordinateFuzzing func(time.Duration, int64, time.Duration, int64, int, []corpusEntry, []reflect.Type, string, string) error + runFuzzWorker func(func(corpusEntry) error) error + readCorpus func(string, []reflect.Type) ([]corpusEntry, error) + checkCorpus func(vals []interface{}, types []reflect.Type) error + resetCoverage func() + snapshotCoverage func() +} + +// runFuzzTargets runs the fuzz targets matching the pattern for -run. This will +// only run the f.Fuzz function for each seed corpus without using the fuzzing +// engine to generate or mutate inputs. +func runFuzzTargets(deps testDeps, fuzzTargets []InternalFuzzTarget, deadline time.Time) (ran, ok bool) { + ok = true + if len(fuzzTargets) == 0 || *isFuzzWorker { + return ran, ok + } + m := newMatcher(deps.MatchString, *match, "-test.run") + tctx := newTestContext(*parallel, m) + tctx.deadline = deadline + fctx := &fuzzContext{ + importPath: deps.ImportPath, + readCorpus: deps.ReadCorpus, + checkCorpus: deps.CheckCorpus, + resetCoverage: deps.ResetCoverage, + snapshotCoverage: deps.SnapshotCoverage, + } + root := common{w: os.Stdout} // gather output in one place + if Verbose() { + root.chatty = newChattyPrinter(root.w) + } + for _, ft := range fuzzTargets { + if shouldFailFast() { + break + } + testName, matched, _ := tctx.match.fullName(nil, ft.Name) + if !matched { + continue + } + f := &F{ + common: common{ + signal: make(chan bool), + barrier: make(chan bool), + name: testName, + parent: &root, + level: root.level + 1, + chatty: root.chatty, + }, + testContext: tctx, + fuzzContext: fctx, + } + f.w = indenter{&f.common} + if f.chatty != nil { + f.chatty.Updatef(f.name, "=== RUN %s\n", f.name) + } + + go fRunner(f, ft.Fn) + <-f.signal + } + return root.ran, !root.Failed() +} + +// runFuzzing runs the fuzz target matching the pattern for -fuzz. Only one such +// fuzz target must match. This will run the fuzzing engine to generate and +// mutate new inputs against the f.Fuzz function. +// +// If fuzzing is disabled (-test.fuzz is not set), runFuzzing +// returns immediately. +func runFuzzing(deps testDeps, fuzzTargets []InternalFuzzTarget) (ran, ok bool) { + // TODO(katiehockman,jayconrod): Should we do something special to make sure + // we don't print f.Log statements again with runFuzzing, since we already + // would have printed them when we ran runFuzzTargets (ie. seed corpus run)? + if len(fuzzTargets) == 0 || *matchFuzz == "" { + return false, true + } + m := newMatcher(deps.MatchString, *matchFuzz, "-test.fuzz") + tctx := newTestContext(1, m) + fctx := &fuzzContext{ + importPath: deps.ImportPath, + readCorpus: deps.ReadCorpus, + checkCorpus: deps.CheckCorpus, + resetCoverage: deps.ResetCoverage, + snapshotCoverage: deps.SnapshotCoverage, + } + root := common{w: os.Stdout} + if *isFuzzWorker { + root.w = io.Discard + fctx.runFuzzWorker = deps.RunFuzzWorker + } else { + fctx.coordinateFuzzing = deps.CoordinateFuzzing + } + if Verbose() && !*isFuzzWorker { + root.chatty = newChattyPrinter(root.w) + } + var target *InternalFuzzTarget + var f *F + for i := range fuzzTargets { + ft := &fuzzTargets[i] + testName, matched, _ := tctx.match.fullName(nil, ft.Name) + if !matched { + continue + } + if target != nil { + fmt.Fprintln(os.Stderr, "testing: warning: -fuzz matches more than one target, won't fuzz") + return false, true + } + target = ft + f = &F{ + common: common{ + signal: make(chan bool), + barrier: nil, // T.Parallel has no effect when fuzzing. + name: testName, + parent: &root, + level: root.level + 1, + chatty: root.chatty, + }, + fuzzContext: fctx, + testContext: tctx, + } + f.w = indenter{&f.common} + } + if target == nil { + return false, true + } + if f.chatty != nil { + f.chatty.Updatef(f.name, "=== FUZZ %s\n", f.name) + } + go fRunner(f, target.Fn) + <-f.signal + return f.ran, !f.failed +} + +// fRunner wraps a call to a fuzz target and ensures that cleanup functions are +// called and status flags are set. fRunner should be called in its own +// goroutine. To wait for its completion, receive f.signal. +// +// fRunner is analogous with tRunner, which wraps subtests started with T.Run. +// Tests and fuzz targets work a little differently, so for now, these functions +// aren't consolidated. In particular, because there are no F.Run and F.Parallel +// methods, i.e., no fuzz sub-targets or parallel fuzz targets, a few +// simplifications are made. We also require that F.Fuzz, F.Skip, or F.Fail is +// called. +func fRunner(f *F, fn func(*F)) { + // When this goroutine is done, either because runtime.Goexit was called, + // a panic started, or fn returned normally, record the duration and send + // t.signal, indicating the fuzz target is done. + defer func() { + // Detect whether the fuzz target panicked or called runtime.Goexit without + // calling F.Fuzz, F.Fail, or F.Skip. If it did, panic (possibly replacing + // a nil panic value). Nothing should recover after fRunner unwinds, + // so this should crash the process with a stack. Unfortunately, recovering + // here adds stack frames, but the location of the original panic should + // still be clear. + if f.Failed() { + atomic.AddUint32(&numFailed, 1) + } + err := recover() + f.mu.RLock() + ok := f.skipped || f.failed || (f.fuzzCalled && f.finished) + f.mu.RUnlock() + if err == nil && !ok { + err = errNilPanicOrGoexit + } + + // Use a deferred call to ensure that we report that the test is + // complete even if a cleanup function calls t.FailNow. See issue 41355. + didPanic := false + defer func() { + if didPanic { + return + } + if err != nil { + panic(err) + } + // Only report that the test is complete if it doesn't panic, + // as otherwise the test binary can exit before the panic is + // reported to the user. See issue 41479. + f.signal <- true + }() + + // If we recovered a panic or inappropriate runtime.Goexit, fail the test, + // flush the output log up to the root, then panic. + doPanic := func(err interface{}) { + f.Fail() + if r := f.runCleanup(recoverAndReturnPanic); r != nil { + f.Logf("cleanup panicked with %v", r) + } + for root := &f.common; root.parent != nil; root = root.parent { + root.mu.Lock() + root.duration += time.Since(root.start) + d := root.duration + root.mu.Unlock() + root.flushToParent(root.name, "--- FAIL: %s (%s)\n", root.name, fmtDuration(d)) + } + didPanic = true + panic(err) + } + if err != nil { + doPanic(err) + } + + // No panic or inappropriate Goexit. + f.duration += time.Since(f.start) + + if len(f.sub) > 0 { + // Run parallel inputs. + // Release the parallel subtests. + close(f.barrier) + // Wait for the subtests to complete. + for _, sub := range f.sub { + <-sub.signal + } + cleanupStart := time.Now() + err := f.runCleanup(recoverAndReturnPanic) + f.duration += time.Since(cleanupStart) + if err != nil { + doPanic(err) + } + } + + // Report after all subtests have finished. + f.report() + f.done = true + f.setRan() + }() + defer func() { + if len(f.sub) == 0 { + f.runCleanup(normalPanic) + } + }() + + f.start = time.Now() + fn(f) + + // Code beyond this point is only executed if fn returned normally. + // That means fn did not call F.Fuzz or F.Skip. It should have called F.Fail. + f.mu.Lock() + defer f.mu.Unlock() + if !f.failed { + panic(f.name + " returned without calling F.Fuzz, F.Fail, or F.Skip") + } +}