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