From 68f80dec7aa2d7c4ae909b4b3eb0953bc3990701 Mon Sep 17 00:00:00 2001 From: Aleksandr Nogikh Date: Mon, 13 Feb 2023 20:36:16 +0100 Subject: 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) --- prog/collide.go | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'prog/collide.go') 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 +} -- cgit mrf-deployment