diff options
| author | Aleksandr Nogikh <nogikh@google.com> | 2023-02-13 20:36:16 +0100 |
|---|---|---|
| committer | Aleksandr Nogikh <wp32pw@gmail.com> | 2023-02-14 14:56:49 +0100 |
| commit | 68f80dec7aa2d7c4ae909b4b3eb0953bc3990701 (patch) | |
| tree | e67c30b44eccdf99ffdac459dc3d287a6a8ed37f /prog/collide.go | |
| parent | 9db88265dbce82f690f9b166b24bba1570d15854 (diff) | |
prog: add a new DupCallCollide collide type
It duplicates random calls in a program and makes the duplicated copies
async.
E.g. it could transform
r0 = test()
test2(r0)
to
r0 = test()
test2(r0) (async)
test2(r0)
or
test() (async)
r0 = test()
test2(r0)
Diffstat (limited to 'prog/collide.go')
| -rw-r--r-- | prog/collide.go | 40 |
1 files changed, 40 insertions, 0 deletions
diff --git a/prog/collide.go b/prog/collide.go index fea8cc146..67cca6ecb 100644 --- a/prog/collide.go +++ b/prog/collide.go @@ -97,3 +97,43 @@ func DoubleExecCollide(origProg *Prog, rand *rand.Rand) (*Prog, error) { prog.Calls = append(prog.Calls, dupCalls...) return prog, nil } + +// DupCallCollide duplicates some of the calls in the program and marks them async. +// This should hopefully trigger races in a more granular way than DoubleExecCollide. +func DupCallCollide(origProg *Prog, rand *rand.Rand) (*Prog, error) { + if len(origProg.Calls) < 2 { + // For 1-call programs the behavior is similar to DoubleExecCollide. + return nil, fmt.Errorf("the prog is too small for the transformation") + } + // By default let's duplicate 1/3 calls in the original program. + insert := len(origProg.Calls) / 3 + if insert == 0 { + // .. but always at least one. + insert = 1 + } + if insert > maxAsyncPerProg { + insert = maxAsyncPerProg + } + if insert+len(origProg.Calls) > MaxCalls { + insert = MaxCalls - len(origProg.Calls) + } + if insert == 0 { + return nil, fmt.Errorf("no calls could be duplicated") + } + duplicate := map[int]bool{} + for _, pos := range rand.Perm(len(origProg.Calls))[:insert] { + duplicate[pos] = true + } + prog := origProg.Clone() + var retCalls []*Call + for i, c := range prog.Calls { + if duplicate[i] { + dupCall := cloneCall(c, nil) + dupCall.Props.Async = true + retCalls = append(retCalls, dupCall) + } + retCalls = append(retCalls, c) + } + prog.Calls = retCalls + return prog, nil +} |
