}
func (m *mutator) mutateInt(v, maxValue int64) int64 {
- numIters := 1 + m.r.exp2()
var max int64
- for iter := 0; iter < numIters; iter++ {
+ for {
max = 100
switch m.rand(2) {
case 0:
// Add a random number
if v >= maxValue {
- iter--
continue
}
if v > 0 && maxValue-v < max {
max = maxValue - v
}
v += int64(1 + m.rand(int(max)))
+ return v
case 1:
// Subtract a random number
if v <= -maxValue {
- iter--
continue
}
if v < 0 && maxValue+v < max {
max = maxValue + v
}
v -= int64(1 + m.rand(int(max)))
+ return v
}
}
- return v
}
func (m *mutator) mutateUInt(v, maxValue uint64) uint64 {
- numIters := 1 + m.r.exp2()
var max uint64
- for iter := 0; iter < numIters; iter++ {
+ for {
max = 100
switch m.rand(2) {
case 0:
// Add a random number
if v >= maxValue {
- iter--
continue
}
if v > 0 && maxValue-v < max {
}
v += uint64(1 + m.rand(int(max)))
+ return v
case 1:
// Subtract a random number
if v <= 0 {
- iter--
continue
}
if v < max {
max = v
}
v -= uint64(1 + m.rand(int(max)))
+ return v
}
}
- return v
}
func (m *mutator) mutateFloat(v, maxValue float64) float64 {
- numIters := 1 + m.r.exp2()
var max float64
- for iter := 0; iter < numIters; iter++ {
+ for {
switch m.rand(4) {
case 0:
// Add a random number
if v >= maxValue {
- iter--
continue
}
max = 100
max = maxValue - v
}
v += float64(1 + m.rand(int(max)))
+ return v
case 1:
// Subtract a random number
if v <= -maxValue {
- iter--
continue
}
max = 100
max = maxValue + v
}
v -= float64(1 + m.rand(int(max)))
+ return v
case 2:
// Multiply by a random number
absV := math.Abs(v)
if v == 0 || absV >= maxValue {
- iter--
continue
}
max = 10
max = maxValue / absV
}
v *= float64(1 + m.rand(int(max)))
+ return v
case 3:
// Divide by a random number
if v == 0 {
- iter--
continue
}
v /= float64(1 + m.rand(10))
+ return v
}
}
- return v
}
type byteSliceMutator func(*mutator, []byte) []byte
*ptrB = b
}()
- numIters := 1 + m.r.exp2()
- for iter := 0; iter < numIters; iter++ {
+ for {
mut := byteSliceMutators[m.rand(len(byteSliceMutators))]
- mutated := mut(m, b)
- if mutated == nil {
- iter--
- continue
+ if mutated := mut(m, b); mutated != nil {
+ b = mutated
+ return
}
- b = mutated
}
}
}
}
+// chainedMutations is how many mutations are applied before the worker
+// resets the input to it's original state.
+// NOTE: this number was picked without much thought. It is low enough that
+// it seems to create a significant diversity in mutated inputs. We may want
+// to consider looking into this more closely once we have a proper performance
+// testing framework. Another option is to randomly pick the number of chained
+// mutations on each invocation of the workerServer.fuzz method (this appears to
+// be what libFuzzer does, although there seems to be no documentation which
+// explains why this choice was made.)
+const chainedMutations = 5
+
// fuzz runs the test function on random variations of the input value in shared
// memory for a limited duration or number of iterations.
//
return resp
}
- vals, err := unmarshalCorpusFile(mem.valueCopy())
+ originalVals, err := unmarshalCorpusFile(mem.valueCopy())
if err != nil {
resp.InternalErr = err.Error()
return resp
}
+ vals := make([]interface{}, len(originalVals))
+ copy(vals, originalVals)
shouldStop := func() bool {
return args.Limit > 0 && mem.header().count >= args.Limit
select {
case <-ctx.Done():
return resp
-
default:
+ if mem.header().count%chainedMutations == 0 {
+ copy(vals, originalVals)
+ ws.m.r.save(&mem.header().randState, &mem.header().randInc)
+ }
ws.m.mutate(vals, cap(mem.valueRef()))
+
entry := CorpusEntry{Values: vals}
dur, cov, errMsg := fuzzOnce(entry)
if errMsg != "" {
wc.m.r.restore(mem.header().randState, mem.header().randInc)
if !args.Warmup {
// Only mutate the valuesOut if fuzzing actually occurred.
- for i := int64(0); i < resp.Count; i++ {
+ for i := int64(0); i < resp.Count%chainedMutations; i++ {
wc.m.mutate(valuesOut, cap(mem.valueRef()))
}
}