diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2026-03-06 11:36:44 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2026-03-09 12:29:48 +0000 |
| commit | 176bead5023749b301d573375d79dabee4d0d888 (patch) | |
| tree | d63c6e04860a64a12599c80d50f3b8a5ff27aa4b /pkg/instance/instance.go | |
| parent | 5cb44a80412f4dcfba9693d7d0e4c2ae352acdaa (diff) | |
pkg/aflow/action/crash: collect test coverage
Collect code coverage for test programs.
This is likley to be needed for #6878 and seed generation workflow.
For now it's not wired into any workflow/tool and is not tested.
But this should provide most of the plumbing to wire it up.
Diffstat (limited to 'pkg/instance/instance.go')
| -rw-r--r-- | pkg/instance/instance.go | 86 |
1 files changed, 47 insertions, 39 deletions
diff --git a/pkg/instance/instance.go b/pkg/instance/instance.go index d8b3a8f71..e63dd7808 100644 --- a/pkg/instance/instance.go +++ b/pkg/instance/instance.go @@ -34,7 +34,7 @@ type Env interface { BuildSyzkaller(string, string) (string, error) CleanKernel(*BuildKernelConfig) error BuildKernel(*BuildKernelConfig) (string, build.ImageDetails, error) - Test(numVMs int, reproSyz, reproOpts, reproC []byte) ([]EnvTestResult, error) + Test(numVMs int, reproSyz, reproOpts, reproC []byte, collectCoverage bool) ([]EnvTestResult, error) } type env struct { @@ -258,7 +258,7 @@ func (err *CrashError) Error() string { // Test boots numVMs VMs, tests basic kernel operation, and optionally tests the provided reproducer. // *TestError is returned if there is a problem with kernel/image (crash, reboot loop, etc). // *CrashError is returned if the reproducer crashes kernel. -func (env *env) Test(numVMs int, reproSyz, reproOpts, reproC []byte) ([]EnvTestResult, error) { +func (env *env) Test(numVMs int, reproSyz, reproOpts, reproC []byte, collectCoverage bool) ([]EnvTestResult, error) { if env.testSem != nil { env.testSem.Wait() defer env.testSem.Signal() @@ -279,14 +279,15 @@ func (env *env) Test(numVMs int, reproSyz, reproOpts, reproC []byte) ([]EnvTestR res := make(chan EnvTestResult, numVMs) for i := 0; i < numVMs; i++ { inst := &inst{ - cfg: env.cfg, - optionalFlags: env.optionalFlags, - reporter: reporter, - vmPool: vmPool, - vmIndex: i, - reproSyz: reproSyz, - reproOpts: reproOpts, - reproC: reproC, + cfg: env.cfg, + optionalFlags: env.optionalFlags, + reporter: reporter, + vmPool: vmPool, + vmIndex: i, + reproSyz: reproSyz, + reproOpts: reproOpts, + reproC: reproC, + collectCoverage: collectCoverage, } go func() { res <- inst.test() }() } @@ -298,20 +299,22 @@ func (env *env) Test(numVMs int, reproSyz, reproOpts, reproC []byte) ([]EnvTestR } type inst struct { - cfg *mgrconfig.Config - optionalFlags bool - reporter *report.Reporter - vmPool *vm.Pool - vm *vm.Instance - vmIndex int - reproSyz []byte - reproOpts []byte - reproC []byte + cfg *mgrconfig.Config + optionalFlags bool + reporter *report.Reporter + vmPool *vm.Pool + vm *vm.Instance + vmIndex int + reproSyz []byte + reproOpts []byte + reproC []byte + collectCoverage bool } type EnvTestResult struct { Error error RawOutput []byte + Coverage [][]uint64 } func (inst *inst) test() EnvTestResult { @@ -362,7 +365,7 @@ func (inst *inst) test() EnvTestResult { return ret } if len(inst.reproSyz) != 0 || len(inst.reproC) != 0 { - ret.RawOutput, ret.Error = inst.testRepro() + ret.RawOutput, ret.Coverage, ret.Error = inst.testRepro() } return ret } @@ -403,44 +406,45 @@ func (inst *inst) testInstance() error { return nil } -func (inst *inst) testRepro() ([]byte, error) { +func (inst *inst) testRepro() ([]byte, [][]uint64, error) { execProg, err := SetupExecProg(inst.vm, inst.cfg, inst.reporter, &OptionalConfig{ OldFlagsCompatMode: !inst.optionalFlags, }) if err != nil { - return nil, err + return nil, nil, err } - transformError := func(res *RunResult, err error) ([]byte, error) { + transformError := func(res *RunResult, err error) ([]byte, [][]uint64, error) { if err != nil { - return nil, err + return nil, nil, err } - if res != nil && res.Report != nil { - return res.Output, &CrashError{Report: res.Report} + if res.Report != nil { + err = &CrashError{Report: res.Report} } - return res.Output, nil + return res.Output, res.Coverage, err } - out := []byte{} + out, coverage := []byte{}, [][]uint64{} if len(inst.reproSyz) > 0 { opts, err := inst.csourceOptions() if err != nil { - return nil, err + return nil, nil, err } - out, err = transformError(execProg.RunSyzProg(ExecParams{ - SyzProg: inst.reproSyz, - Duration: inst.cfg.Timeouts.NoOutputRunningTime, - Opts: opts, + out, coverage, err = transformError(execProg.RunSyzProg(ExecParams{ + SyzProg: inst.reproSyz, + Duration: inst.cfg.Timeouts.NoOutputRunningTime, + Opts: opts, + CollectCoverage: inst.collectCoverage, })) if err != nil { - return out, err + return out, coverage, err } } if len(inst.reproC) > 0 { // We should test for more than full "no output" timeout, but the problem is that C reproducers // don't print anything, so we will get a false "no output" crash. - out, err = transformError(execProg.RunCProgRaw(inst.reproC, inst.cfg.Target, + out, _, err = transformError(execProg.RunCProgRaw(inst.reproC, inst.cfg.Target, inst.cfg.Timeouts.NoOutput/2)) } - return out, err + return out, coverage, err } func (inst *inst) csourceOptions() (csource.Options, error) { @@ -462,7 +466,7 @@ func (inst *inst) csourceOptions() (csource.Options, error) { // nolint:revive func ExecprogCmd(execprog, executor, OS, arch, vmType string, opts csource.Options, - optionalFlags bool, slowdown int, progFile string) string { + optionalFlags bool, slowdown int, coverFile, progFile string) string { repeatCount := 1 if opts.Repeat { repeatCount = 0 @@ -488,11 +492,15 @@ func ExecprogCmd(execprog, executor, OS, arch, vmType string, opts csource.Optio {Name: "type", Value: fmt.Sprint(vmType)}, }) } + coverArg := "" + if coverFile != "" { + coverArg = " -cover=%v -coverfile=" + coverFile + } return fmt.Sprintf("%v -executor=%v -arch=%v%v -sandbox=%v"+ - " -procs=%v -repeat=%v -threaded=%v -collide=%v -cover=0%v %v", + " -procs=%v -repeat=%v -threaded=%v -collide=%v%v%v %v", execprog, executor, arch, osArg, sandbox, opts.Procs, repeatCount, opts.Threaded, opts.Collide, - optionalArg, progFile) + coverArg, optionalArg, progFile) } var MakeBin = func() string { |
