github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/prog/prio_test.go (about)

     1  // Copyright 2018 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 prog
     5  
     6  import (
     7  	"math/rand"
     8  	"reflect"
     9  	"testing"
    10  
    11  	"github.com/google/syzkaller/pkg/testutil"
    12  )
    13  
    14  func TestNormalizePrios(t *testing.T) {
    15  	prios := [][]int32{
    16  		{2, 2, 2},
    17  		{1, 2, 4},
    18  		{1, 2, 0},
    19  	}
    20  	want := [][]int32{
    21  		{10, 10, 10},
    22  		{4, 8, 17},
    23  		{10, 20, 0},
    24  	}
    25  	t.Logf("had:  %+v", prios)
    26  	normalizePrios(prios)
    27  	if !reflect.DeepEqual(prios, want) {
    28  		t.Logf("got:  %+v", prios)
    29  		t.Errorf("want: %+v", want)
    30  	}
    31  }
    32  
    33  // Test static priorities assigned based on argument direction.
    34  func TestStaticPriorities(t *testing.T) {
    35  	target := initTargetTest(t, "linux", "amd64")
    36  	rs := rand.NewSource(0)
    37  	// The test is probabilistic and needs some sensible number of iterations to succeed.
    38  	// If it fails try to increase the number a bit.
    39  	const iters = 2e5
    40  	// The first call is the one that creates a resource and the rest are calls that can use that resource.
    41  	tests := [][]string{
    42  		{"open", "read", "write", "mmap"},
    43  		{"socket", "listen", "setsockopt"},
    44  	}
    45  	ct := target.DefaultChoiceTable()
    46  	r := rand.New(rs)
    47  	for _, syscalls := range tests {
    48  		// Counts the number of times a call is chosen after a call that creates a resource (referenceCall).
    49  		counter := make(map[string]int)
    50  		referenceCall := syscalls[0]
    51  		for _, call := range syscalls {
    52  			count := 0
    53  			for it := 0; it < iters; it++ {
    54  				chosenCall := target.Syscalls[ct.choose(r, target.SyscallMap[call].ID)].Name
    55  				if call == referenceCall {
    56  					counter[chosenCall]++
    57  				} else if chosenCall == referenceCall {
    58  					count++
    59  				}
    60  			}
    61  			if call == referenceCall {
    62  				continue
    63  			}
    64  			// Checks that prio[callCreatesRes][callUsesRes] > prio[callUsesRes][callCreatesRes]
    65  			if count >= counter[call] {
    66  				t.Fatalf("too high priority for %s -> %s: %d vs %s -> %s: %d",
    67  					call, referenceCall, count, referenceCall, call, counter[call])
    68  			}
    69  		}
    70  	}
    71  }
    72  
    73  func TestPrioDeterminism(t *testing.T) {
    74  	if testutil.RaceEnabled {
    75  		t.Skip("skipping in race mode, too slow")
    76  	}
    77  	target, rs, iters := initTest(t)
    78  	ct := target.DefaultChoiceTable()
    79  	var corpus []*Prog
    80  	for i := 0; i < 100; i++ {
    81  		corpus = append(corpus, target.Generate(rs, 10, ct))
    82  	}
    83  	ct0 := target.BuildChoiceTable(corpus, nil)
    84  	ct1 := target.BuildChoiceTable(corpus, nil)
    85  	if !reflect.DeepEqual(ct0.runs, ct1.runs) {
    86  		t.Fatal("non-deterministic ChoiceTable")
    87  	}
    88  	for i := 0; i < iters; i++ {
    89  		seed := rs.Int63()
    90  		call0 := ct0.choose(rand.New(rand.NewSource(seed)), -1)
    91  		call1 := ct1.choose(rand.New(rand.NewSource(seed)), -1)
    92  		if call0 != call1 {
    93  			t.Fatalf("seed=%v iter=%v call=%v/%v", seed, i, call0, call1)
    94  		}
    95  	}
    96  }