1// Copyright 2020 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package testing
6
7import (
8	"errors"
9	"flag"
10	"fmt"
11	"io"
12	"os"
13	"path/filepath"
14	"reflect"
15	"runtime"
16	"strings"
17	"time"
18)
19
20func initFuzzFlags() {
21	matchFuzz = flag.String("test.fuzz", "", "run the fuzz test matching `regexp`")
22	flag.Var(&fuzzDuration, "test.fuzztime", "time to spend fuzzing; default is to run indefinitely")
23	flag.Var(&minimizeDuration, "test.fuzzminimizetime", "time to spend minimizing a value after finding a failing input")
24
25	fuzzCacheDir = flag.String("test.fuzzcachedir", "", "directory where interesting fuzzing inputs are stored (for use only by cmd/go)")
26	isFuzzWorker = flag.Bool("test.fuzzworker", false, "coordinate with the parent process to fuzz random values (for use only by cmd/go)")
27}
28
29var (
30	matchFuzz        *string
31	fuzzDuration     durationOrCountFlag
32	minimizeDuration = durationOrCountFlag{d: 60 * time.Second, allowZero: true}
33	fuzzCacheDir     *string
34	isFuzzWorker     *bool
35
36	// corpusDir is the parent directory of the fuzz test's seed corpus within
37	// the package.
38	corpusDir = "testdata/fuzz"
39)
40
41// fuzzWorkerExitCode is used as an exit code by fuzz worker processes after an
42// internal error. This distinguishes internal errors from uncontrolled panics
43// and other failures. Keep in sync with internal/fuzz.workerExitCode.
44const fuzzWorkerExitCode = 70
45
46// InternalFuzzTarget is an internal type but exported because it is
47// cross-package; it is part of the implementation of the "go test" command.
48type InternalFuzzTarget struct {
49	Name string
50	Fn   func(f *F)
51}
52
53// F is a type passed to fuzz tests.
54//
55// Fuzz tests run generated inputs against a provided fuzz target, which can
56// find and report potential bugs in the code being tested.
57//
58// A fuzz test runs the seed corpus by default, which includes entries provided
59// by (*F).Add and entries in the testdata/fuzz/<FuzzTestName> directory. After
60// any necessary setup and calls to (*F).Add, the fuzz test must then call
61// (*F).Fuzz to provide the fuzz target. See the testing package documentation
62// for an example, and see the [F.Fuzz] and [F.Add] method documentation for
63// details.
64//
65// *F methods can only be called before (*F).Fuzz. Once the test is
66// executing the fuzz target, only (*T) methods can be used. The only *F methods
67// that are allowed in the (*F).Fuzz function are (*F).Failed and (*F).Name.
68type F struct {
69	common
70	fuzzContext *fuzzContext
71	testContext *testContext
72
73	// inFuzzFn is true when the fuzz function is running. Most F methods cannot
74	// be called when inFuzzFn is true.
75	inFuzzFn bool
76
77	// corpus is a set of seed corpus entries, added with F.Add and loaded
78	// from testdata.
79	corpus []corpusEntry
80
81	result     fuzzResult
82	fuzzCalled bool
83}
84
85var _ TB = (*F)(nil)
86
87// corpusEntry is an alias to the same type as internal/fuzz.CorpusEntry.
88// We use a type alias because we don't want to export this type, and we can't
89// import internal/fuzz from testing.
90type corpusEntry = struct {
91	Parent     string
92	Path       string
93	Data       []byte
94	Values     []any
95	Generation int
96	IsSeed     bool
97}
98
99// Helper marks the calling function as a test helper function.
100// When printing file and line information, that function will be skipped.
101// Helper may be called simultaneously from multiple goroutines.
102func (f *F) Helper() {
103	if f.inFuzzFn {
104		panic("testing: f.Helper was called inside the fuzz target, use t.Helper instead")
105	}
106
107	// common.Helper is inlined here.
108	// If we called it, it would mark F.Helper as the helper
109	// instead of the caller.
110	f.mu.Lock()
111	defer f.mu.Unlock()
112	if f.helperPCs == nil {
113		f.helperPCs = make(map[uintptr]struct{})
114	}
115	// repeating code from callerName here to save walking a stack frame
116	var pc [1]uintptr
117	n := runtime.Callers(2, pc[:]) // skip runtime.Callers + Helper
118	if n == 0 {
119		panic("testing: zero callers found")
120	}
121	if _, found := f.helperPCs[pc[0]]; !found {
122		f.helperPCs[pc[0]] = struct{}{}
123		f.helperNames = nil // map will be recreated next time it is needed
124	}
125}
126
127// Fail marks the function as having failed but continues execution.
128func (f *F) Fail() {
129	// (*F).Fail may be called by (*T).Fail, which we should allow. However, we
130	// shouldn't allow direct (*F).Fail calls from inside the (*F).Fuzz function.
131	if f.inFuzzFn {
132		panic("testing: f.Fail was called inside the fuzz target, use t.Fail instead")
133	}
134	f.common.Helper()
135	f.common.Fail()
136}
137
138// Skipped reports whether the test was skipped.
139func (f *F) Skipped() bool {
140	// (*F).Skipped may be called by tRunner, which we should allow. However, we
141	// shouldn't allow direct (*F).Skipped calls from inside the (*F).Fuzz function.
142	if f.inFuzzFn {
143		panic("testing: f.Skipped was called inside the fuzz target, use t.Skipped instead")
144	}
145	f.common.Helper()
146	return f.common.Skipped()
147}
148
149// Add will add the arguments to the seed corpus for the fuzz test. This will be
150// a no-op if called after or within the fuzz target, and args must match the
151// arguments for the fuzz target.
152func (f *F) Add(args ...any) {
153	var values []any
154	for i := range args {
155		if t := reflect.TypeOf(args[i]); !supportedTypes[t] {
156			panic(fmt.Sprintf("testing: unsupported type to Add %v", t))
157		}
158		values = append(values, args[i])
159	}
160	f.corpus = append(f.corpus, corpusEntry{Values: values, IsSeed: true, Path: fmt.Sprintf("seed#%d", len(f.corpus))})
161}
162
163// supportedTypes represents all of the supported types which can be fuzzed.
164var supportedTypes = map[reflect.Type]bool{
165	reflect.TypeOf(([]byte)("")):  true,
166	reflect.TypeOf((string)("")):  true,
167	reflect.TypeOf((bool)(false)): true,
168	reflect.TypeOf((byte)(0)):     true,
169	reflect.TypeOf((rune)(0)):     true,
170	reflect.TypeOf((float32)(0)):  true,
171	reflect.TypeOf((float64)(0)):  true,
172	reflect.TypeOf((int)(0)):      true,
173	reflect.TypeOf((int8)(0)):     true,
174	reflect.TypeOf((int16)(0)):    true,
175	reflect.TypeOf((int32)(0)):    true,
176	reflect.TypeOf((int64)(0)):    true,
177	reflect.TypeOf((uint)(0)):     true,
178	reflect.TypeOf((uint8)(0)):    true,
179	reflect.TypeOf((uint16)(0)):   true,
180	reflect.TypeOf((uint32)(0)):   true,
181	reflect.TypeOf((uint64)(0)):   true,
182}
183
184// Fuzz runs the fuzz function, ff, for fuzz testing. If ff fails for a set of
185// arguments, those arguments will be added to the seed corpus.
186//
187// ff must be a function with no return value whose first argument is *T and
188// whose remaining arguments are the types to be fuzzed.
189// For example:
190//
191//	f.Fuzz(func(t *testing.T, b []byte, i int) { ... })
192//
193// The following types are allowed: []byte, string, bool, byte, rune, float32,
194// float64, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64.
195// More types may be supported in the future.
196//
197// ff must not call any *F methods, e.g. (*F).Log, (*F).Error, (*F).Skip. Use
198// the corresponding *T method instead. The only *F methods that are allowed in
199// the (*F).Fuzz function are (*F).Failed and (*F).Name.
200//
201// This function should be fast and deterministic, and its behavior should not
202// depend on shared state. No mutable input arguments, or pointers to them,
203// should be retained between executions of the fuzz function, as the memory
204// backing them may be mutated during a subsequent invocation. ff must not
205// modify the underlying data of the arguments provided by the fuzzing engine.
206//
207// When fuzzing, F.Fuzz does not return until a problem is found, time runs out
208// (set with -fuzztime), or the test process is interrupted by a signal. F.Fuzz
209// should be called exactly once, unless F.Skip or [F.Fail] is called beforehand.
210func (f *F) Fuzz(ff any) {
211	if f.fuzzCalled {
212		panic("testing: F.Fuzz called more than once")
213	}
214	f.fuzzCalled = true
215	if f.failed {
216		return
217	}
218	f.Helper()
219
220	// ff should be in the form func(*testing.T, ...interface{})
221	fn := reflect.ValueOf(ff)
222	fnType := fn.Type()
223	if fnType.Kind() != reflect.Func {
224		panic("testing: F.Fuzz must receive a function")
225	}
226	if fnType.NumIn() < 2 || fnType.In(0) != reflect.TypeOf((*T)(nil)) {
227		panic("testing: fuzz target must receive at least two arguments, where the first argument is a *T")
228	}
229	if fnType.NumOut() != 0 {
230		panic("testing: fuzz target must not return a value")
231	}
232
233	// Save the types of the function to compare against the corpus.
234	var types []reflect.Type
235	for i := 1; i < fnType.NumIn(); i++ {
236		t := fnType.In(i)
237		if !supportedTypes[t] {
238			panic(fmt.Sprintf("testing: unsupported type for fuzzing %v", t))
239		}
240		types = append(types, t)
241	}
242
243	// Load the testdata seed corpus. Check types of entries in the testdata
244	// corpus and entries declared with F.Add.
245	//
246	// Don't load the seed corpus if this is a worker process; we won't use it.
247	if f.fuzzContext.mode != fuzzWorker {
248		for _, c := range f.corpus {
249			if err := f.fuzzContext.deps.CheckCorpus(c.Values, types); err != nil {
250				// TODO(#48302): Report the source location of the F.Add call.
251				f.Fatal(err)
252			}
253		}
254
255		// Load seed corpus
256		c, err := f.fuzzContext.deps.ReadCorpus(filepath.Join(corpusDir, f.name), types)
257		if err != nil {
258			f.Fatal(err)
259		}
260		for i := range c {
261			c[i].IsSeed = true // these are all seed corpus values
262			if f.fuzzContext.mode == fuzzCoordinator {
263				// If this is the coordinator process, zero the values, since we don't need
264				// to hold onto them.
265				c[i].Values = nil
266			}
267		}
268
269		f.corpus = append(f.corpus, c...)
270	}
271
272	// run calls fn on a given input, as a subtest with its own T.
273	// run is analogous to T.Run. The test filtering and cleanup works similarly.
274	// fn is called in its own goroutine.
275	run := func(captureOut io.Writer, e corpusEntry) (ok bool) {
276		if e.Values == nil {
277			// The corpusEntry must have non-nil Values in order to run the
278			// test. If Values is nil, it is a bug in our code.
279			panic(fmt.Sprintf("corpus file %q was not unmarshaled", e.Path))
280		}
281		if shouldFailFast() {
282			return true
283		}
284		testName := f.name
285		if e.Path != "" {
286			testName = fmt.Sprintf("%s/%s", testName, filepath.Base(e.Path))
287		}
288		if f.testContext.isFuzzing {
289			// Don't preserve subtest names while fuzzing. If fn calls T.Run,
290			// there will be a very large number of subtests with duplicate names,
291			// which will use a large amount of memory. The subtest names aren't
292			// useful since there's no way to re-run them deterministically.
293			f.testContext.match.clearSubNames()
294		}
295
296		// Record the stack trace at the point of this call so that if the subtest
297		// function - which runs in a separate stack - is marked as a helper, we can
298		// continue walking the stack into the parent test.
299		var pc [maxStackLen]uintptr
300		n := runtime.Callers(2, pc[:])
301		t := &T{
302			common: common{
303				barrier: make(chan bool),
304				signal:  make(chan bool),
305				name:    testName,
306				parent:  &f.common,
307				level:   f.level + 1,
308				creator: pc[:n],
309				chatty:  f.chatty,
310			},
311			context: f.testContext,
312		}
313		if captureOut != nil {
314			// t.parent aliases f.common.
315			t.parent.w = captureOut
316		}
317		t.w = indenter{&t.common}
318		if t.chatty != nil {
319			t.chatty.Updatef(t.name, "=== RUN   %s\n", t.name)
320		}
321		f.common.inFuzzFn, f.inFuzzFn = true, true
322		go tRunner(t, func(t *T) {
323			args := []reflect.Value{reflect.ValueOf(t)}
324			for _, v := range e.Values {
325				args = append(args, reflect.ValueOf(v))
326			}
327			// Before resetting the current coverage, defer the snapshot so that
328			// we make sure it is called right before the tRunner function
329			// exits, regardless of whether it was executed cleanly, panicked,
330			// or if the fuzzFn called t.Fatal.
331			if f.testContext.isFuzzing {
332				defer f.fuzzContext.deps.SnapshotCoverage()
333				f.fuzzContext.deps.ResetCoverage()
334			}
335			fn.Call(args)
336		})
337		<-t.signal
338		if t.chatty != nil && t.chatty.json {
339			t.chatty.Updatef(t.parent.name, "=== NAME  %s\n", t.parent.name)
340		}
341		f.common.inFuzzFn, f.inFuzzFn = false, false
342		return !t.Failed()
343	}
344
345	switch f.fuzzContext.mode {
346	case fuzzCoordinator:
347		// Fuzzing is enabled, and this is the test process started by 'go test'.
348		// Act as the coordinator process, and coordinate workers to perform the
349		// actual fuzzing.
350		corpusTargetDir := filepath.Join(corpusDir, f.name)
351		cacheTargetDir := filepath.Join(*fuzzCacheDir, f.name)
352		err := f.fuzzContext.deps.CoordinateFuzzing(
353			fuzzDuration.d,
354			int64(fuzzDuration.n),
355			minimizeDuration.d,
356			int64(minimizeDuration.n),
357			*parallel,
358			f.corpus,
359			types,
360			corpusTargetDir,
361			cacheTargetDir)
362		if err != nil {
363			f.result = fuzzResult{Error: err}
364			f.Fail()
365			fmt.Fprintf(f.w, "%v\n", err)
366			if crashErr, ok := err.(fuzzCrashError); ok {
367				crashPath := crashErr.CrashPath()
368				fmt.Fprintf(f.w, "Failing input written to %s\n", crashPath)
369				testName := filepath.Base(crashPath)
370				fmt.Fprintf(f.w, "To re-run:\ngo test -run=%s/%s\n", f.name, testName)
371			}
372		}
373		// TODO(jayconrod,katiehockman): Aggregate statistics across workers
374		// and add to FuzzResult (ie. time taken, num iterations)
375
376	case fuzzWorker:
377		// Fuzzing is enabled, and this is a worker process. Follow instructions
378		// from the coordinator.
379		if err := f.fuzzContext.deps.RunFuzzWorker(func(e corpusEntry) error {
380			// Don't write to f.w (which points to Stdout) if running from a
381			// fuzz worker. This would become very verbose, particularly during
382			// minimization. Return the error instead, and let the caller deal
383			// with the output.
384			var buf strings.Builder
385			if ok := run(&buf, e); !ok {
386				return errors.New(buf.String())
387			}
388			return nil
389		}); err != nil {
390			// Internal errors are marked with f.Fail; user code may call this too, before F.Fuzz.
391			// The worker will exit with fuzzWorkerExitCode, indicating this is a failure
392			// (and 'go test' should exit non-zero) but a failing input should not be recorded.
393			f.Errorf("communicating with fuzzing coordinator: %v", err)
394		}
395
396	default:
397		// Fuzzing is not enabled, or will be done later. Only run the seed
398		// corpus now.
399		for _, e := range f.corpus {
400			name := fmt.Sprintf("%s/%s", f.name, filepath.Base(e.Path))
401			if _, ok, _ := f.testContext.match.fullName(nil, name); ok {
402				run(f.w, e)
403			}
404		}
405	}
406}
407
408func (f *F) report() {
409	if *isFuzzWorker || f.parent == nil {
410		return
411	}
412	dstr := fmtDuration(f.duration)
413	format := "--- %s: %s (%s)\n"
414	if f.Failed() {
415		f.flushToParent(f.name, format, "FAIL", f.name, dstr)
416	} else if f.chatty != nil {
417		if f.Skipped() {
418			f.flushToParent(f.name, format, "SKIP", f.name, dstr)
419		} else {
420			f.flushToParent(f.name, format, "PASS", f.name, dstr)
421		}
422	}
423}
424
425// fuzzResult contains the results of a fuzz run.
426type fuzzResult struct {
427	N     int           // The number of iterations.
428	T     time.Duration // The total time taken.
429	Error error         // Error is the error from the failing input
430}
431
432func (r fuzzResult) String() string {
433	if r.Error == nil {
434		return ""
435	}
436	return r.Error.Error()
437}
438
439// fuzzCrashError is satisfied by a failing input detected while fuzzing.
440// These errors are written to the seed corpus and can be re-run with 'go test'.
441// Errors within the fuzzing framework (like I/O errors between coordinator
442// and worker processes) don't satisfy this interface.
443type fuzzCrashError interface {
444	error
445	Unwrap() error
446
447	// CrashPath returns the path of the subtest that corresponds to the saved
448	// crash input file in the seed corpus. The test can be re-run with go test
449	// -run=$test/$name $test is the fuzz test name, and $name is the
450	// filepath.Base of the string returned here.
451	CrashPath() string
452}
453
454// fuzzContext holds fields common to all fuzz tests.
455type fuzzContext struct {
456	deps testDeps
457	mode fuzzMode
458}
459
460type fuzzMode uint8
461
462const (
463	seedCorpusOnly fuzzMode = iota
464	fuzzCoordinator
465	fuzzWorker
466)
467
468// runFuzzTests runs the fuzz tests matching the pattern for -run. This will
469// only run the (*F).Fuzz function for each seed corpus without using the
470// fuzzing engine to generate or mutate inputs.
471func runFuzzTests(deps testDeps, fuzzTests []InternalFuzzTarget, deadline time.Time) (ran, ok bool) {
472	ok = true
473	if len(fuzzTests) == 0 || *isFuzzWorker {
474		return ran, ok
475	}
476	m := newMatcher(deps.MatchString, *match, "-test.run", *skip)
477	var mFuzz *matcher
478	if *matchFuzz != "" {
479		mFuzz = newMatcher(deps.MatchString, *matchFuzz, "-test.fuzz", *skip)
480	}
481
482	for _, procs := range cpuList {
483		runtime.GOMAXPROCS(procs)
484		for i := uint(0); i < *count; i++ {
485			if shouldFailFast() {
486				break
487			}
488
489			tctx := newTestContext(*parallel, m)
490			tctx.deadline = deadline
491			fctx := &fuzzContext{deps: deps, mode: seedCorpusOnly}
492			root := common{w: os.Stdout} // gather output in one place
493			if Verbose() {
494				root.chatty = newChattyPrinter(root.w)
495			}
496			for _, ft := range fuzzTests {
497				if shouldFailFast() {
498					break
499				}
500				testName, matched, _ := tctx.match.fullName(nil, ft.Name)
501				if !matched {
502					continue
503				}
504				if mFuzz != nil {
505					if _, fuzzMatched, _ := mFuzz.fullName(nil, ft.Name); fuzzMatched {
506						// If this will be fuzzed, then don't run the seed corpus
507						// right now. That will happen later.
508						continue
509					}
510				}
511				f := &F{
512					common: common{
513						signal:  make(chan bool),
514						barrier: make(chan bool),
515						name:    testName,
516						parent:  &root,
517						level:   root.level + 1,
518						chatty:  root.chatty,
519					},
520					testContext: tctx,
521					fuzzContext: fctx,
522				}
523				f.w = indenter{&f.common}
524				if f.chatty != nil {
525					f.chatty.Updatef(f.name, "=== RUN   %s\n", f.name)
526				}
527				go fRunner(f, ft.Fn)
528				<-f.signal
529				if f.chatty != nil && f.chatty.json {
530					f.chatty.Updatef(f.parent.name, "=== NAME  %s\n", f.parent.name)
531				}
532				ok = ok && !f.Failed()
533				ran = ran || f.ran
534			}
535			if !ran {
536				// There were no tests to run on this iteration.
537				// This won't change, so no reason to keep trying.
538				break
539			}
540		}
541	}
542
543	return ran, ok
544}
545
546// runFuzzing runs the fuzz test matching the pattern for -fuzz. Only one such
547// fuzz test must match. This will run the fuzzing engine to generate and
548// mutate new inputs against the fuzz target.
549//
550// If fuzzing is disabled (-test.fuzz is not set), runFuzzing
551// returns immediately.
552func runFuzzing(deps testDeps, fuzzTests []InternalFuzzTarget) (ok bool) {
553	if len(fuzzTests) == 0 || *matchFuzz == "" {
554		return true
555	}
556	m := newMatcher(deps.MatchString, *matchFuzz, "-test.fuzz", *skip)
557	tctx := newTestContext(1, m)
558	tctx.isFuzzing = true
559	fctx := &fuzzContext{
560		deps: deps,
561	}
562	root := common{w: os.Stdout}
563	if *isFuzzWorker {
564		root.w = io.Discard
565		fctx.mode = fuzzWorker
566	} else {
567		fctx.mode = fuzzCoordinator
568	}
569	if Verbose() && !*isFuzzWorker {
570		root.chatty = newChattyPrinter(root.w)
571	}
572	var fuzzTest *InternalFuzzTarget
573	var testName string
574	var matched []string
575	for i := range fuzzTests {
576		name, ok, _ := tctx.match.fullName(nil, fuzzTests[i].Name)
577		if !ok {
578			continue
579		}
580		matched = append(matched, name)
581		fuzzTest = &fuzzTests[i]
582		testName = name
583	}
584	if len(matched) == 0 {
585		fmt.Fprintln(os.Stderr, "testing: warning: no fuzz tests to fuzz")
586		return true
587	}
588	if len(matched) > 1 {
589		fmt.Fprintf(os.Stderr, "testing: will not fuzz, -fuzz matches more than one fuzz test: %v\n", matched)
590		return false
591	}
592
593	f := &F{
594		common: common{
595			signal:  make(chan bool),
596			barrier: nil, // T.Parallel has no effect when fuzzing.
597			name:    testName,
598			parent:  &root,
599			level:   root.level + 1,
600			chatty:  root.chatty,
601		},
602		fuzzContext: fctx,
603		testContext: tctx,
604	}
605	f.w = indenter{&f.common}
606	if f.chatty != nil {
607		f.chatty.Updatef(f.name, "=== RUN   %s\n", f.name)
608	}
609	go fRunner(f, fuzzTest.Fn)
610	<-f.signal
611	if f.chatty != nil {
612		f.chatty.Updatef(f.parent.name, "=== NAME  %s\n", f.parent.name)
613	}
614	return !f.failed
615}
616
617// fRunner wraps a call to a fuzz test and ensures that cleanup functions are
618// called and status flags are set. fRunner should be called in its own
619// goroutine. To wait for its completion, receive from f.signal.
620//
621// fRunner is analogous to tRunner, which wraps subtests started with T.Run.
622// Unit tests and fuzz tests work a little differently, so for now, these
623// functions aren't consolidated. In particular, because there are no F.Run and
624// F.Parallel methods, i.e., no fuzz sub-tests or parallel fuzz tests, a few
625// simplifications are made. We also require that F.Fuzz, F.Skip, or F.Fail is
626// called.
627func fRunner(f *F, fn func(*F)) {
628	// When this goroutine is done, either because runtime.Goexit was called, a
629	// panic started, or fn returned normally, record the duration and send
630	// t.signal, indicating the fuzz test is done.
631	defer func() {
632		// Detect whether the fuzz test panicked or called runtime.Goexit
633		// without calling F.Fuzz, F.Fail, or F.Skip. If it did, panic (possibly
634		// replacing a nil panic value). Nothing should recover after fRunner
635		// unwinds, so this should crash the process and print stack.
636		// Unfortunately, recovering here adds stack frames, but the location of
637		// the original panic should still be
638		// clear.
639		f.checkRaces()
640		if f.Failed() {
641			numFailed.Add(1)
642		}
643		err := recover()
644		if err == nil {
645			f.mu.RLock()
646			fuzzNotCalled := !f.fuzzCalled && !f.skipped && !f.failed
647			if !f.finished && !f.skipped && !f.failed {
648				err = errNilPanicOrGoexit
649			}
650			f.mu.RUnlock()
651			if fuzzNotCalled && err == nil {
652				f.Error("returned without calling F.Fuzz, F.Fail, or F.Skip")
653			}
654		}
655
656		// Use a deferred call to ensure that we report that the test is
657		// complete even if a cleanup function calls F.FailNow. See issue 41355.
658		didPanic := false
659		defer func() {
660			if !didPanic {
661				// Only report that the test is complete if it doesn't panic,
662				// as otherwise the test binary can exit before the panic is
663				// reported to the user. See issue 41479.
664				f.signal <- true
665			}
666		}()
667
668		// If we recovered a panic or inappropriate runtime.Goexit, fail the test,
669		// flush the output log up to the root, then panic.
670		doPanic := func(err any) {
671			f.Fail()
672			if r := f.runCleanup(recoverAndReturnPanic); r != nil {
673				f.Logf("cleanup panicked with %v", r)
674			}
675			for root := &f.common; root.parent != nil; root = root.parent {
676				root.mu.Lock()
677				root.duration += highPrecisionTimeSince(root.start)
678				d := root.duration
679				root.mu.Unlock()
680				root.flushToParent(root.name, "--- FAIL: %s (%s)\n", root.name, fmtDuration(d))
681			}
682			didPanic = true
683			panic(err)
684		}
685		if err != nil {
686			doPanic(err)
687		}
688
689		// No panic or inappropriate Goexit.
690		f.duration += highPrecisionTimeSince(f.start)
691
692		if len(f.sub) > 0 {
693			// Unblock inputs that called T.Parallel while running the seed corpus.
694			// This only affects fuzz tests run as normal tests.
695			// While fuzzing, T.Parallel has no effect, so f.sub is empty, and this
696			// branch is not taken. f.barrier is nil in that case.
697			f.testContext.release()
698			close(f.barrier)
699			// Wait for the subtests to complete.
700			for _, sub := range f.sub {
701				<-sub.signal
702			}
703			cleanupStart := highPrecisionTimeNow()
704			err := f.runCleanup(recoverAndReturnPanic)
705			f.duration += highPrecisionTimeSince(cleanupStart)
706			if err != nil {
707				doPanic(err)
708			}
709		}
710
711		// Report after all subtests have finished.
712		f.report()
713		f.done = true
714		f.setRan()
715	}()
716	defer func() {
717		if len(f.sub) == 0 {
718			f.runCleanup(normalPanic)
719		}
720	}()
721
722	f.start = highPrecisionTimeNow()
723	f.resetRaces()
724	fn(f)
725
726	// Code beyond this point will not be executed when FailNow or SkipNow
727	// is invoked.
728	f.mu.Lock()
729	f.finished = true
730	f.mu.Unlock()
731}
732