Add a shim for internal/fuzz
This simply shadows the real code temporarily to see what else is broken. It only defines a single type to fix testing/internal/testdeps.
Этот коммит содержится в:
родитель
20a27746b2
коммит
9cedd78d9c
6 изменённых файлов: 309 добавлений и 9 удалений
|
@ -230,6 +230,7 @@ func pathsToOverride(needsSyscallPackage bool) map[string]bool {
|
||||||
"device/": false,
|
"device/": false,
|
||||||
"examples/": false,
|
"examples/": false,
|
||||||
"internal/": true,
|
"internal/": true,
|
||||||
|
"internal/fuzz/": false,
|
||||||
"internal/bytealg/": false,
|
"internal/bytealg/": false,
|
||||||
"internal/reflectlite/": false,
|
"internal/reflectlite/": false,
|
||||||
"internal/task/": false,
|
"internal/task/": false,
|
||||||
|
|
133
src/internal/fuzz/fuzz.go
Обычный файл
133
src/internal/fuzz/fuzz.go
Обычный файл
|
@ -0,0 +1,133 @@
|
||||||
|
// Package fuzz is a shim to allow compilation against Go 1.18.
|
||||||
|
// It only defines a single type to work with testing/internal/testdeps,
|
||||||
|
// and hide all the other new dependencies from this package.
|
||||||
|
package fuzz
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"reflect"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CorpusEntry represents an individual input for fuzzing.
|
||||||
|
//
|
||||||
|
// We must use an equivalent type in the testing and testing/internal/testdeps
|
||||||
|
// packages, but testing can't import this package directly, and we don't want
|
||||||
|
// to export this type from testing. Instead, we use the same struct type and
|
||||||
|
// use a type alias (not a defined type) for convenience.
|
||||||
|
type CorpusEntry = struct {
|
||||||
|
Parent string
|
||||||
|
|
||||||
|
// Path is the path of the corpus file, if the entry was loaded from disk.
|
||||||
|
// For other entries, including seed values provided by f.Add, Path is the
|
||||||
|
// name of the test, e.g. seed#0 or its hash.
|
||||||
|
Path string
|
||||||
|
|
||||||
|
// Data is the raw input data. Data should only be populated for seed
|
||||||
|
// values. For on-disk corpus files, Data will be nil, as it will be loaded
|
||||||
|
// from disk using Path.
|
||||||
|
Data []byte
|
||||||
|
|
||||||
|
// Values is the unmarshaled values from a corpus file.
|
||||||
|
Values []any
|
||||||
|
|
||||||
|
Generation int
|
||||||
|
|
||||||
|
// IsSeed indicates whether this entry is part of the seed corpus.
|
||||||
|
IsSeed bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// CoordinateFuzzingOpts is a set of arguments for CoordinateFuzzing.
|
||||||
|
// The zero value is valid for each field unless specified otherwise.
|
||||||
|
type CoordinateFuzzingOpts struct {
|
||||||
|
// Log is a writer for logging progress messages and warnings.
|
||||||
|
// If nil, io.Discard will be used instead.
|
||||||
|
Log io.Writer
|
||||||
|
|
||||||
|
// Timeout is the amount of wall clock time to spend fuzzing after the corpus
|
||||||
|
// has loaded. If zero, there will be no time limit.
|
||||||
|
Timeout time.Duration
|
||||||
|
|
||||||
|
// Limit is the number of random values to generate and test. If zero,
|
||||||
|
// there will be no limit on the number of generated values.
|
||||||
|
Limit int64
|
||||||
|
|
||||||
|
// MinimizeTimeout is the amount of wall clock time to spend minimizing
|
||||||
|
// after discovering a crasher. If zero, there will be no time limit. If
|
||||||
|
// MinimizeTimeout and MinimizeLimit are both zero, then minimization will
|
||||||
|
// be disabled.
|
||||||
|
MinimizeTimeout time.Duration
|
||||||
|
|
||||||
|
// MinimizeLimit is the maximum number of calls to the fuzz function to be
|
||||||
|
// made while minimizing after finding a crash. If zero, there will be no
|
||||||
|
// limit. Calls to the fuzz function made when minimizing also count toward
|
||||||
|
// Limit. If MinimizeTimeout and MinimizeLimit are both zero, then
|
||||||
|
// minimization will be disabled.
|
||||||
|
MinimizeLimit int64
|
||||||
|
|
||||||
|
// parallel is the number of worker processes to run in parallel. If zero,
|
||||||
|
// CoordinateFuzzing will run GOMAXPROCS workers.
|
||||||
|
Parallel int
|
||||||
|
|
||||||
|
// Seed is a list of seed values added by the fuzz target with testing.F.Add
|
||||||
|
// and in testdata.
|
||||||
|
Seed []CorpusEntry
|
||||||
|
|
||||||
|
// Types is the list of types which make up a corpus entry.
|
||||||
|
// Types must be set and must match values in Seed.
|
||||||
|
Types []reflect.Type
|
||||||
|
|
||||||
|
// CorpusDir is a directory where files containing values that crash the
|
||||||
|
// code being tested may be written. CorpusDir must be set.
|
||||||
|
CorpusDir string
|
||||||
|
|
||||||
|
// CacheDir is a directory containing additional "interesting" values.
|
||||||
|
// The fuzzer may derive new values from these, and may write new values here.
|
||||||
|
CacheDir string
|
||||||
|
}
|
||||||
|
|
||||||
|
// CoordinateFuzzing creates several worker processes and communicates with
|
||||||
|
// them to test random inputs that could trigger crashes and expose bugs.
|
||||||
|
// The worker processes run the same binary in the same directory with the
|
||||||
|
// same environment variables as the coordinator process. Workers also run
|
||||||
|
// with the same arguments as the coordinator, except with the -test.fuzzworker
|
||||||
|
// flag prepended to the argument list.
|
||||||
|
//
|
||||||
|
// If a crash occurs, the function will return an error containing information
|
||||||
|
// about the crash, which can be reported to the user.
|
||||||
|
func CoordinateFuzzing(ctx context.Context, opts CoordinateFuzzingOpts) (err error) {
|
||||||
|
return errors.New("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadCorpus reads the corpus from the provided dir. The returned corpus
|
||||||
|
// entries are guaranteed to match the given types. Any malformed files will
|
||||||
|
// be saved in a MalformedCorpusError and returned, along with the most recent
|
||||||
|
// error.
|
||||||
|
func ReadCorpus(dir string, types []reflect.Type) ([]CorpusEntry, error) {
|
||||||
|
return nil, errors.New("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckCorpus verifies that the types in vals match the expected types
|
||||||
|
// provided.
|
||||||
|
func CheckCorpus(vals []any, types []reflect.Type) error {
|
||||||
|
return errors.New("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func ResetCoverage() {}
|
||||||
|
func SnapshotCoverage() {}
|
||||||
|
|
||||||
|
// RunFuzzWorker is called in a worker process to communicate with the
|
||||||
|
// coordinator process in order to fuzz random inputs. RunFuzzWorker loops
|
||||||
|
// until the coordinator tells it to stop.
|
||||||
|
//
|
||||||
|
// fn is a wrapper on the fuzz function. It may return an error to indicate
|
||||||
|
// a given input "crashed". The coordinator will also record a crasher if
|
||||||
|
// the function times out or terminates the process.
|
||||||
|
//
|
||||||
|
// RunFuzzWorker returns an error if it could not communicate with the
|
||||||
|
// coordinator process.
|
||||||
|
func RunFuzzWorker(ctx context.Context, fn func(CorpusEntry) error) error {
|
||||||
|
return errors.New("not implemented")
|
||||||
|
}
|
143
src/testing/fuzz.go
Обычный файл
143
src/testing/fuzz.go
Обычный файл
|
@ -0,0 +1,143 @@
|
||||||
|
package testing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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 tests.
|
||||||
|
//
|
||||||
|
// Fuzz tests run generated inputs against a provided fuzz target, which can
|
||||||
|
// find and report potential bugs in the code being tested.
|
||||||
|
//
|
||||||
|
// A fuzz test runs the seed corpus by default, which includes entries provided
|
||||||
|
// by (*F).Add and entries in the testdata/fuzz/<FuzzTestName> directory. After
|
||||||
|
// any necessary setup and calls to (*F).Add, the fuzz test must then call
|
||||||
|
// (*F).Fuzz to provide the fuzz target. See the testing package documentation
|
||||||
|
// for an example, and see the F.Fuzz and F.Add method documentation for
|
||||||
|
// details.
|
||||||
|
//
|
||||||
|
// *F methods can only be called before (*F).Fuzz. Once the test is
|
||||||
|
// executing the fuzz target, only (*T) methods can be used. The only *F methods
|
||||||
|
// that are allowed in the (*F).Fuzz function are (*F).Failed and (*F).Name.
|
||||||
|
type F struct {
|
||||||
|
common
|
||||||
|
fuzzContext *fuzzContext
|
||||||
|
testContext *testContext
|
||||||
|
|
||||||
|
// inFuzzFn is true when the fuzz function is running. Most F methods cannot
|
||||||
|
// be called when inFuzzFn is true.
|
||||||
|
inFuzzFn bool
|
||||||
|
|
||||||
|
// corpus is a set of seed corpus entries, added with F.Add and loaded
|
||||||
|
// from testdata.
|
||||||
|
corpus []corpusEntry
|
||||||
|
|
||||||
|
result fuzzResult
|
||||||
|
fuzzCalled bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// import internal/fuzz from testing.
|
||||||
|
type corpusEntry = struct {
|
||||||
|
Parent string
|
||||||
|
Path string
|
||||||
|
Data []byte
|
||||||
|
Values []interface{}
|
||||||
|
Generation int
|
||||||
|
IsSeed bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add will add the arguments to the seed corpus for the fuzz test. This will be
|
||||||
|
// a no-op if called after or within the fuzz target, and args must match the
|
||||||
|
// arguments for the fuzz target.
|
||||||
|
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, IsSeed: true, Path: 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) { ... })
|
||||||
|
//
|
||||||
|
// The following types are allowed: []byte, string, bool, byte, rune, float32,
|
||||||
|
// float64, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64.
|
||||||
|
// More types may be supported in the future.
|
||||||
|
//
|
||||||
|
// ff must not call any *F methods, e.g. (*F).Log, (*F).Error, (*F).Skip. Use
|
||||||
|
// the corresponding *T method instead. The only *F methods that are allowed in
|
||||||
|
// the (*F).Fuzz function are (*F).Failed and (*F).Name.
|
||||||
|
//
|
||||||
|
// This function should be fast and deterministic, and its behavior should not
|
||||||
|
// depend on shared state. No mutatable input arguments, or pointers to them,
|
||||||
|
// should be retained between executions of the fuzz function, as the memory
|
||||||
|
// backing them may be mutated during a subsequent invocation. ff must not
|
||||||
|
// modify the underlying data of the arguments provided by the fuzzing engine.
|
||||||
|
//
|
||||||
|
// When fuzzing, F.Fuzz does not return until a problem is found, time runs out
|
||||||
|
// (set with -fuzztime), or the test process is interrupted by a signal. F.Fuzz
|
||||||
|
// should be called exactly once, unless F.Skip or F.Fail is called beforehand.
|
||||||
|
func (f *F) Fuzz(ff interface{}) {
|
||||||
|
f.failed = true
|
||||||
|
f.result.N = 0
|
||||||
|
f.result.T = 0
|
||||||
|
f.result.Error = errors.New("operation not implemented")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// fuzzContext holds fields common to all fuzz tests.
|
||||||
|
type fuzzContext struct {
|
||||||
|
deps testDeps
|
||||||
|
mode fuzzMode
|
||||||
|
}
|
||||||
|
|
||||||
|
type fuzzMode uint8
|
||||||
|
|
||||||
|
// 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 failing input
|
||||||
|
}
|
|
@ -430,15 +430,6 @@ type testDeps interface {
|
||||||
MatchString(pat, str string) (bool, error)
|
MatchString(pat, str string) (bool, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MainStart(deps interface{}, tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) *M {
|
|
||||||
Init()
|
|
||||||
return &M{
|
|
||||||
Tests: tests,
|
|
||||||
Benchmarks: benchmarks,
|
|
||||||
deps: deps.(testDeps),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run runs the tests. It returns an exit code to pass to os.Exit.
|
// Run runs the tests. It returns an exit code to pass to os.Exit.
|
||||||
func (m *M) Run() (code int) {
|
func (m *M) Run() (code int) {
|
||||||
defer func() {
|
defer func() {
|
||||||
|
|
16
src/testing/testing_go118.go
Обычный файл
16
src/testing/testing_go118.go
Обычный файл
|
@ -0,0 +1,16 @@
|
||||||
|
//go:build go1.18
|
||||||
|
// +build go1.18
|
||||||
|
|
||||||
|
package testing
|
||||||
|
|
||||||
|
// MainStart is meant for use by tests generated by 'go test'.
|
||||||
|
// It is not meant to be called directly and is not subject to the Go 1 compatibility document.
|
||||||
|
// It may change signature from release to release.
|
||||||
|
func MainStart(deps interface{}, tests []InternalTest, benchmarks []InternalBenchmark, fuzzTargets []InternalFuzzTarget, examples []InternalExample) *M {
|
||||||
|
Init()
|
||||||
|
return &M{
|
||||||
|
Tests: tests,
|
||||||
|
Benchmarks: benchmarks,
|
||||||
|
deps: deps.(testDeps),
|
||||||
|
}
|
||||||
|
}
|
16
src/testing/testing_other.go
Обычный файл
16
src/testing/testing_other.go
Обычный файл
|
@ -0,0 +1,16 @@
|
||||||
|
//go:build !go1.18
|
||||||
|
// +build !go1.18
|
||||||
|
|
||||||
|
package testing
|
||||||
|
|
||||||
|
// MainStart is meant for use by tests generated by 'go test'.
|
||||||
|
// It is not meant to be called directly and is not subject to the Go 1 compatibility document.
|
||||||
|
// It may change signature from release to release.
|
||||||
|
func MainStart(deps interface{}, tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) *M {
|
||||||
|
Init()
|
||||||
|
return &M{
|
||||||
|
Tests: tests,
|
||||||
|
Benchmarks: benchmarks,
|
||||||
|
deps: deps.(testDeps),
|
||||||
|
}
|
||||||
|
}
|
Загрузка…
Создание таблицы
Сослаться в новой задаче