fuzz.go 22 KB

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