aboutsummaryrefslogtreecommitdiffstats
path: root/prog/rand.go
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2019-01-03 12:12:55 +0100
committerDmitry Vyukov <dvyukov@google.com>2019-01-03 12:23:57 +0100
commitadddc5fd46167e2c22cdc6a7d0d7b73cc418dc6f (patch)
tree26672d15766cc1e668761b74c29c64143e42ada2 /prog/rand.go
parent66fcd29b60c566b3d7b7cc75550a4b96e355164d (diff)
prog: remove several sources of non-determinism
Non-determinism is bad: - it leads to flaky coverage reports - it makes test failures non-reproducible Remove 4 sources of non-determinism related to maps: - file name generation - string generation - resource generation - hints generation All a test that ensures all main operations are fully deterministic.
Diffstat (limited to 'prog/rand.go')
-rw-r--r--prog/rand.go33
1 files changed, 20 insertions, 13 deletions
diff --git a/prog/rand.go b/prog/rand.go
index c3b7c2352..c1ac76776 100644
--- a/prog/rand.go
+++ b/prog/rand.go
@@ -9,6 +9,7 @@ import (
"math"
"math/rand"
"path/filepath"
+ "sort"
"strings"
"github.com/google/syzkaller/pkg/ifuzz"
@@ -188,11 +189,7 @@ func (r *randGen) filenameImpl(s *state) string {
// Generate a new name.
dir := "."
if r.oneOf(2) && len(s.files) != 0 {
- files := make([]string, 0, len(s.files))
- for f := range s.files {
- files = append(files, f)
- }
- dir = files[r.Intn(len(files))]
+ dir = r.randFromMap(s.files)
if len(dir) > 0 && dir[len(dir)-1] == 0 {
dir = dir[:len(dir)-1]
}
@@ -207,10 +204,15 @@ func (r *randGen) filenameImpl(s *state) string {
}
}
}
- files := make([]string, 0, len(s.files))
- for f := range s.files {
+ return r.randFromMap(s.files)
+}
+
+func (r *randGen) randFromMap(m map[string]bool) string {
+ files := make([]string, 0, len(m))
+ for f := range m {
files = append(files, f)
}
+ sort.Strings(files)
return files[r.Intn(len(files))]
}
@@ -221,11 +223,7 @@ func (r *randGen) randString(s *state, t *BufferType) []byte {
if len(s.strings) != 0 && r.bin() {
// Return an existing string.
// TODO(dvyukov): make s.strings indexed by string SubKind.
- strings := make([]string, 0, len(s.strings))
- for s := range s.strings {
- strings = append(strings, s)
- }
- return []byte(strings[r.Intn(len(strings))])
+ return []byte(r.randFromMap(s.strings))
}
punct := []byte{'!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '-', '+', '\\',
'/', ':', '.', ',', '-', '\'', '[', ']', '{', '}'}
@@ -275,6 +273,7 @@ func (r *randGen) createResource(s *state, res *ResourceType) (arg Arg, calls []
all = append(all, kind1)
}
}
+ sort.Strings(all)
kind = all[r.Intn(len(all))]
}
// Find calls that produce the necessary resources.
@@ -585,8 +584,16 @@ func (a *ResourceType) generate(r *randGen, s *state) (arg Arg, calls []*Call) {
switch {
case r.nOutOf(1000, 1011):
// Get an existing resource.
+ alltypes := make([][]*ResultArg, 0, len(s.resources))
+ for _, res1 := range s.resources {
+ alltypes = append(alltypes, res1)
+ }
+ sort.Slice(alltypes, func(i, j int) bool {
+ return alltypes[i][0].Type().Name() < alltypes[j][0].Type().Name()
+ })
var allres []*ResultArg
- for name1, res1 := range s.resources {
+ for _, res1 := range alltypes {
+ name1 := res1[0].Type().Name()
if r.target.isCompatibleResource(a.Desc.Name, name1) ||
r.oneOf(20) && r.target.isCompatibleResource(a.Desc.Kind[0], name1) {
allres = append(allres, res1...)