Skip to content

Commit cfc7315

Browse files
committed
syz-ci: upload syz progs with coverage to gcs
1 parent 831e362 commit cfc7315

File tree

3 files changed

+68
-30
lines changed

3 files changed

+68
-30
lines changed

pkg/cover/manager_to_ci.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,24 +27,24 @@ type dbCoverageRecord struct {
2727
CoverageInfo
2828
}
2929

30-
func writeJSLine(w io.Writer, covInfo dbCoverageRecord) error {
31-
bs, err := json.Marshal(covInfo)
30+
func WriteJSLine[T any](w io.Writer, obj *T) error {
31+
bs, err := json.Marshal(obj)
3232
if err != nil {
33-
return fmt.Errorf("failed to marshal covInfo: %w", err)
33+
return fmt.Errorf("json.Marshal: %w", err)
3434
}
3535
bs = append(bs, '\n')
3636
if _, err = w.Write(bs); err != nil {
37-
return fmt.Errorf("failed to write js data: %w", err)
37+
return fmt.Errorf("w.Write: %w", err)
3838
}
3939
return nil
4040
}
4141

4242
func WriteCIJSONLine(w io.Writer, managerCover CoverageInfo, ciDetails CIDetails) error {
43-
dbLine := dbCoverageRecord{
43+
dbLine := &dbCoverageRecord{
4444
CIDetails: ciDetails,
4545
CoverageInfo: managerCover,
4646
}
47-
if err := writeJSLine(w, dbLine); err != nil {
47+
if err := WriteJSLine(w, dbLine); err != nil {
4848
return fmt.Errorf("failed to serialize func line: %w", err)
4949
}
5050
return nil

syz-ci/manager.go

Lines changed: 60 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,9 @@ loop:
216216
if err := mgr.uploadCoverReport(); err != nil {
217217
mgr.Errorf("failed to upload cover report: %v", err)
218218
}
219+
if err := mgr.uploadProgramsWithCoverage(); err != nil {
220+
mgr.Errorf("failed to upload programs with coverage: %v", err)
221+
}
219222
if err := mgr.uploadCoverStat(fuzzingMinutesBeforeCover); err != nil {
220223
mgr.Errorf("failed to upload coverage stat: %v", err)
221224
}
@@ -875,8 +878,8 @@ func (mgr *Manager) uploadCoverReport() error {
875878
return nil
876879
}
877880

878-
func (mgr *Manager) uploadCoverStat(fuzzingMinutes int) error {
879-
if !mgr.managercfg.Cover || mgr.cfg.CoverPipelinePath == "" {
881+
func (mgr *Manager) uploadJSONLToGCS(mgrSrc, gcsDest string, f func(io.Writer, *json.Decoder, time.Time) error) error {
882+
if !mgr.managercfg.Cover || gcsDest == "" {
880883
return nil
881884
}
882885

@@ -889,19 +892,16 @@ func (mgr *Manager) uploadCoverStat(fuzzingMinutes int) error {
889892
}
890893
defer buildSem.Signal()
891894

892-
// Coverage report generation consumes and caches lots of memory.
893-
// In the syz-ci context report generation won't be used after this point,
894-
// so tell manager to flush report generator.
895-
resp, err := mgr.httpGET("/cover?jsonl=1&flush=1")
895+
resp, err := mgr.httpGET(mgrSrc)
896896
if err != nil {
897-
return fmt.Errorf("failed to httpGet /cover?jsonl=1 report: %w", err)
897+
return fmt.Errorf("failed to httpGet %s: %w", mgrSrc, err)
898898
}
899899
defer resp.Body.Close()
900900
if resp.StatusCode != http.StatusOK {
901901
sb := new(strings.Builder)
902902
io.Copy(sb, resp.Body)
903-
return fmt.Errorf("failed to GET /cover?jsonl=1, httpStatus %d: %s",
904-
resp.StatusCode, sb.String())
903+
return fmt.Errorf("failed to GET %s, httpStatus %d: %s",
904+
mgrSrc, resp.StatusCode, sb.String())
905905
}
906906

907907
curTime := time.Now()
@@ -910,12 +910,35 @@ func (mgr *Manager) uploadCoverStat(fuzzingMinutes int) error {
910910
go func() {
911911
decoder := json.NewDecoder(resp.Body)
912912
for decoder.More() {
913-
var covInfo cover.CoverageInfo
914-
if err := decoder.Decode(&covInfo); err != nil {
915-
pw.CloseWithError(fmt.Errorf("failed to decode CoverageInfo: %w", err))
913+
if err := f(pw, decoder, curTime); err != nil {
914+
pw.CloseWithError(fmt.Errorf("callback: %w", err))
916915
return
917916
}
918-
if err := cover.WriteCIJSONLine(pw, covInfo, cover.CIDetails{
917+
}
918+
pw.Close()
919+
}()
920+
fileName := fmt.Sprintf("%s/%s-%s-%d-%d.jsonl",
921+
mgr.mgrcfg.DashboardClient,
922+
mgr.name, curTime.Format(time.DateOnly),
923+
curTime.Hour(), curTime.Minute())
924+
if err := mgr.uploadFile(mgr.cfg.CoverPipelinePath, fileName, pr, false); err != nil {
925+
return fmt.Errorf("failed to uploadFileGCS(): %w", err)
926+
}
927+
return nil
928+
}
929+
930+
func (mgr *Manager) uploadCoverStat(fuzzingMinutes int) error {
931+
// Coverage report generation consumes and caches lots of memory.
932+
// In the syz-ci context report generation won't be used after this point,
933+
// so tell manager to flush report generator.
934+
if err := mgr.uploadJSONLToGCS("/cover?jsonl=1&flush=1",
935+
mgr.cfg.CoverPipelinePath,
936+
func(w io.Writer, dec *json.Decoder, curTime time.Time) error {
937+
var covInfo cover.CoverageInfo
938+
if err := dec.Decode(&covInfo); err != nil {
939+
return fmt.Errorf("failed to decode CoverageInfo: %w", err)
940+
}
941+
if err := cover.WriteCIJSONLine(w, covInfo, cover.CIDetails{
919942
Version: 1,
920943
Timestamp: curTime.Format(time.RFC3339Nano),
921944
FuzzingMinutes: fuzzingMinutes,
@@ -926,18 +949,31 @@ func (mgr *Manager) uploadCoverStat(fuzzingMinutes int) error {
926949
KernelBranch: mgr.lastBuild.KernelBranch,
927950
KernelCommit: mgr.lastBuild.KernelCommit,
928951
}); err != nil {
929-
pw.CloseWithError(fmt.Errorf("failed to write CIJSONLine: %w", err))
930-
return
952+
return fmt.Errorf("failed to write CIJSONLine: %w", err)
931953
}
932-
}
933-
pw.Close()
934-
}()
935-
fileName := fmt.Sprintf("%s/%s-%s-%d-%d.jsonl",
936-
mgr.mgrcfg.DashboardClient,
937-
mgr.name, curTime.Format(time.DateOnly),
938-
curTime.Hour(), curTime.Minute())
939-
if err := mgr.uploadFile(mgr.cfg.CoverPipelinePath, fileName, pr, false); err != nil {
940-
return fmt.Errorf("failed to uploadFileGCS(): %w", err)
954+
return nil
955+
}); err != nil {
956+
return fmt.Errorf("mgr.uploadJSONLToGCS: %w", err)
957+
}
958+
return nil
959+
}
960+
961+
func (mgr *Manager) uploadProgramsWithCoverage() error {
962+
if err := mgr.uploadJSONLToGCS("/coverprogs?jsonl=1",
963+
mgr.cfg.CoverProgramsPath,
964+
func(w io.Writer, dec *json.Decoder, curTime time.Time) error {
965+
var programCoverage cover.ProgramCoverage
966+
if err := dec.Decode(&programCoverage); err != nil {
967+
return fmt.Errorf("cover.ProgramCoverage: %w", err)
968+
}
969+
programCoverage.Repo = mgr.lastBuild.KernelRepo
970+
programCoverage.Commit = mgr.lastBuild.KernelCommit
971+
if err := cover.WriteJSLine(w, &programCoverage); err != nil {
972+
return fmt.Errorf("cover.WriteJSLine: %w", err)
973+
}
974+
return nil
975+
}); err != nil {
976+
return fmt.Errorf("mgr.uploadJSONLToGCS: %w", err)
941977
}
942978
return nil
943979
}

syz-ci/syz-ci.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ type Config struct {
107107
// Path to upload coverage reports from managers (optional).
108108
// Supported protocols: GCS (gs://) and HTTP PUT (http:// or https://).
109109
CoverUploadPath string `json:"cover_upload_path"`
110+
// Path to upload managers syz programs and their coverage in jsonl (optional).
111+
CoverProgramsPath string `json:"cover_programs_path"`
110112
// Path to upload json coverage reports from managers (optional).
111113
CoverPipelinePath string `json:"cover_pipeline_path"`
112114
// Path to upload corpus.db from managers (optional).

0 commit comments

Comments
 (0)