aboutsummaryrefslogtreecommitdiffstats
path: root/prog/hints.go
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2017-12-08 10:45:11 +0100
committerDmitry Vyukov <dvyukov@google.com>2017-12-08 10:45:11 +0100
commit4016fc5ad7f3a4760c28fa7c6c3c1fa30e2ba1de (patch)
tree037d7746187ebe8cd7470cf28f6f124e6c5187f1 /prog/hints.go
parent5c1e6a291b4c23d3ace93651996d989be3b7939d (diff)
prog: fix hints of data args
Hints for data args don't work. We do all the work, but at the final stage we patch arg in the _old_ program, not in the _new_ one. So programs passed to the callback are all the same and don't contain any mutations. Tests did not catch this because they work right before that point (don't test the actual interface function MutateWithHints). Fix that and add a test that catches this.
Diffstat (limited to 'prog/hints.go')
-rw-r--r--prog/hints.go30
1 files changed, 22 insertions, 8 deletions
diff --git a/prog/hints.go b/prog/hints.go
index a4eb7ba36..065e9f8ba 100644
--- a/prog/hints.go
+++ b/prog/hints.go
@@ -19,7 +19,9 @@ package prog
// For more insights on particular mutations please see prog/hints_test.go.
import (
+ "bytes"
"encoding/binary"
+ "fmt"
)
type uint64Set map[uint64]bool
@@ -45,6 +47,20 @@ func (m CompMap) AddComp(arg1, arg2 uint64) {
m[arg1][arg2] = true
}
+func (m CompMap) String() string {
+ buf := new(bytes.Buffer)
+ for v, comps := range m {
+ if len(buf.Bytes()) != 0 {
+ fmt.Fprintf(buf, ", ")
+ }
+ fmt.Fprintf(buf, "0x%x:", v)
+ for c := range comps {
+ fmt.Fprintf(buf, " 0x%x", c)
+ }
+ }
+ return buf.String()
+}
+
// Mutates the program using the comparison operands stored in compMaps.
// For each of the mutants executes the exec callback.
func (p *Prog) MutateWithHints(callIndex int, comps CompMap, exec func(newP *Prog)) {
@@ -77,14 +93,13 @@ func generateHints(p *Prog, compMap CompMap, c *Call, arg Arg, exec func(p *Prog
}
newP, argMap := p.cloneImpl(true)
- var originalArg Arg
validateExec := func() {
if err := newP.validate(); err != nil {
- panic("a program generated with hints did not pass validation: " +
- err.Error())
+ panic(fmt.Sprintf("invalid hints candidate: %v", err))
}
exec(newP)
}
+ var originalArg Arg
constArgCandidate := func(newArg Arg) {
oldArg := argMap[arg]
newP.replaceArg(c, oldArg, newArg, nil)
@@ -92,7 +107,7 @@ func generateHints(p *Prog, compMap CompMap, c *Call, arg Arg, exec func(p *Prog
newP.replaceArg(c, oldArg, originalArg, nil)
}
- dataArgCandidate := func(newArg Arg) {
+ dataArgCandidate := func() {
// Data arg mutations are done in-place. No need to restore the original
// value - it gets restored in checkDataArg().
// dataArgCandidate is only needed for unit tests.
@@ -104,8 +119,7 @@ func generateHints(p *Prog, compMap CompMap, c *Call, arg Arg, exec func(p *Prog
originalArg = MakeConstArg(a.Type(), a.Val)
checkConstArg(a, compMap, constArgCandidate)
case *DataArg:
- originalArg = MakeDataArg(a.Type(), a.Data)
- checkDataArg(a, compMap, dataArgCandidate)
+ checkDataArg(argMap[arg].(*DataArg), compMap, dataArgCandidate)
}
}
@@ -115,7 +129,7 @@ func checkConstArg(arg *ConstArg, compMap CompMap, cb func(newArg Arg)) {
}
}
-func checkDataArg(arg *DataArg, compMap CompMap, cb func(newArg Arg)) {
+func checkDataArg(arg *DataArg, compMap CompMap, cb func()) {
bytes := make([]byte, 8)
original := make([]byte, 8)
for i := 0; i < min(len(arg.Data), maxDataLength); i++ {
@@ -124,7 +138,7 @@ func checkDataArg(arg *DataArg, compMap CompMap, cb func(newArg Arg)) {
for replacer := range shrinkExpand(val, compMap) {
binary.LittleEndian.PutUint64(bytes, replacer)
copy(arg.Data[i:], bytes)
- cb(arg)
+ cb()
copy(arg.Data[i:], original)
}
}