github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/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, 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, 5)
    34  	progData = inp2.Prog.Serialize()
    35  	for i := 0; i < 5; 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, corpus.StatSignal.Val(), 5)
    52  	assert.Equal(t, corpus.StatCover.Val(), 0)
    53  	assert.Equal(t, corpus.StatProgs.Val(), 2)
    54  
    55  	corpus.Minimize(true)
    56  }
    57  
    58  func TestCorpusCoverage(t *testing.T) {
    59  	target := getTarget(t, targets.TestOS, targets.TestArch64)
    60  	ch := make(chan NewItemEvent)
    61  	corpus := NewMonitoredCorpus(context.Background(), ch)
    62  	rs := rand.NewSource(0)
    63  
    64  	inp := generateInput(target, rs, 5, 5)
    65  	inp.Cover = []uint32{10, 11}
    66  	go corpus.Save(inp)
    67  	event := <-ch
    68  	assert.Equal(t, []uint32{10, 11}, event.NewCover)
    69  
    70  	inp.Call = 1
    71  	inp.Cover = []uint32{11, 12}
    72  	go corpus.Save(inp)
    73  	event = <-ch
    74  	assert.Equal(t, []uint32{12}, event.NewCover)
    75  
    76  	// Check the total corpus size.
    77  	assert.Equal(t, corpus.StatCover.Val(), 3)
    78  }
    79  
    80  func TestCorpusSaveConcurrency(t *testing.T) {
    81  	target := getTarget(t, targets.TestOS, targets.TestArch64)
    82  	corpus := NewCorpus(context.Background())
    83  
    84  	const (
    85  		routines = 10
    86  		iters    = 100
    87  	)
    88  
    89  	for i := 0; i < routines; i++ {
    90  		go func() {
    91  			rs := rand.NewSource(0)
    92  			r := rand.New(rs)
    93  			for it := 0; it < iters; it++ {
    94  				inp := generateInput(target, rs, 10, it)
    95  				corpus.Save(inp)
    96  				corpus.ChooseProgram(r).Clone()
    97  			}
    98  		}()
    99  	}
   100  }
   101  
   102  func generateInput(target *prog.Target, rs rand.Source, ncalls, sizeSig int) NewInput {
   103  	p := target.Generate(rs, ncalls, target.DefaultChoiceTable())
   104  	var raw []uint32
   105  	for i := 1; i <= sizeSig; i++ {
   106  		raw = append(raw, uint32(i))
   107  	}
   108  	return NewInput{
   109  		Prog:   p,
   110  		Call:   int(rs.Int63() % int64(len(p.Calls))),
   111  		Signal: signal.FromRaw(raw, 0),
   112  	}
   113  }
   114  
   115  func getTarget(t *testing.T, os, arch string) *prog.Target {
   116  	t.Parallel()
   117  	target, err := prog.GetTarget(os, arch)
   118  	if err != nil {
   119  		t.Fatal(err)
   120  	}
   121  	return target
   122  }