func triageInput(env *ipc.Env, inp Input) { if *flagNoCover { panic("should not be called when coverage is disabled") } call := inp.p.Calls[inp.call].Meta newCover := cover.Difference(inp.cover, corpusCover[call.CallID]) newCover = cover.Difference(newCover, flakes) if len(newCover) == 0 { return } if _, ok := corpusHashes[hash(inp.p.Serialize())]; ok { return } minCover := inp.cover for i := 0; i < 3; i++ { allCover := execute1(env, inp.p, &statExecTriage) if len(allCover[inp.call]) == 0 { // The call was not executed. Happens sometimes, reason unknown. continue } cov := allCover[inp.call] diff := cover.SymmetricDifference(inp.cover, cov) if len(diff) != 0 { flakes = cover.Union(flakes, diff) } minCover = cover.Intersection(minCover, cov) } stableNewCover := cover.Intersection(newCover, minCover) if len(stableNewCover) == 0 { return } inp.p, inp.call = prog.Minimize(inp.p, inp.call, func(p1 *prog.Prog, call1 int) bool { allCover := execute1(env, p1, &statExecMinimize) if len(allCover[call1]) == 0 { return false // The call was not executed. } cov := allCover[call1] if len(cover.Intersection(stableNewCover, cov)) != len(stableNewCover) { return false } minCover = cover.Intersection(minCover, cov) return true }) inp.cover = minCover corpusCover[call.CallID] = cover.Union(corpusCover[call.CallID], minCover) corpus = append(corpus, inp) data := inp.p.Serialize() corpusHashes[hash(data)] = struct{}{} logf(2, "added new input for %v to corpus:\n%s", call.CallName, data) statNewInput++ a := &NewManagerInputArgs{*flagName, RpcInput{call.CallName, inp.p.Serialize(), inp.call, []uint32(inp.cover)}} if err := manager.Call("Manager.NewInput", a, nil); err != nil { panic(err) } }
func (mgr *Manager) httpCover(w http.ResponseWriter, r *http.Request) { mgr.mu.Lock() defer mgr.mu.Unlock() var cov cover.Cover call := r.FormValue("call") unique := r.FormValue("unique") != "" && call != "" perCall := false if n, err := strconv.Atoi(call); err == nil && n < len(mgr.corpus) { cov = mgr.corpus[n].Cover } else { perCall = true for _, inp := range mgr.corpus { if call == "" || call == inp.Call { cov = cover.Union(cov, cover.Cover(inp.Cover)) } } } if unique { cov = cover.Intersection(cov, mgr.uniqueCover(perCall)) } if err := generateCoverHtml(w, mgr.cfg.Vmlinux, cov); err != nil { http.Error(w, fmt.Sprintf("failed to generate coverage profile: %v", err), http.StatusInternalServerError) return } runtime.GC() }
func (mgr *Manager) httpCorpus(w http.ResponseWriter, r *http.Request) { mgr.mu.Lock() defer mgr.mu.Unlock() var data []UIInput call := r.FormValue("call") totalUnique := mgr.uniqueCover(false) for i, inp := range mgr.corpus { if call != inp.Call { continue } p, err := prog.Deserialize(inp.Prog) if err != nil { http.Error(w, fmt.Sprintf("failed to deserialize program: %v", err), http.StatusInternalServerError) return } unique := cover.Intersection(inp.Cover, totalUnique) data = append(data, UIInput{ Short: p.String(), Full: string(inp.Prog), Cover: len(inp.Cover), UniqueCover: len(unique), N: i, }) } sort.Sort(UIInputArray(data)) if err := corpusTemplate.Execute(w, data); err != nil { http.Error(w, fmt.Sprintf("failed to execute template: %v", err), http.StatusInternalServerError) return } }
func triageInput(pid int, env *ipc.Env, inp Input) { if noCover { panic("should not be called when coverage is disabled") } call := inp.p.Calls[inp.call].Meta coverMu.RLock() newCover := cover.Difference(inp.cover, corpusCover[call.CallID]) newCover = cover.Difference(newCover, flakes) coverMu.RUnlock() if len(newCover) == 0 { return } corpusMu.RLock() if _, ok := corpusHashes[hash(inp.p.Serialize())]; ok { corpusMu.RUnlock() return } corpusMu.RUnlock() minCover := inp.cover for i := 0; i < 3; i++ { allCover := execute1(pid, env, inp.p, &statExecTriage) if len(allCover[inp.call]) == 0 { // The call was not executed. Happens sometimes, reason unknown. continue } coverMu.RLock() cov := allCover[inp.call] diff := cover.SymmetricDifference(inp.cover, cov) minCover = cover.Intersection(minCover, cov) updateFlakes := len(diff) != 0 && len(cover.Difference(diff, flakes)) != 0 coverMu.RUnlock() if updateFlakes { coverMu.Lock() flakes = cover.Union(flakes, diff) coverMu.Unlock() } } stableNewCover := cover.Intersection(newCover, minCover) if len(stableNewCover) == 0 { return } inp.p, inp.call = prog.Minimize(inp.p, inp.call, func(p1 *prog.Prog, call1 int) bool { allCover := execute1(pid, env, p1, &statExecMinimize) coverMu.RLock() defer coverMu.RUnlock() if len(allCover[call1]) == 0 { return false // The call was not executed. } cov := allCover[call1] if len(cover.Intersection(stableNewCover, cov)) != len(stableNewCover) { return false } minCover = cover.Intersection(minCover, cov) return true }, false) inp.cover = minCover atomic.AddUint64(&statNewInput, 1) data := inp.p.Serialize() Logf(2, "added new input for %v to corpus:\n%s", call.CallName, data) a := &NewInputArgs{*flagName, RpcInput{call.CallName, data, inp.call, []uint32(inp.cover)}} if err := manager.Call("Manager.NewInput", a, nil); err != nil { panic(err) } corpusMu.Lock() defer corpusMu.Unlock() coverMu.Lock() defer coverMu.Unlock() corpusCover[call.CallID] = cover.Union(corpusCover[call.CallID], minCover) corpus = append(corpus, inp.p) corpusHashes[hash(data)] = struct{}{} }
func (mgr *Manager) httpSummary(w http.ResponseWriter, r *http.Request) { mgr.mu.Lock() defer mgr.mu.Unlock() data := &UISummaryData{ Name: mgr.cfg.Name, } data.Stats = append(data.Stats, UIStat{Name: "uptime", Value: fmt.Sprint(time.Since(mgr.startTime) / 1e9 * 1e9)}) data.Stats = append(data.Stats, UIStat{Name: "corpus", Value: fmt.Sprint(len(mgr.corpus))}) data.Stats = append(data.Stats, UIStat{Name: "triage queue", Value: fmt.Sprint(len(mgr.candidates))}) var err error if data.Crashes, err = mgr.collectCrashes(); err != nil { http.Error(w, fmt.Sprintf("failed to collect crashes: %v", err), http.StatusInternalServerError) return } type CallCov struct { count int cov cover.Cover } calls := make(map[string]*CallCov) for _, inp := range mgr.corpus { if calls[inp.Call] == nil { calls[inp.Call] = new(CallCov) } cc := calls[inp.Call] cc.count++ cc.cov = cover.Union(cc.cov, cover.Cover(inp.Cover)) } secs := uint64(1) if !mgr.firstConnect.IsZero() { secs = uint64(time.Since(mgr.firstConnect))/1e9 + 1 } var cov cover.Cover totalUnique := mgr.uniqueCover(true) for c, cc := range calls { cov = cover.Union(cov, cc.cov) unique := cover.Intersection(cc.cov, totalUnique) data.Calls = append(data.Calls, UICallType{ Name: c, Inputs: cc.count, Cover: len(cc.cov), UniqueCover: len(unique), }) } sort.Sort(UICallTypeArray(data.Calls)) data.Stats = append(data.Stats, UIStat{Name: "cover", Value: fmt.Sprint(len(cov)), Link: "/cover"}) var intStats []UIStat for k, v := range mgr.stats { val := fmt.Sprintf("%v", v) if x := v / secs; x >= 10 { val += fmt.Sprintf(" (%v/sec)", x) } else if x := v * 60 / secs; x >= 10 { val += fmt.Sprintf(" (%v/min)", x) } else { x := v * 60 * 60 / secs val += fmt.Sprintf(" (%v/hour)", x) } intStats = append(intStats, UIStat{Name: k, Value: val}) } sort.Sort(UIStatArray(intStats)) data.Stats = append(data.Stats, intStats...) data.Log = CachedLogOutput() if err := summaryTemplate.Execute(w, data); err != nil { http.Error(w, fmt.Sprintf("failed to execute template: %v", err), http.StatusInternalServerError) return } }