diff options
| author | Aleksandr Nogikh <nogikh@google.com> | 2021-08-02 17:08:58 +0000 |
|---|---|---|
| committer | Aleksandr Nogikh <wp32pw@gmail.com> | 2021-08-06 15:34:58 +0200 |
| commit | de040344f89656862b5bbd306b8a9c143dae3dea (patch) | |
| tree | 41bf6feec26d42e6ec18ce7d55e6a2b1f0bbc1d9 | |
| parent | 00fc459663540df701f62355dc1871a583021aa7 (diff) | |
pkg/report: separate reporter wrapper from OS-specific implementations
Currently a number of report post-processing activities are implemented as a
decorator over the interface that defines OS-specific implementations.
Following exactly the same interface is too restrictive in this case as adding
extra parameters to the post-processing forces the developer to adjust all
implementations thay may not need these parameters at all.
Untie the wrapper from the Reporter interface. Use a package-private
reporterImpl interface for the OS-specific implementations, while having an
exported Reporter structure. Make sure that Reporter is stored and
passed as a pointer.
| -rw-r--r-- | pkg/instance/instance.go | 2 | ||||
| -rw-r--r-- | pkg/report/akaros.go | 2 | ||||
| -rw-r--r-- | pkg/report/bsd.go | 2 | ||||
| -rw-r--r-- | pkg/report/darwin.go | 2 | ||||
| -rw-r--r-- | pkg/report/freebsd.go | 2 | ||||
| -rw-r--r-- | pkg/report/fuchsia.go | 2 | ||||
| -rw-r--r-- | pkg/report/fuzz.go | 8 | ||||
| -rw-r--r-- | pkg/report/gvisor.go | 2 | ||||
| -rw-r--r-- | pkg/report/linux.go | 2 | ||||
| -rw-r--r-- | pkg/report/netbsd.go | 2 | ||||
| -rw-r--r-- | pkg/report/openbsd.go | 2 | ||||
| -rw-r--r-- | pkg/report/report.go | 46 | ||||
| -rw-r--r-- | pkg/report/report_test.go | 10 | ||||
| -rw-r--r-- | pkg/report/stub.go | 2 | ||||
| -rw-r--r-- | pkg/repro/repro.go | 4 | ||||
| -rw-r--r-- | syz-manager/manager.go | 2 | ||||
| -rwxr-xr-x | syz-verifier/main.go | 2 | ||||
| -rw-r--r-- | tools/syz-crush/crush.go | 2 | ||||
| -rw-r--r-- | tools/syz-runtest/runtest.go | 2 | ||||
| -rw-r--r-- | vm/vm.go | 4 |
20 files changed, 58 insertions, 44 deletions
diff --git a/pkg/instance/instance.go b/pkg/instance/instance.go index 70846711f..794d4484f 100644 --- a/pkg/instance/instance.go +++ b/pkg/instance/instance.go @@ -243,7 +243,7 @@ func (env *env) Test(numVMs int, reproSyz, reproOpts, reproC []byte) ([]error, e type inst struct { cfg *mgrconfig.Config optionalFlags bool - reporter report.Reporter + reporter *report.Reporter vmPool *vm.Pool vm *vm.Instance vmIndex int diff --git a/pkg/report/akaros.go b/pkg/report/akaros.go index ad0d3c3dd..e3f6c2a25 100644 --- a/pkg/report/akaros.go +++ b/pkg/report/akaros.go @@ -20,7 +20,7 @@ type akaros struct { objfile string } -func ctorAkaros(cfg *config) (Reporter, []string, error) { +func ctorAkaros(cfg *config) (reporterImpl, []string, error) { ctx := &akaros{ config: cfg, } diff --git a/pkg/report/bsd.go b/pkg/report/bsd.go index 327ddc8c6..b627ed4f4 100644 --- a/pkg/report/bsd.go +++ b/pkg/report/bsd.go @@ -23,7 +23,7 @@ type bsd struct { symbols map[string][]symbolizer.Symbol } -func ctorBSD(cfg *config, oopses []*oops, symbolizeRes []*regexp.Regexp) (Reporter, error) { +func ctorBSD(cfg *config, oopses []*oops, symbolizeRes []*regexp.Regexp) (reporterImpl, error) { var symbols map[string][]symbolizer.Symbol kernelObject := "" if cfg.kernelObj != "" { diff --git a/pkg/report/darwin.go b/pkg/report/darwin.go index aea8ab455..1b93d5c5d 100644 --- a/pkg/report/darwin.go +++ b/pkg/report/darwin.go @@ -7,7 +7,7 @@ import ( "regexp" ) -func ctorDarwin(cfg *config) (Reporter, []string, error) { +func ctorDarwin(cfg *config) (reporterImpl, []string, error) { symbolizeRes := []*regexp.Regexp{} ctx, err := ctorBSD(cfg, darwinOopses, symbolizeRes) return ctx, nil, err diff --git a/pkg/report/freebsd.go b/pkg/report/freebsd.go index a379060af..fb4755d60 100644 --- a/pkg/report/freebsd.go +++ b/pkg/report/freebsd.go @@ -12,7 +12,7 @@ type freebsd struct { *config } -func ctorFreebsd(cfg *config) (Reporter, []string, error) { +func ctorFreebsd(cfg *config) (reporterImpl, []string, error) { ctx := &freebsd{ config: cfg, } diff --git a/pkg/report/fuchsia.go b/pkg/report/fuchsia.go index e83d6fadf..39c175ccd 100644 --- a/pkg/report/fuchsia.go +++ b/pkg/report/fuchsia.go @@ -38,7 +38,7 @@ var ( } ) -func ctorFuchsia(cfg *config) (Reporter, []string, error) { +func ctorFuchsia(cfg *config) (reporterImpl, []string, error) { ctx := &fuchsia{ config: cfg, } diff --git a/pkg/report/fuzz.go b/pkg/report/fuzz.go index 8952baf76..2e747929a 100644 --- a/pkg/report/fuzz.go +++ b/pkg/report/fuzz.go @@ -13,7 +13,7 @@ import ( func Fuzz(data []byte) int { res := 0 for os, reporter := range fuzzReporters { - typ := reporter.(*reporterWrapper).typ + typ := reporter.typ containsCrash := reporter.ContainsCrash(data) rep := reporter.Parse(data) if containsCrash != (rep != nil) { @@ -64,8 +64,8 @@ func Fuzz(data []byte) int { return res } -var fuzzReporters = func() map[string]Reporter { - reporters := make(map[string]Reporter) +var fuzzReporters = func() map[string]*Reporter { + reporters := make(map[string]*Reporter) for os := range ctors { if os == targets.Windows { continue @@ -80,7 +80,7 @@ var fuzzReporters = func() map[string]Reporter { if err != nil { panic(err) } - if _, ok := reporter.(*stub); ok { + if _, ok := reporter.impl.(*stub); ok { continue } reporters[os] = reporter diff --git a/pkg/report/gvisor.go b/pkg/report/gvisor.go index ebe790e78..15961afad 100644 --- a/pkg/report/gvisor.go +++ b/pkg/report/gvisor.go @@ -12,7 +12,7 @@ type gvisor struct { *config } -func ctorGvisor(cfg *config) (Reporter, []string, error) { +func ctorGvisor(cfg *config) (reporterImpl, []string, error) { ctx := &gvisor{ config: cfg, } diff --git a/pkg/report/linux.go b/pkg/report/linux.go index 16ca3c56d..6955a6057 100644 --- a/pkg/report/linux.go +++ b/pkg/report/linux.go @@ -33,7 +33,7 @@ type linux struct { eoi []byte } -func ctorLinux(cfg *config) (Reporter, []string, error) { +func ctorLinux(cfg *config) (reporterImpl, []string, error) { var symbols map[string][]symbolizer.Symbol vmlinux := "" if cfg.kernelObj != "" { diff --git a/pkg/report/netbsd.go b/pkg/report/netbsd.go index fea878622..d954b5e83 100644 --- a/pkg/report/netbsd.go +++ b/pkg/report/netbsd.go @@ -7,7 +7,7 @@ import ( "regexp" ) -func ctorNetbsd(cfg *config) (Reporter, []string, error) { +func ctorNetbsd(cfg *config) (reporterImpl, []string, error) { symbolizeRes := []*regexp.Regexp{ // stack regexp.MustCompile(` at netbsd:([A-Za-z0-9_]+)\+0x([0-9a-f]+)`), diff --git a/pkg/report/openbsd.go b/pkg/report/openbsd.go index d24481776..8b38a2dbc 100644 --- a/pkg/report/openbsd.go +++ b/pkg/report/openbsd.go @@ -7,7 +7,7 @@ import ( "regexp" ) -func ctorOpenbsd(cfg *config) (Reporter, []string, error) { +func ctorOpenbsd(cfg *config) (reporterImpl, []string, error) { symbolizeRes := []*regexp.Regexp{ // stack regexp.MustCompile(` at ([A-Za-z0-9_]+)\+0x([0-9a-f]+)`), diff --git a/pkg/report/report.go b/pkg/report/report.go index 502a5d552..7ee98c516 100644 --- a/pkg/report/report.go +++ b/pkg/report/report.go @@ -12,12 +12,13 @@ import ( "regexp" "strings" + "github.com/google/go-cmp/cmp" "github.com/google/syzkaller/pkg/mgrconfig" "github.com/google/syzkaller/pkg/vcs" "github.com/google/syzkaller/sys/targets" ) -type Reporter interface { +type reporterImpl interface { // ContainsCrash searches kernel console output for oops messages. ContainsCrash(output []byte) bool @@ -29,6 +30,12 @@ type Reporter interface { Symbolize(rep *Report) error } +type Reporter struct { + impl reporterImpl + suppressions []*regexp.Regexp + typ string +} + type Report struct { // Title contains a representative description of the first oops. Title string @@ -90,7 +97,7 @@ func (t Type) String() string { } // NewReporter creates reporter for the specified OS/Type. -func NewReporter(cfg *mgrconfig.Config) (Reporter, error) { +func NewReporter(cfg *mgrconfig.Config) (*Reporter, error) { typ := cfg.TargetOS if cfg.Type == "gvisor" { typ = cfg.Type @@ -118,7 +125,7 @@ func NewReporter(cfg *mgrconfig.Config) (Reporter, error) { if err != nil { return nil, err } - return &reporterWrapper{rep, supps, typ}, nil + return &Reporter{rep, supps, typ}, nil } const ( @@ -148,7 +155,7 @@ type config struct { ignores []*regexp.Regexp } -type fn func(cfg *config) (Reporter, []string, error) +type fn func(cfg *config) (reporterImpl, []string, error) func compileRegexps(list []string) ([]*regexp.Regexp, error) { compiled := make([]*regexp.Regexp, len(list)) @@ -162,14 +169,8 @@ func compileRegexps(list []string) ([]*regexp.Regexp, error) { return compiled, nil } -type reporterWrapper struct { - Reporter - suppressions []*regexp.Regexp - typ string -} - -func (wrap *reporterWrapper) Parse(output []byte) *Report { - rep := wrap.Reporter.Parse(output) +func (reporter *Reporter) Parse(output []byte) *Report { + rep := reporter.impl.Parse(output) if rep == nil { return nil } @@ -177,7 +178,7 @@ func (wrap *reporterWrapper) Parse(output []byte) *Report { for i, title := range rep.AltTitles { rep.AltTitles[i] = sanitizeTitle(replaceTable(dynamicTitleReplacement, title)) } - rep.Suppressed = matchesAny(rep.Output, wrap.suppressions) + rep.Suppressed = matchesAny(rep.Output, reporter.suppressions) if bytes.Contains(rep.Output, gceConsoleHangup) { rep.Corrupted = true } @@ -197,6 +198,19 @@ func (wrap *reporterWrapper) Parse(output []byte) *Report { return rep } +func (reporter *Reporter) ContainsCrash(output []byte) bool { + return reporter.impl.ContainsCrash(output) +} + +func (reporter *Reporter) Symbolize(rep *Report) error { + return reporter.impl.Symbolize(rep) +} + +// We need this method to enable comparisons though go-cmp. +func (reporter Reporter) Equal(other Reporter) bool { + return cmp.Equal(reporter, other, cmp.AllowUnexported(Reporter{})) +} + func extractReportType(rep *Report) Type { // Type/frame extraction logic should be integrated with oops types. // But for now we do this more ad-hoc analysis here to at least isolate @@ -219,13 +233,13 @@ func extractReportType(rep *Report) Type { return Unknown } -func IsSuppressed(reporter Reporter, output []byte) bool { - return matchesAny(output, reporter.(*reporterWrapper).suppressions) || +func IsSuppressed(reporter *Reporter, output []byte) bool { + return matchesAny(output, reporter.suppressions) || bytes.Contains(output, gceConsoleHangup) } // ParseAll returns all successive reports in output. -func ParseAll(reporter Reporter, output []byte) (reports []*Report) { +func ParseAll(reporter *Reporter, output []byte) (reports []*Report) { for { rep := reporter.Parse(output) if rep == nil { diff --git a/pkg/report/report_test.go b/pkg/report/report_test.go index 355edc764..236186b1b 100644 --- a/pkg/report/report_test.go +++ b/pkg/report/report_test.go @@ -42,7 +42,7 @@ type ParseTest struct { Report []byte } -func testParseFile(t *testing.T, reporter Reporter, fn string) { +func testParseFile(t *testing.T, reporter *Reporter, fn string) { data, err := ioutil.ReadFile(fn) if err != nil { t.Fatal(err) @@ -151,7 +151,7 @@ func parseHeaderLine(t *testing.T, test *ParseTest, ln string) { } } -func testParseImpl(t *testing.T, reporter Reporter, test *ParseTest) { +func testParseImpl(t *testing.T, reporter *Reporter, test *ParseTest) { rep := reporter.Parse(test.Log) containsCrash := reporter.ContainsCrash(test.Log) expectCrash := (test.Title != "") @@ -203,7 +203,7 @@ func testParseImpl(t *testing.T, reporter Reporter, test *ParseTest) { checkReport(t, reporter, rep, test) } -func checkReport(t *testing.T, reporter Reporter, rep *Report, test *ParseTest) { +func checkReport(t *testing.T, reporter *Reporter, rep *Report, test *ParseTest) { if test.HasReport && !bytes.Equal(rep.Report, test.Report) { t.Fatalf("extracted wrong report:\n%s\nwant:\n%s", rep.Report, test.Report) } @@ -277,7 +277,7 @@ func TestGuiltyFile(t *testing.T) { forEachFile(t, "guilty", testGuiltyFile) } -func testGuiltyFile(t *testing.T, reporter Reporter, fn string) { +func testGuiltyFile(t *testing.T, reporter *Reporter, fn string) { data, err := ioutil.ReadFile(fn) if err != nil { t.Fatal(err) @@ -322,7 +322,7 @@ func testGuiltyFile(t *testing.T, reporter Reporter, fn string) { } } -func forEachFile(t *testing.T, dir string, fn func(t *testing.T, reporter Reporter, fn string)) { +func forEachFile(t *testing.T, dir string, fn func(t *testing.T, reporter *Reporter, fn string)) { for os := range ctors { if os == targets.Windows { continue // not implemented diff --git a/pkg/report/stub.go b/pkg/report/stub.go index edd469606..d1946a338 100644 --- a/pkg/report/stub.go +++ b/pkg/report/stub.go @@ -7,7 +7,7 @@ type stub struct { *config } -func ctorStub(cfg *config) (Reporter, []string, error) { +func ctorStub(cfg *config) (reporterImpl, []string, error) { ctx := &stub{ config: cfg, } diff --git a/pkg/repro/repro.go b/pkg/repro/repro.go index 4433c84a9..52f456a83 100644 --- a/pkg/repro/repro.go +++ b/pkg/repro/repro.go @@ -44,7 +44,7 @@ type Stats struct { type context struct { target *targets.Target - reporter report.Reporter + reporter *report.Reporter crashTitle string crashType report.Type instances chan *instance @@ -63,7 +63,7 @@ type instance struct { executorBin string } -func Run(crashLog []byte, cfg *mgrconfig.Config, features *host.Features, reporter report.Reporter, +func Run(crashLog []byte, cfg *mgrconfig.Config, features *host.Features, reporter *report.Reporter, vmPool *vm.Pool, vmIndexes []int) (*Result, *Stats, error) { if len(vmIndexes) == 0 { return nil, nil, fmt.Errorf("no VMs provided") diff --git a/syz-manager/manager.go b/syz-manager/manager.go index add89116e..6bab4bb43 100644 --- a/syz-manager/manager.go +++ b/syz-manager/manager.go @@ -49,7 +49,7 @@ type Manager struct { vmPool *vm.Pool target *prog.Target sysTarget *targets.Target - reporter report.Reporter + reporter *report.Reporter crashdir string serv *RPCServer corpusDB *db.DB diff --git a/syz-verifier/main.go b/syz-verifier/main.go index eea9d92ed..0a047231d 100755 --- a/syz-verifier/main.go +++ b/syz-verifier/main.go @@ -83,7 +83,7 @@ type RPCServer struct { type poolInfo struct { cfg *mgrconfig.Config pool *vm.Pool - Reporter report.Reporter + Reporter *report.Reporter // runners keeps track of what programs have been sent to each Runner. // There is one Runner executing per VM instance. runners map[int]runnerProgs diff --git a/tools/syz-crush/crush.go b/tools/syz-crush/crush.go index 5b2dcfffd..b795becc8 100644 --- a/tools/syz-crush/crush.go +++ b/tools/syz-crush/crush.go @@ -166,7 +166,7 @@ func storeCrash(cfg *mgrconfig.Config, rep *report.Report) { } } -func runInstance(cfg *mgrconfig.Config, reporter report.Reporter, +func runInstance(cfg *mgrconfig.Config, reporter *report.Reporter, vmPool *vm.Pool, index int, timeout time.Duration, runType FileType) *report.Report { log.Printf("vm-%v: starting", index) inst, err := vmPool.Create(index) diff --git a/tools/syz-runtest/runtest.go b/tools/syz-runtest/runtest.go index 8ef15af38..98b433b04 100644 --- a/tools/syz-runtest/runtest.go +++ b/tools/syz-runtest/runtest.go @@ -132,7 +132,7 @@ func main() { type Manager struct { cfg *mgrconfig.Config vmPool *vm.Pool - reporter report.Reporter + reporter *report.Reporter requests chan *runtest.RunRequest checkResult *rpctype.CheckArgs checkResultReady chan bool @@ -179,7 +179,7 @@ const ( // Exit says which exit modes should be considered as errors/OK. // Returns a non-symbolized crash report, or nil if no error happens. func (inst *Instance) MonitorExecution(outc <-chan []byte, errc <-chan error, - reporter report.Reporter, exit ExitCondition) (rep *report.Report) { + reporter *report.Reporter, exit ExitCondition) (rep *report.Report) { mon := &monitor{ inst: inst, outc: outc, @@ -266,7 +266,7 @@ type monitor struct { inst *Instance outc <-chan []byte errc <-chan error - reporter report.Reporter + reporter *report.Reporter exit ExitCondition output []byte matchPos int |
