| // Copyright 2018 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 prog |
| |
| import ( |
| "math/rand" |
| "reflect" |
| "testing" |
| |
| "github.com/google/syzkaller/pkg/testutil" |
| ) |
| |
| func TestNormalizePrios(t *testing.T) { |
| prios := [][]int32{ |
| {2, 2, 2}, |
| {1, 2, 4}, |
| {1, 2, 0}, |
| } |
| want := [][]int32{ |
| {10, 10, 10}, |
| {4, 8, 17}, |
| {10, 20, 0}, |
| } |
| t.Logf("had: %+v", prios) |
| normalizePrios(prios) |
| if !reflect.DeepEqual(prios, want) { |
| t.Logf("got: %+v", prios) |
| t.Errorf("want: %+v", want) |
| } |
| } |
| |
| // Test static priorities assigned based on argument direction. |
| func TestStaticPriorities(t *testing.T) { |
| target := initTargetTest(t, "linux", "amd64") |
| rs := rand.NewSource(0) |
| // The test is probabilistic and needs some sensible number of iterations to succeed. |
| // If it fails try to increase the number a bit. |
| const iters = 2e5 |
| // The first call is the one that creates a resource and the rest are calls that can use that resource. |
| tests := [][]string{ |
| {"open", "read", "write", "mmap"}, |
| {"socket", "listen", "setsockopt"}, |
| } |
| ct := target.DefaultChoiceTable() |
| r := rand.New(rs) |
| for _, syscalls := range tests { |
| // Counts the number of times a call is chosen after a call that creates a resource (referenceCall). |
| counter := make(map[string]int) |
| referenceCall := syscalls[0] |
| for _, call := range syscalls { |
| count := 0 |
| for it := 0; it < iters; it++ { |
| chosenCall := target.Syscalls[ct.choose(r, target.SyscallMap[call].ID)].Name |
| if call == referenceCall { |
| counter[chosenCall]++ |
| } else if chosenCall == referenceCall { |
| count++ |
| } |
| } |
| if call == referenceCall { |
| continue |
| } |
| // Checks that prio[callCreatesRes][callUsesRes] > prio[callUsesRes][callCreatesRes] |
| if count >= counter[call] { |
| t.Fatalf("too high priority for %s -> %s: %d vs %s -> %s: %d", |
| call, referenceCall, count, referenceCall, call, counter[call]) |
| } |
| } |
| } |
| } |
| |
| func TestPrioDeterminism(t *testing.T) { |
| if testutil.RaceEnabled { |
| t.Skip("skipping in race mode, too slow") |
| } |
| target, rs, iters := initTest(t) |
| ct := target.DefaultChoiceTable() |
| var corpus []*Prog |
| for i := 0; i < 100; i++ { |
| corpus = append(corpus, target.Generate(rs, 10, ct)) |
| } |
| ct0 := target.BuildChoiceTable(corpus, nil) |
| ct1 := target.BuildChoiceTable(corpus, nil) |
| if !reflect.DeepEqual(ct0.runs, ct1.runs) { |
| t.Fatal("non-deterministic ChoiceTable") |
| } |
| for i := 0; i < iters; i++ { |
| seed := rs.Int63() |
| call0 := ct0.choose(rand.New(rand.NewSource(seed)), -1) |
| call1 := ct1.choose(rand.New(rand.NewSource(seed)), -1) |
| if call0 != call1 { |
| t.Fatalf("seed=%v iter=%v call=%v/%v", seed, i, call0, call1) |
| } |
| } |
| } |