github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/prog/rotation_test.go (about)

     1  // Copyright 2019 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  	"bytes"
     8  	"fmt"
     9  	"math/rand"
    10  	"sort"
    11  	"testing"
    12  
    13  	"github.com/google/go-cmp/cmp"
    14  )
    15  
    16  func TestRotationResourceless(t *testing.T) {
    17  	target, rs, _ := initRandomTargetTest(t, "test", "64")
    18  	calls := map[*Syscall]bool{
    19  		target.SyscallMap["test$int"]: true,
    20  	}
    21  	got := MakeRotator(target, calls, rand.New(rs)).Select()
    22  	if diff := cmp.Diff(calls, got); diff != "" {
    23  		t.Fatal(diff)
    24  	}
    25  }
    26  
    27  func TestRotationRandom(t *testing.T) {
    28  	target, rs, _ := initTest(t)
    29  	for _, ncalls := range []int{10, 100, 1000, 1e9} {
    30  		rnd := rand.New(rand.NewSource(rs.Int63()))
    31  		t.Run(fmt.Sprint(ncalls), func(t *testing.T) {
    32  			t.Parallel()
    33  			calls0 := selectCalls(target, rnd, ncalls)
    34  			calls := MakeRotator(target, calls0, rnd).Select()
    35  			for call := range calls {
    36  				if !calls0[call] {
    37  					t.Errorf("selected disabled syscall %v", call.Name)
    38  				}
    39  			}
    40  			buf := new(bytes.Buffer)
    41  			var array []*Syscall
    42  			for call := range calls {
    43  				array = append(array, call)
    44  			}
    45  			sort.Slice(array, func(i, j int) bool {
    46  				return array[i].Name < array[j].Name
    47  			})
    48  			for _, call := range array {
    49  				fmt.Fprintf(buf, "%v\n", call.Name)
    50  			}
    51  			t.Logf("calls %v->%v:\n%s", len(calls0), len(calls), buf.Bytes())
    52  		})
    53  	}
    54  }
    55  
    56  func TestRotationCoverage(t *testing.T) {
    57  	target, rs, _ := initTest(t)
    58  	calls := make(map[*Syscall]bool)
    59  	counters := make(map[string]int)
    60  	for _, call := range target.Syscalls {
    61  		if call.Attrs.Disabled || call.Attrs.Automatic {
    62  			continue
    63  		}
    64  		calls[call] = true
    65  		counters[call.Name] = 0
    66  	}
    67  	rotator := MakeRotator(target, calls, rand.New(rs))
    68  nextIter:
    69  	for iter := 0; iter < 1e4; iter++ {
    70  		for call := range rotator.Select() {
    71  			counters[call.Name]++
    72  		}
    73  		for _, count := range counters {
    74  			if count == 0 {
    75  				continue nextIter
    76  			}
    77  		}
    78  		break
    79  	}
    80  	type pair struct {
    81  		name  string
    82  		count int
    83  	}
    84  	var pairs []pair
    85  	remain := len(counters)
    86  	for name, count := range counters {
    87  		pairs = append(pairs, pair{name, count})
    88  		if count != 0 {
    89  			remain--
    90  		}
    91  	}
    92  	sort.Slice(pairs, func(i, j int) bool {
    93  		if pairs[i].count != pairs[j].count {
    94  			return pairs[i].count > pairs[j].count
    95  		}
    96  		return pairs[i].name < pairs[j].name
    97  	})
    98  	for i, pair := range pairs {
    99  		t.Logf("# %4d: % 4d %v", i, pair.count, pair.name)
   100  	}
   101  	if remain != 0 {
   102  		t.Fatalf("uncovered syscalls: %v", remain)
   103  	}
   104  }
   105  
   106  func selectCalls(target *Target, rnd *rand.Rand, ncalls int) map[*Syscall]bool {
   107  retry:
   108  	calls := make(map[*Syscall]bool)
   109  	for _, call := range target.Syscalls {
   110  		calls[call] = true
   111  	}
   112  	for {
   113  		for {
   114  			remove := 0
   115  			switch {
   116  			case len(calls) > ncalls+1000:
   117  				remove = 100
   118  			case len(calls) > ncalls+50:
   119  				remove = 20
   120  			case len(calls) > ncalls:
   121  				remove = 1
   122  			default:
   123  				return calls
   124  			}
   125  			var array []*Syscall
   126  			for call := range calls {
   127  				array = append(array, call)
   128  			}
   129  			sort.Slice(array, func(i, j int) bool {
   130  				return array[i].ID < array[j].ID
   131  			})
   132  			rnd.Shuffle(len(calls), func(i, j int) {
   133  				array[i], array[j] = array[j], array[i]
   134  			})
   135  			for _, call := range array[:remove] {
   136  				delete(calls, call)
   137  			}
   138  			calls, _ = target.transitivelyEnabled(calls)
   139  			if len(calls) == 0 {
   140  				goto retry
   141  			}
   142  		}
   143  	}
   144  }
   145  
   146  func TestRotationDeterminism(t *testing.T) {
   147  	target, rs, _ := initTest(t)
   148  	calls := make(map[*Syscall]bool)
   149  	for _, call := range target.Syscalls {
   150  		calls[call] = true
   151  	}
   152  	seed := rs.Int63()
   153  	rnd0 := rand.New(rand.NewSource(seed))
   154  	calls0 := MakeRotator(target, calls, rnd0).Select()
   155  	rnd1 := rand.New(rand.NewSource(seed))
   156  	calls1 := MakeRotator(target, calls, rnd1).Select()
   157  	if diff := cmp.Diff(calls0, calls1); diff != "" {
   158  		t.Fatal(diff)
   159  	}
   160  }