github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/pkg/corpus/corpus_test.go (about) 1 // Copyright 2024 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 package corpus 5 6 import ( 7 "context" 8 "math/rand" 9 "testing" 10 11 "github.com/google/syzkaller/pkg/signal" 12 "github.com/google/syzkaller/prog" 13 "github.com/google/syzkaller/sys/targets" 14 "github.com/stretchr/testify/assert" 15 ) 16 17 func TestCorpusOperation(t *testing.T) { 18 // Basic corpus functionality. 19 target := getTarget(t, targets.TestOS, targets.TestArch64) 20 ch := make(chan NewItemEvent) 21 corpus := NewMonitoredCorpus(context.Background(), ch) 22 23 // First program is saved. 24 rs := rand.NewSource(0) 25 inp1 := generateInput(target, rs, 5) 26 go corpus.Save(inp1) 27 event := <-ch 28 progData := inp1.Prog.Serialize() 29 assert.Equal(t, progData, event.ProgData) 30 assert.Equal(t, false, event.Exists) 31 32 // Second program is saved for every its call. 33 inp2 := generateInput(target, rs, 5) 34 progData = inp2.Prog.Serialize() 35 for i := 0; i < len(inp2.Prog.Calls); i++ { 36 inp2.Call = i 37 go corpus.Save(inp2) 38 event := <-ch 39 assert.Equal(t, progData, event.ProgData) 40 assert.Equal(t, i != 0, event.Exists) 41 } 42 43 // Verify that we can query corpus items. 44 items := corpus.Items() 45 assert.Len(t, items, 2) 46 for _, item := range items { 47 assert.Equal(t, item, corpus.Item(item.Sig)) 48 } 49 50 // Verify the total signal. 51 assert.Equal(t, 5, corpus.StatSignal.Val()) 52 assert.Equal(t, 2, corpus.StatProgs.Val()) 53 54 corpus.Minimize(true) 55 } 56 57 func TestCorpusCoverage(t *testing.T) { 58 target := getTarget(t, targets.TestOS, targets.TestArch64) 59 ch := make(chan NewItemEvent) 60 corpus := NewMonitoredCorpus(context.Background(), ch) 61 rs := rand.NewSource(0) 62 63 inp := generateInput(target, rs, 5) 64 inp.Cover = []uint64{10, 11} 65 go corpus.Save(inp) 66 event := <-ch 67 assert.Equal(t, []uint64{10, 11}, event.NewCover) 68 69 inp.Call = 1 70 inp.Cover = []uint64{11, 12} 71 go corpus.Save(inp) 72 event = <-ch 73 assert.Equal(t, []uint64{12}, event.NewCover) 74 75 // Check the total corpus size. 76 assert.Equal(t, corpus.StatCover.Val(), 3) 77 } 78 79 func TestCorpusSaveConcurrency(t *testing.T) { 80 target := getTarget(t, targets.TestOS, targets.TestArch64) 81 corpus := NewCorpus(context.Background()) 82 83 const ( 84 routines = 10 85 iters = 100 86 ) 87 88 for i := 0; i < routines; i++ { 89 go func() { 90 rs := rand.NewSource(0) 91 r := rand.New(rs) 92 for it := 0; it < iters; it++ { 93 inp := generateInput(target, rs, it) 94 corpus.Save(inp) 95 corpus.ChooseProgram(r).Clone() 96 } 97 }() 98 } 99 } 100 101 func generateInput(target *prog.Target, rs rand.Source, sizeSig int) NewInput { 102 return generateRangedInput(target, rs, 1, sizeSig) 103 } 104 105 func generateRangedInput(target *prog.Target, rs rand.Source, sigFrom, sigTo int) NewInput { 106 p := target.Generate(rs, 5, target.DefaultChoiceTable()) 107 var raw []uint64 108 for i := sigFrom; i <= sigTo; i++ { 109 raw = append(raw, uint64(i)) 110 } 111 return NewInput{ 112 Prog: p, 113 Call: int(rs.Int63() % int64(len(p.Calls))), 114 Signal: signal.FromRaw(raw, 0), 115 Cover: raw, 116 } 117 } 118 119 func getTarget(t *testing.T, os, arch string) *prog.Target { 120 t.Parallel() 121 target, err := prog.GetTarget(os, arch) 122 if err != nil { 123 t.Fatal(err) 124 } 125 return target 126 }