github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/pkg/fuzzer/job_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 fuzzer 5 6 import ( 7 "fmt" 8 "testing" 9 10 "github.com/google/syzkaller/pkg/cover" 11 "github.com/google/syzkaller/pkg/flatrpc" 12 "github.com/google/syzkaller/pkg/fuzzer/queue" 13 "github.com/google/syzkaller/pkg/signal" 14 "github.com/google/syzkaller/prog" 15 "github.com/google/syzkaller/sys/targets" 16 "github.com/stretchr/testify/assert" 17 ) 18 19 func TestDeflake(t *testing.T) { 20 type Test struct { 21 Info triageCall 22 Exec func(run uint64) (errno int32, signal []uint64, cover []uint64) 23 Runs uint64 24 } 25 tests := []Test{ 26 { 27 Info: triageCall{ 28 newSignal: signal.FromRaw([]uint64{0, 1, 2, 3, 4}, 0), 29 cover: cover.FromRaw([]uint64{10, 20}), 30 }, 31 Exec: func(run uint64) (int32, []uint64, []uint64) { 32 // For first, we return 1. For second, 2. And so on. 33 return 0, []uint64{run}, []uint64{10, 20} 34 }, 35 Runs: 3, 36 }, 37 { 38 Info: triageCall{ 39 newSignal: signal.FromRaw([]uint64{0, 1, 2}, 0), 40 // Cover is a union of all coverages. 41 cover: cover.FromRaw([]uint64{10, 20, 30, 40, 100}), 42 // 0, 2, 6 were in three resuls. 43 stableSignal: signal.FromRaw([]uint64{0, 2, 6}, 0), 44 // 0, 2 were also in newSignal. 45 newStableSignal: signal.FromRaw([]uint64{0, 2, 6}, 0), 46 }, 47 Exec: func(run uint64) (int32, []uint64, []uint64) { 48 switch run { 49 case 1: 50 return 0, []uint64{0, 2, 4, 6, 8}, []uint64{10, 20} 51 case 2: 52 // This one should be ignored -- it has a different errno. 53 return 1, []uint64{0, 1, 2}, []uint64{100} 54 case 3: 55 return 0, []uint64{0, 2, 4, 6, 8}, []uint64{20, 30} 56 case 4: 57 return 0, []uint64{0, 2, 6}, []uint64{30, 40} 58 } 59 panic("unrechable") 60 }, 61 Runs: 4, 62 }, 63 { 64 Info: triageCall{ 65 newSignal: signal.FromRaw([]uint64{0, 1, 2, 3, 4}, 3), 66 cover: cover.FromRaw([]uint64{10, 20}), 67 stableSignal: signal.FromRaw([]uint64{2}, 0), 68 newStableSignal: signal.FromRaw([]uint64{2}, 0), 69 }, 70 Exec: func(run uint64) (int32, []uint64, []uint64) { 71 // For first, we return 0 and 1. For second, 1 and 2. And so on. 72 return 0, []uint64{run, run + 1}, []uint64{10, 20} 73 }, 74 Runs: 2, 75 }, 76 } 77 78 target, err := prog.GetTarget(targets.TestOS, targets.TestArch64Fuzz) 79 assert.NoError(t, err) 80 const anyTestProg = `syz_compare(&AUTO="00000000", 0x4, &AUTO=@conditional={0x0, @void, @void, @void}, AUTO)` 81 prog, err := target.Deserialize([]byte(anyTestProg), prog.NonStrict) 82 assert.NoError(t, err) 83 84 for i, test := range tests { 85 t.Run(fmt.Sprint(i), func(t *testing.T) { 86 info := test.Info 87 info.signals[0] = test.Info.newSignal.Copy() 88 info.cover = nil 89 info.stableSignal = nil 90 info.newStableSignal = nil 91 testJob := &triageJob{ 92 p: prog, 93 calls: map[int]*triageCall{0: &info}, 94 fuzzer: &Fuzzer{ 95 Cover: newCover(), 96 Config: &Config{}, 97 }, 98 info: &JobInfo{}, 99 } 100 101 var run uint64 102 stop := testJob.deflake(func(_ *queue.Request, _ ProgFlags) *queue.Result { 103 run++ 104 errno, signal, cover := test.Exec(run) 105 return &queue.Result{ 106 Info: &flatrpc.ProgInfo{ 107 Calls: []*flatrpc.CallInfo{{ 108 Error: errno, 109 Signal: signal, 110 Cover: cover, 111 }}, 112 }, 113 } 114 }) 115 116 assert.False(t, stop) 117 assert.Equal(t, run, test.Runs) 118 assert.ElementsMatch(t, info.cover.Serialize(), test.Info.cover.Serialize()) 119 assert.ElementsMatch(t, info.stableSignal.ToRaw(), test.Info.stableSignal.ToRaw()) 120 assert.ElementsMatch(t, info.newStableSignal.ToRaw(), test.Info.newStableSignal.ToRaw()) 121 }) 122 } 123 }