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  }