From 0bd8b1dd5124f72465a85feea4044d98b2571d6d Mon Sep 17 00:00:00 2001 From: Taras Madan Date: Thu, 14 Oct 2021 12:49:19 +0000 Subject: syz-verifier: remove verifier, io and os/signal from the stats dependencies --- syz-verifier/main.go | 36 ++++++++++++++- syz-verifier/stats.go | 110 ++++++++++++++++++++------------------------- syz-verifier/stats_test.go | 18 ++++---- 3 files changed, 91 insertions(+), 73 deletions(-) (limited to 'syz-verifier') diff --git a/syz-verifier/main.go b/syz-verifier/main.go index 7065f5d7c..b7b11b5c6 100755 --- a/syz-verifier/main.go +++ b/syz-verifier/main.go @@ -2,16 +2,18 @@ // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. // package main starts the syz-verifier tool. High-level documentation can be -// found in docs/syz_verfier.md. +// found in docs/syz_verifier.md. package main import ( + "errors" "flag" "fmt" "io" "math/rand" "net" "os" + "os/signal" "path/filepath" "strconv" "strings" @@ -239,6 +241,31 @@ func main() { vrf.startInstances() } +// SetPrintStatAtSIGINT asks Stats object to report verification +// statistics when an os.Interrupt occurs and Exit(). +func (vrf *Verifier) SetPrintStatAtSIGINT() error { + if vrf.stats == nil { + return errors.New("verifier.stats is nil") + } + + osSignalChannel := make(chan os.Signal) + signal.Notify(osSignalChannel, os.Interrupt) + + go func() { + <-osSignalChannel + defer os.Exit(0) + + totalExecutionTime := time.Since(vrf.stats.StartTime).Minutes() + if vrf.stats.TotalMismatches < 0 { + fmt.Fprint(vrf.statsWrite, "No mismatches occurred until syz-verifier was stopped.") + }else{ + fmt.Fprintf(vrf.statsWrite, vrf.stats.GetTextDescription(totalExecutionTime)) + } + }() + + return nil +} + func (vrf *Verifier) startInstances() { for idx, pi := range vrf.pools { go func(pi *poolInfo, idx int) { @@ -282,6 +309,8 @@ func (vrf *Verifier) createAndManageInstance(pi *poolInfo, idx int) { } inst.MonitorExecution(outc, errc, pi.Reporter, vm.ExitTimeout) + + log.Logf(0, "reboot the VM in pool %d", idx) } func startRPCServer(vrf *Verifier) (*RPCServer, error) { @@ -340,7 +369,10 @@ func (srv *RPCServer) UpdateUnsupported(a *rpctype.UpdateUnsupportedArgs, r *int srv.notChecked-- if srv.notChecked == 0 { vrf.finalizeCallSet(os.Stdout) - vrf.stats = InitStats(vrf.calls, vrf.statsWrite) + + vrf.stats = InitStats(vrf.calls) + vrf.SetPrintStatAtSIGINT() + vrf.choiceTable = vrf.target.BuildChoiceTable(nil, vrf.calls) srv.cond.Signal() } diff --git a/syz-verifier/stats.go b/syz-verifier/stats.go index 804b6ec75..a6d00a0d2 100644 --- a/syz-verifier/stats.go +++ b/syz-verifier/stats.go @@ -5,10 +5,8 @@ package main import ( "fmt" - "io" - "os" - "os/signal" "sort" + "strings" "time" "github.com/google/syzkaller/prog" @@ -31,7 +29,7 @@ type Stats struct { type CallStats struct { // Name is the system call name. Name string - // Mismatches stores the number of errno mismatches identifed in the + // Mismatches stores the number of errno mismatches identified in the // verified programs for this system call. Mismatches int // Occurrences is the number of times the system call appeared in a @@ -41,85 +39,71 @@ type CallStats struct { States map[ReturnState]bool } -// InitStats creates a stats object that will report verification -// statistics when an os.Interrupt occurs. -func InitStats(calls map[*prog.Syscall]bool, w io.Writer) *Stats { - s := &Stats{ +// InitStats creates a stats object. +func InitStats(calls map[*prog.Syscall]bool) *Stats { + stats := &Stats{ Calls: make(map[string]*CallStats), StartTime: time.Now(), } - for c := range calls { - s.Calls[c.Name] = &CallStats{ - Name: c.Name, + + for syscall := range calls { + stats.Calls[syscall.Name] = &CallStats{ + Name: syscall.Name, States: make(map[ReturnState]bool)} } - c := make(chan os.Signal) - signal.Notify(c, os.Interrupt) - go func() { - <-c - dt := time.Since(s.StartTime).Minutes() - if s.TotalMismatches < 0 { - fmt.Fprint(w, "No mismatches occurred until syz-verifier was stopped.") - os.Exit(0) - } - s.ReportGlobalStats(w, dt) - os.Exit(0) - }() + return stats +} + +// ReportGlobalStats creates a report with statistics about all the +// supported system calls for which errno mismatches were identified in +// the verified programs, shown in decreasing order. +func (stats *Stats) GetTextDescription(deltaTime float64) string { + var result strings.Builder + + tc := stats.totalCallsExecuted() + fmt.Fprintf(&result, "total number of mismatches / total number of calls "+ + "executed: %d / %d (%0.2f %%)\n\n", stats.TotalMismatches, tc, getPercentage(stats.TotalMismatches, tc)) + fmt.Fprintf(&result, "programs / minute: %0.2f\n\n", float64(stats.TotalProgs)/deltaTime) + fmt.Fprintf(&result, "true mismatching programs: %d / total number of programs: %d (%0.2f %%)\n", + stats.MismatchingProgs, stats.TotalProgs, getPercentage(stats.MismatchingProgs, stats.TotalProgs)) + fmt.Fprintf(&result, "flaky programs: %d / total number of programs: %d (%0.2f %%)\n\n", + stats.FlakyProgs, stats.TotalProgs, getPercentage(stats.FlakyProgs, stats.TotalProgs)) + cs := stats.getOrderedStats() + for _, c := range cs { + fmt.Fprintf(&result, "%s\n", stats.getCallStatsTextDescription(c.Name)) + } - return s + return result.String() } -// ReportCallStats creates a report with the current statistics for call. -func (s *Stats) ReportCallStats(call string) string { - cs, ok := s.Calls[call] +// getCallStatsTextDescription creates a report with the current statistics for call. +func (stats *Stats) getCallStatsTextDescription(call string) string { + syscallStat, ok := stats.Calls[call] if !ok { return "" } - name, m, o := cs.Name, cs.Mismatches, cs.Occurrences - data := fmt.Sprintf("statistics for %s:\n"+ + syscallName, mismatches, occurrences := syscallStat.Name, syscallStat.Mismatches, syscallStat.Occurrences + return fmt.Sprintf("statistics for %s:\n"+ "\t↳ mismatches of %s / occurrences of %s: %d / %d (%0.2f %%)\n"+ "\t↳ mismatches of %s / total number of mismatches: "+ "%d / %d (%0.2f %%)\n"+ - "\t↳ %d distinct states identified: %v\n", name, name, name, m, o, - getPercentage(m, o), name, m, s.TotalMismatches, - getPercentage(m, s.TotalMismatches), len(cs.States), s.getOrderedStates(name)) - return data -} - -func getPercentage(value, total int) float64 { - return float64(value) / float64(total) * 100 -} - -// ReportGlobalStats creates a report with statistics about all the -// supported system calls for which errno mismatches were identified in -// the verified programs, shown in decreasing order. -func (s *Stats) ReportGlobalStats(w io.Writer, deltaTime float64) { - tc := s.totalCallsExecuted() - fmt.Fprintf(w, "total number of mismatches / total number of calls "+ - "executed: %d / %d (%0.2f %%)\n\n", s.TotalMismatches, tc, getPercentage(s.TotalMismatches, tc)) - fmt.Fprintf(w, "programs / minute: %0.2f\n\n", float64(s.TotalProgs)/deltaTime) - fmt.Fprintf(w, "true mismatching programs: %d / total number of programs: %d (%0.2f %%)\n", - s.MismatchingProgs, s.TotalProgs, getPercentage(s.MismatchingProgs, s.TotalProgs)) - fmt.Fprintf(w, "flaky programs: %d / total number of programs: %d (%0.2f %%)\n\n", - s.FlakyProgs, s.TotalProgs, getPercentage(s.FlakyProgs, s.TotalProgs)) - cs := s.getOrderedStats() - for _, c := range cs { - fmt.Fprintf(w, "%s\n", s.ReportCallStats(c.Name)) - } + "\t↳ %d distinct states identified: %v\n", syscallName, syscallName, syscallName, mismatches, occurrences, + getPercentage(mismatches, occurrences), syscallName, mismatches, stats.TotalMismatches, + getPercentage(mismatches, stats.TotalMismatches), len(syscallStat.States), stats.getOrderedStates(syscallName)) } -func (s *Stats) totalCallsExecuted() int { +func (stats *Stats) totalCallsExecuted() int { t := 0 - for _, cs := range s.Calls { + for _, cs := range stats.Calls { t += cs.Occurrences } return t } -func (s *Stats) getOrderedStats() []*CallStats { +func (stats *Stats) getOrderedStats() []*CallStats { css := make([]*CallStats, 0) - for _, cs := range s.Calls { + for _, cs := range stats.Calls { if cs.Mismatches > 0 { css = append(css, cs) } @@ -132,8 +116,8 @@ func (s *Stats) getOrderedStats() []*CallStats { return css } -func (s *Stats) getOrderedStates(call string) []string { - states := s.Calls[call].States +func (stats *Stats) getOrderedStates(call string) []string { + states := stats.Calls[call].States ss := make([]string, 0, len(states)) for s := range states { ss = append(ss, fmt.Sprintf("%q", s)) @@ -141,3 +125,7 @@ func (s *Stats) getOrderedStates(call string) []string { sort.Strings(ss) return ss } + +func getPercentage(value, total int) float64 { + return float64(value) / float64(total) * 100 +} diff --git a/syz-verifier/stats_test.go b/syz-verifier/stats_test.go index 38f4f4661..e553e3827 100644 --- a/syz-verifier/stats_test.go +++ b/syz-verifier/stats_test.go @@ -3,7 +3,6 @@ package main import ( - "bytes" "testing" "github.com/google/go-cmp/cmp" @@ -32,7 +31,7 @@ func dummyStats() *Stats { } } -func TestReportCallStats(t *testing.T) { +func TestGetCallStatsTextDescription(t *testing.T) { tests := []struct { name, call, report string }{ @@ -55,19 +54,18 @@ func TestReportCallStats(t *testing.T) { for _, test := range tests { s := dummyStats() t.Run(test.name, func(t *testing.T) { - got, want := s.ReportCallStats(test.call), test.report + got, want := s.getCallStatsTextDescription(test.call), test.report if diff := cmp.Diff(want, got); diff != "" { - t.Errorf("s.ReportCallStats mismatch (-want +got):\n%s", diff) + t.Errorf("s.getCallStatsTextDescription mismatch (-want +got):\n%s", diff) } }) } } -func TestReportGlobalStats(t *testing.T) { - s := dummyStats() - out := bytes.Buffer{} - s.ReportGlobalStats(&out, float64(10)) - got, want := out.String(), +func TestGetTextDescription(t *testing.T) { + stats := dummyStats() + + got, want := stats.GetTextDescription(float64(10)), "total number of mismatches / total number of calls "+ "executed: 10 / 20 (50.00 %)\n\n"+ "programs / minute: 2.40\n\n"+ @@ -93,6 +91,6 @@ func TestReportGlobalStats(t *testing.T) { "[\"Flags: 7, Errno: 1 (operation not permitted)\" \"Flags: 7, Errno: 3 (no such process)\"]\n\n" if diff := cmp.Diff(want, got); diff != "" { - t.Errorf("s.ReportGlobalStats mismatch (-want +got):\n%s", diff) + t.Errorf("s.GetTextDescription mismatch (-want +got):\n%s", diff) } } -- cgit mrf-deployment