| // Copyright 2019 syzkaller project authors. All rights reserved. |
| // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. |
| |
| package bisect |
| |
| import ( |
| "bytes" |
| "fmt" |
| "io/ioutil" |
| "os" |
| "strconv" |
| "testing" |
| |
| "github.com/google/syzkaller/pkg/instance" |
| "github.com/google/syzkaller/pkg/mgrconfig" |
| "github.com/google/syzkaller/pkg/report" |
| "github.com/google/syzkaller/pkg/vcs" |
| ) |
| |
| // testEnv will implement instance.BuilderTester. This allows us to |
| // set bisect.env.inst to a testEnv object. |
| type testEnv struct { |
| repo *vcs.TestRepo |
| r vcs.Repo |
| t *testing.T |
| // TODO: add a "fix bool" here so that Test() can return results according to |
| // whether fix/cause bisection is happening. |
| } |
| |
| func (env *testEnv) BuildSyzkaller(repo, commit string) error { |
| return nil |
| } |
| |
| func (env *testEnv) BuildKernel(compilerBin, userspaceDir, cmdlineFile, sysctlFile string, |
| kernelConfig []byte) (string, error) { |
| return "", nil |
| } |
| |
| func (env *testEnv) Test(numVMs int, reproSyz, reproOpts, reproC []byte) ([]error, error) { |
| hc, err := env.r.HeadCommit() |
| if err != nil { |
| env.t.Fatal(err) |
| } |
| // For cause bisection, if newer than or equal to 602, it crashes. |
| // -- 602 is the cause commit. |
| // TODO: for fix bisection(check env.fix), if older than 602, it crashes. |
| // -- 602 is the fix commit. |
| val, err := strconv.Atoi(hc.Title) |
| if err != nil { |
| env.t.Fatalf("invalid commit title: %v", val) |
| } |
| if val >= 602 { |
| var errors []error |
| for i := 0; i < numVMs; i++ { |
| errors = append(errors, &instance.CrashError{ |
| Report: &report.Report{ |
| Title: fmt.Sprintf("crashes at %v", hc.Title), |
| }, |
| }) |
| } |
| return errors, nil |
| } |
| var errors []error |
| for i := 0; i < numVMs; i++ { |
| errors = append(errors, nil) |
| } |
| return errors, nil |
| } |
| |
| // TestBisectCause tests that bisection returns the correct cause |
| // commit. |
| func TestBisectCause(t *testing.T) { |
| t.Parallel() |
| baseDir, err := ioutil.TempDir("", "syz-git-test") |
| if err != nil { |
| t.Fatal(err) |
| } |
| defer os.RemoveAll(baseDir) |
| originRepo := vcs.CreateTestRepo(t, baseDir, "originRepo") |
| for rv := 4; rv < 10; rv++ { |
| for i := 0; i < 6; i++ { |
| originRepo.CommitChange(fmt.Sprintf("%v", rv*100+i)) |
| if i == 0 { |
| originRepo.SetTag(fmt.Sprintf("v%v.0", rv)) |
| } |
| } |
| } |
| if !originRepo.SupportsBisection() { |
| t.Skip("bisection is unsupported by git (probably too old version)") |
| } |
| repo := vcs.CloneTestRepo(t, baseDir, "repo", originRepo) |
| r, err := vcs.NewRepo("test", "64", repo.Dir) |
| if err != nil { |
| t.Fatal(err) |
| } |
| head, err := r.HeadCommit() |
| if err != nil { |
| t.Fatal(err) |
| } |
| cfg := &Config{ |
| Fix: false, |
| Trace: new(bytes.Buffer), |
| Manager: mgrconfig.Config{ |
| TargetOS: "test", |
| TargetVMArch: "64", |
| Type: "qemu", |
| KernelSrc: repo.Dir, |
| }, |
| Kernel: KernelConfig{ |
| Commit: head.Hash, |
| Repo: originRepo.Dir, |
| }, |
| } |
| inst := &testEnv{ |
| repo: repo, |
| r: r, |
| t: t, |
| } |
| commits, rep, err := runImpl(cfg, r, r.(vcs.Bisecter), inst) |
| if err != nil { |
| t.Fatalf("returned error: '%v'", err) |
| } |
| if len(commits) != 1 { |
| t.Fatalf("Got %d commits: %v", len(commits), commits) |
| } |
| if commits[0].Title != "602" { |
| t.Fatalf("Expected commit '602' got '%v'", commits[0].Title) |
| } |
| if rep == nil { |
| t.Fatal("returned rep==nil, report should not be empty") |
| } |
| } |