github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/prog/mutation.go (about) 1 // Copyright 2015 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 package prog 5 6 import ( 7 "encoding/binary" 8 "fmt" 9 "math" 10 "math/rand" 11 "sort" 12 13 "github.com/google/syzkaller/pkg/image" 14 ) 15 16 // Maximum length of generated binary blobs inserted into the program. 17 const maxBlobLen = uint64(100 << 10) 18 19 // Mutate program p. 20 // 21 // p: The program to mutate. 22 // rs: Random source. 23 // ncalls: The allowed maximum calls in mutated program. 24 // ct: ChoiceTable for syscalls. 25 // noMutate: Set of IDs of syscalls which should not be mutated. 26 // corpus: The entire corpus, including original program p. 27 func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable, noMutate map[int]bool, corpus []*Prog) { 28 p.MutateWithOpts(rs, ncalls, ct, noMutate, corpus, DefaultMutateOpts) 29 } 30 31 var DefaultMutateOpts = MutateOpts{ 32 ExpectedIterations: 5, 33 MutateArgCount: 3, 34 35 SquashWeight: 50, 36 SpliceWeight: 200, 37 InsertWeight: 100, 38 MutateArgWeight: 100, 39 RemoveCallWeight: 10, 40 } 41 42 type MutateOpts struct { 43 ExpectedIterations int 44 MutateArgCount int 45 SquashWeight int 46 SpliceWeight int 47 InsertWeight int 48 MutateArgWeight int 49 RemoveCallWeight int 50 } 51 52 func (o MutateOpts) weight() int { 53 return o.SquashWeight + o.SpliceWeight + o.InsertWeight + o.MutateArgWeight + o.RemoveCallWeight 54 } 55 56 func (p *Prog) MutateWithOpts(rs rand.Source, ncalls int, ct *ChoiceTable, noMutate map[int]bool, 57 corpus []*Prog, opts MutateOpts) { 58 if p.isUnsafe { 59 panic("mutation of unsafe programs is not supposed to be done") 60 } 61 totalWeight := opts.weight() 62 r := newRand(p.Target, rs) 63 if ncalls < len(p.Calls) { 64 ncalls = len(p.Calls) 65 } 66 ctx := &mutator{ 67 p: p, 68 r: r, 69 ncalls: ncalls, 70 ct: ct, 71 noMutate: noMutate, 72 corpus: corpus, 73 opts: opts, 74 } 75 for stop, ok := false, false; !stop; stop = ok && len(p.Calls) != 0 && r.oneOf(opts.ExpectedIterations) { 76 val := r.Intn(totalWeight) 77 val -= opts.SquashWeight 78 if val < 0 { 79 // Not all calls have anything squashable, 80 // so this has lower priority in reality. 81 ok = ctx.squashAny() 82 continue 83 } 84 val -= opts.SpliceWeight 85 if val < 0 { 86 ok = ctx.splice() 87 continue 88 } 89 val -= opts.InsertWeight 90 if val < 0 { 91 ok = ctx.insertCall() 92 continue 93 } 94 val -= opts.MutateArgWeight 95 if val < 0 { 96 ok = ctx.mutateArg() 97 continue 98 } 99 ok = ctx.removeCall() 100 } 101 p.sanitizeFix() 102 p.debugValidate() 103 if got := len(p.Calls); got < 1 || got > ncalls { 104 panic(fmt.Sprintf("bad number of calls after mutation: %v, want [1, %v]", got, ncalls)) 105 } 106 } 107 108 // Internal state required for performing mutations -- currently this matches 109 // the arguments passed to Mutate(). 110 type mutator struct { 111 p *Prog // The program to mutate. 112 r *randGen // The randGen instance. 113 ncalls int // The allowed maximum calls in mutated program. 114 ct *ChoiceTable // ChoiceTable for syscalls. 115 noMutate map[int]bool // Set of IDs of syscalls which should not be mutated. 116 corpus []*Prog // The entire corpus, including original program p. 117 opts MutateOpts 118 } 119 120 // This function selects a random other program p0 out of the corpus, and 121 // mutates ctx.p as follows: preserve ctx.p's Calls up to a random index i 122 // (exclusive) concatenated with p0's calls from index i (inclusive). 123 func (ctx *mutator) splice() bool { 124 p, r := ctx.p, ctx.r 125 if len(ctx.corpus) == 0 || len(p.Calls) == 0 || len(p.Calls) >= ctx.ncalls { 126 return false 127 } 128 p0 := ctx.corpus[r.Intn(len(ctx.corpus))] 129 p0c := p0.Clone() 130 idx := r.Intn(len(p.Calls)) 131 p.Calls = append(p.Calls[:idx], append(p0c.Calls, p.Calls[idx:]...)...) 132 for i := len(p.Calls) - 1; i >= ctx.ncalls; i-- { 133 p.RemoveCall(i) 134 } 135 return true 136 } 137 138 // Picks a random complex pointer and squashes its arguments into an ANY. 139 // Subsequently, if the ANY contains blobs, mutates a random blob. 140 func (ctx *mutator) squashAny() bool { 141 p, r := ctx.p, ctx.r 142 complexPtrs := p.complexPtrs() 143 if len(complexPtrs) == 0 { 144 return false 145 } 146 ptr := complexPtrs[r.Intn(len(complexPtrs))] 147 if ctx.noMutate[ptr.call.Meta.ID] { 148 return false 149 } 150 if !p.Target.isAnyPtr(ptr.arg.Type()) { 151 p.Target.squashPtr(ptr.arg) 152 } 153 var blobs []*DataArg 154 var bases []*PointerArg 155 ForeachSubArg(ptr.arg, func(arg Arg, ctx *ArgCtx) { 156 if data, ok := arg.(*DataArg); ok && arg.Dir() != DirOut { 157 blobs = append(blobs, data) 158 bases = append(bases, ctx.Base) 159 } 160 }) 161 if len(blobs) == 0 { 162 return false 163 } 164 // Note: we need to call analyze before we mutate the blob. 165 // After mutation the blob can grow out of bounds of the data area 166 // and analyze will crash with out-of-bounds access while marking existing allocations. 167 s := analyze(ctx.ct, ctx.corpus, p, ptr.call) 168 // TODO(dvyukov): we probably want special mutation for ANY. 169 // E.g. merging adjacent ANYBLOBs (we don't create them, 170 // but they can appear in future); or replacing ANYRES 171 // with a blob (and merging it with adjacent blobs). 172 idx := r.Intn(len(blobs)) 173 arg := blobs[idx] 174 base := bases[idx] 175 baseSize := base.Res.Size() 176 arg.data = mutateData(r, arg.Data(), 0, maxBlobLen) 177 // Update base pointer if size has increased. 178 if baseSize < base.Res.Size() { 179 newArg := r.allocAddr(s, base.Type(), base.Dir(), base.Res.Size(), base.Res) 180 *base = *newArg 181 } 182 return true 183 } 184 185 // Inserts a new call at a randomly chosen point (with bias towards the end of 186 // existing program). Does not insert a call if program already has ncalls. 187 func (ctx *mutator) insertCall() bool { 188 p, r := ctx.p, ctx.r 189 if len(p.Calls) >= ctx.ncalls { 190 return false 191 } 192 idx := r.biasedRand(len(p.Calls)+1, 5) 193 var c *Call 194 if idx < len(p.Calls) { 195 c = p.Calls[idx] 196 } 197 s := analyze(ctx.ct, ctx.corpus, p, c) 198 calls := r.generateCall(s, p, idx) 199 p.insertBefore(c, calls) 200 for len(p.Calls) > ctx.ncalls { 201 p.RemoveCall(idx) 202 } 203 return true 204 } 205 206 // Removes a random call from program. 207 func (ctx *mutator) removeCall() bool { 208 p, r := ctx.p, ctx.r 209 if len(p.Calls) == 0 { 210 return false 211 } 212 idx := r.Intn(len(p.Calls)) 213 p.RemoveCall(idx) 214 return true 215 } 216 217 // Mutate an argument of a random call. 218 func (ctx *mutator) mutateArg() bool { 219 p, r := ctx.p, ctx.r 220 if len(p.Calls) == 0 { 221 return false 222 } 223 224 idx := chooseCall(p, r) 225 if idx < 0 { 226 return false 227 } 228 c := p.Calls[idx] 229 if ctx.noMutate[c.Meta.ID] { 230 return false 231 } 232 updateSizes := true 233 for stop, ok := false, false; !stop; stop = ok && r.oneOf(ctx.opts.MutateArgCount) { 234 ok = true 235 ma := &mutationArgs{target: p.Target} 236 ForeachArg(c, ma.collectArg) 237 if len(ma.args) == 0 { 238 return false 239 } 240 s := analyze(ctx.ct, ctx.corpus, p, c) 241 arg, argCtx := ma.chooseArg(r.Rand) 242 calls, ok1 := p.Target.mutateArg(r, s, arg, argCtx, &updateSizes) 243 if !ok1 { 244 ok = false 245 continue 246 } 247 moreCalls, fieldsPatched := r.patchConditionalFields(c, s) 248 calls = append(calls, moreCalls...) 249 p.insertBefore(c, calls) 250 idx += len(calls) 251 for len(p.Calls) > ctx.ncalls { 252 idx-- 253 p.RemoveCall(idx) 254 } 255 if idx < 0 || idx >= len(p.Calls) || p.Calls[idx] != c { 256 panic(fmt.Sprintf("wrong call index: idx=%v calls=%v p.Calls=%v ncalls=%v", 257 idx, len(calls), len(p.Calls), ctx.ncalls)) 258 } 259 if updateSizes || fieldsPatched { 260 p.Target.assignSizesCall(c) 261 } 262 } 263 return true 264 } 265 266 // Select a call based on the complexity of the arguments. 267 func chooseCall(p *Prog, r *randGen) int { 268 var prioSum float64 269 var callPriorities []float64 270 for _, c := range p.Calls { 271 var totalPrio float64 272 ForeachArg(c, func(arg Arg, ctx *ArgCtx) { 273 prio, stopRecursion := arg.Type().getMutationPrio(p.Target, arg, false) 274 totalPrio += prio 275 ctx.Stop = stopRecursion 276 }) 277 prioSum += totalPrio 278 callPriorities = append(callPriorities, prioSum) 279 } 280 if prioSum == 0 { 281 return -1 // All calls are without arguments. 282 } 283 return sort.SearchFloat64s(callPriorities, prioSum*r.Float64()) 284 } 285 286 func (target *Target) mutateArg(r *randGen, s *state, arg Arg, ctx ArgCtx, updateSizes *bool) ([]*Call, bool) { 287 var baseSize uint64 288 if ctx.Base != nil { 289 baseSize = ctx.Base.Res.Size() 290 } 291 calls, retry, preserve := arg.Type().mutate(r, s, arg, ctx) 292 if retry { 293 return nil, false 294 } 295 if preserve { 296 *updateSizes = false 297 } 298 // Update base pointer if size has increased. 299 if base := ctx.Base; base != nil && baseSize < base.Res.Size() { 300 newArg := r.allocAddr(s, base.Type(), base.Dir(), base.Res.Size(), base.Res) 301 replaceArg(base, newArg) 302 } 303 return calls, true 304 } 305 306 func regenerate(r *randGen, s *state, arg Arg) (calls []*Call, retry, preserve bool) { 307 var newArg Arg 308 newArg, calls = r.generateArg(s, arg.Type(), arg.Dir()) 309 replaceArg(arg, newArg) 310 return 311 } 312 313 func mutateInt(r *randGen, a *ConstArg, t *IntType) uint64 { 314 switch { 315 case r.nOutOf(1, 3): 316 return a.Val + (uint64(r.Intn(4)) + 1) 317 case r.nOutOf(1, 2): 318 return a.Val - (uint64(r.Intn(4)) + 1) 319 default: 320 return a.Val ^ (1 << uint64(r.Intn(int(t.TypeBitSize())))) 321 } 322 } 323 324 func mutateAlignedInt(r *randGen, a *ConstArg, t *IntType) uint64 { 325 rangeEnd := t.RangeEnd 326 if t.RangeBegin == 0 && int64(rangeEnd) == -1 { 327 // Special [0:-1] range for all possible values. 328 rangeEnd = uint64(1<<t.TypeBitSize() - 1) 329 } 330 index := (a.Val - t.RangeBegin) / t.Align 331 misalignment := (a.Val - t.RangeBegin) % t.Align 332 switch { 333 case r.nOutOf(1, 3): 334 index += uint64(r.Intn(4)) + 1 335 case r.nOutOf(1, 2): 336 index -= uint64(r.Intn(4)) + 1 337 default: 338 index ^= 1 << uint64(r.Intn(int(t.TypeBitSize()))) 339 } 340 lastIndex := (rangeEnd - t.RangeBegin) / t.Align 341 index %= lastIndex + 1 342 return t.RangeBegin + index*t.Align + misalignment 343 } 344 345 func (t *IntType) mutate(r *randGen, s *state, arg Arg, ctx ArgCtx) (calls []*Call, retry, preserve bool) { 346 if r.bin() { 347 return regenerate(r, s, arg) 348 } 349 a := arg.(*ConstArg) 350 if t.Align == 0 { 351 a.Val = mutateInt(r, a, t) 352 } else { 353 a.Val = mutateAlignedInt(r, a, t) 354 } 355 a.Val = truncateToBitSize(a.Val, t.TypeBitSize()) 356 return 357 } 358 359 func (t *FlagsType) mutate(r *randGen, s *state, arg Arg, ctx ArgCtx) (calls []*Call, retry, preserve bool) { 360 a := arg.(*ConstArg) 361 for oldVal := a.Val; oldVal == a.Val; { 362 a.Val = r.flags(t.Vals, t.BitMask, a.Val) 363 } 364 return 365 } 366 367 func (t *LenType) mutate(r *randGen, s *state, arg Arg, ctx ArgCtx) (calls []*Call, retry, preserve bool) { 368 if !r.mutateSize(arg.(*ConstArg), *ctx.Parent, ctx.Fields) { 369 retry = true 370 return 371 } 372 preserve = true 373 return 374 } 375 376 func (t *ResourceType) mutate(r *randGen, s *state, arg Arg, ctx ArgCtx) (calls []*Call, retry, preserve bool) { 377 return regenerate(r, s, arg) 378 } 379 380 func (t *VmaType) mutate(r *randGen, s *state, arg Arg, ctx ArgCtx) (calls []*Call, retry, preserve bool) { 381 return regenerate(r, s, arg) 382 } 383 384 func (t *ProcType) mutate(r *randGen, s *state, arg Arg, ctx ArgCtx) (calls []*Call, retry, preserve bool) { 385 return regenerate(r, s, arg) 386 } 387 388 func (t *BufferType) mutate(r *randGen, s *state, arg Arg, ctx ArgCtx) (calls []*Call, retry, preserve bool) { 389 minLen, maxLen := uint64(0), maxBlobLen 390 if t.Kind == BufferBlobRange { 391 minLen, maxLen = t.RangeBegin, t.RangeEnd 392 } 393 a := arg.(*DataArg) 394 if a.Dir() == DirOut { 395 if t.Kind == BufferFilename && r.oneOf(100) { 396 a.size = uint64(r.randFilenameLength()) 397 } else { 398 mutateBufferSize(r, a, minLen, maxLen) 399 } 400 return 401 } 402 switch t.Kind { 403 case BufferBlobRand, BufferBlobRange: 404 data := append([]byte{}, a.Data()...) 405 a.data = mutateData(r, data, minLen, maxLen) 406 case BufferString: 407 if len(t.Values) != 0 { 408 a.data = r.randString(s, t) 409 } else { 410 if t.TypeSize != 0 { 411 minLen, maxLen = t.TypeSize, t.TypeSize 412 } 413 data := append([]byte{}, a.Data()...) 414 a.data = mutateData(r, data, minLen, maxLen) 415 } 416 case BufferFilename: 417 a.data = []byte(r.filename(s, t)) 418 case BufferGlob: 419 if len(t.Values) != 0 { 420 a.data = r.randString(s, t) 421 } else { 422 a.data = []byte(r.filename(s, t)) 423 } 424 case BufferText: 425 data := append([]byte{}, a.Data()...) 426 a.data = r.mutateText(t.Text, data) 427 case BufferCompressed: 428 a.data, retry = r.mutateImage(a.Data()) 429 default: 430 panic("unknown buffer kind") 431 } 432 return 433 } 434 435 func (r *randGen) mutateImage(compressed []byte) (data []byte, retry bool) { 436 data, dtor := image.MustDecompress(compressed) 437 defer dtor() 438 if len(data) == 0 { 439 return compressed, true // Do not mutate empty data. 440 } 441 hm := MakeGenericHeatmap(data, r.Rand) 442 for i := hm.NumMutations(); i > 0; i-- { 443 index := hm.ChooseLocation() 444 width := 1 << uint(r.Intn(4)) 445 if index+width > len(data) { 446 width = 1 447 } 448 storeInt(data[index:], r.randInt(uint64(width*8)), width) 449 } 450 return image.Compress(data), false 451 } 452 453 func mutateBufferSize(r *randGen, arg *DataArg, minLen, maxLen uint64) { 454 for oldSize := arg.Size(); oldSize == arg.Size(); { 455 arg.size += uint64(r.Intn(33)) - 16 456 // Cast to int64 to prevent underflows. 457 if int64(arg.size) < int64(minLen) { 458 arg.size = minLen 459 } 460 if arg.size > maxLen { 461 arg.size = maxLen 462 } 463 } 464 } 465 466 func (t *ArrayType) mutate(r *randGen, s *state, arg Arg, ctx ArgCtx) (calls []*Call, retry, preserve bool) { 467 a := arg.(*GroupArg) 468 if len(a.Inner) > 1 && r.oneOf(5) { 469 // Swap array elements. 470 for r.nOutOf(2, 3) { 471 i, j := r.Intn(len(a.Inner)), r.Intn(len(a.Inner)) 472 a.Inner[i], a.Inner[j] = a.Inner[j], a.Inner[i] 473 } 474 } 475 count := uint64(0) 476 switch t.Kind { 477 case ArrayRandLen: 478 if r.bin() { 479 for count = uint64(len(a.Inner)); r.bin(); { 480 count++ 481 } 482 } else { 483 for count == uint64(len(a.Inner)) { 484 count = r.randArrayLen() 485 } 486 } 487 case ArrayRangeLen: 488 if t.RangeBegin == t.RangeEnd { 489 panic("trying to mutate fixed length array") 490 } 491 for count == uint64(len(a.Inner)) { 492 count = r.randRange(t.RangeBegin, t.RangeEnd) 493 } 494 } 495 if count > uint64(len(a.Inner)) { 496 for count > uint64(len(a.Inner)) { 497 newArg, newCalls := r.generateArg(s, t.Elem, a.Dir()) 498 a.Inner = append(a.Inner, newArg) 499 calls = append(calls, newCalls...) 500 for _, c := range newCalls { 501 s.analyze(c) 502 } 503 } 504 } else if count < uint64(len(a.Inner)) { 505 for _, arg := range a.Inner[count:] { 506 removeArg(arg) 507 } 508 a.Inner = a.Inner[:count] 509 } 510 return 511 } 512 513 func (t *PtrType) mutate(r *randGen, s *state, arg Arg, ctx ArgCtx) (calls []*Call, retry, preserve bool) { 514 a := arg.(*PointerArg) 515 if r.oneOf(1000) { 516 removeArg(a.Res) 517 index := r.rand(len(r.target.SpecialPointers)) 518 newArg := MakeSpecialPointerArg(t, a.Dir(), index) 519 replaceArg(arg, newArg) 520 return 521 } 522 newArg := r.allocAddr(s, t, a.Dir(), a.Res.Size(), a.Res) 523 replaceArg(arg, newArg) 524 return 525 } 526 527 func (t *StructType) mutate(r *randGen, s *state, arg Arg, ctx ArgCtx) (calls []*Call, retry, preserve bool) { 528 gen := r.target.SpecialTypes[t.Name()] 529 if gen == nil { 530 panic("bad arg returned by mutationArgs: StructType") 531 } 532 var newArg Arg 533 newArg, calls = gen(&Gen{r, s}, t, arg.Dir(), arg) 534 a := arg.(*GroupArg) 535 for i, f := range newArg.(*GroupArg).Inner { 536 replaceArg(a.Inner[i], f) 537 } 538 return 539 } 540 541 func (t *UnionType) mutate(r *randGen, s *state, arg Arg, ctx ArgCtx) (calls []*Call, retry, preserve bool) { 542 if gen := r.target.SpecialTypes[t.Name()]; gen != nil { 543 var newArg Arg 544 newArg, calls = gen(&Gen{r, s}, t, arg.Dir(), arg) 545 replaceArg(arg, newArg) 546 return 547 } 548 a := arg.(*UnionArg) 549 index := r.Intn(len(t.Fields) - 1) 550 if index >= a.Index { 551 index++ 552 } 553 optType, optDir := t.Fields[index].Type, t.Fields[index].Dir(a.Dir()) 554 var newOpt Arg 555 newOpt, calls = r.generateArg(s, optType, optDir) 556 replaceArg(arg, MakeUnionArg(t, a.Dir(), newOpt, index)) 557 return 558 } 559 560 func (t *CsumType) mutate(r *randGen, s *state, arg Arg, ctx ArgCtx) (calls []*Call, retry, preserve bool) { 561 panic("CsumType can't be mutated") 562 } 563 564 func (t *ConstType) mutate(r *randGen, s *state, arg Arg, ctx ArgCtx) (calls []*Call, retry, preserve bool) { 565 panic("ConstType can't be mutated") 566 } 567 568 type mutationArgs struct { 569 target *Target 570 ignoreSpecial bool 571 prioSum float64 572 args []mutationArg 573 argsBuffer [16]mutationArg 574 } 575 576 type mutationArg struct { 577 arg Arg 578 ctx ArgCtx 579 priority float64 580 } 581 582 const ( 583 maxPriority = float64(10) 584 minPriority = float64(1) 585 dontMutate = float64(0) 586 ) 587 588 func (ma *mutationArgs) collectArg(arg Arg, ctx *ArgCtx) { 589 ignoreSpecial := ma.ignoreSpecial 590 ma.ignoreSpecial = false 591 592 typ := arg.Type() 593 prio, stopRecursion := typ.getMutationPrio(ma.target, arg, ignoreSpecial) 594 ctx.Stop = stopRecursion 595 596 if prio == dontMutate { 597 return 598 } 599 600 _, isArrayTyp := typ.(*ArrayType) 601 _, isBufferTyp := typ.(*BufferType) 602 if !isBufferTyp && !isArrayTyp && arg.Dir() == DirOut || !typ.Varlen() && typ.Size() == 0 { 603 return 604 } 605 606 if len(ma.args) == 0 { 607 ma.args = ma.argsBuffer[:0] 608 } 609 ma.prioSum += prio 610 ma.args = append(ma.args, mutationArg{arg, *ctx, ma.prioSum}) 611 } 612 613 func (ma *mutationArgs) chooseArg(r *rand.Rand) (Arg, ArgCtx) { 614 goal := ma.prioSum * r.Float64() 615 chosenIdx := sort.Search(len(ma.args), func(i int) bool { return ma.args[i].priority >= goal }) 616 arg := ma.args[chosenIdx] 617 return arg.arg, arg.ctx 618 } 619 620 // TODO: find a way to estimate optimal priority values. 621 // Assign a priority for each type. The boolean is the reference type and it has 622 // the minimum priority, since it has only two possible values. 623 func (t *IntType) getMutationPrio(target *Target, arg Arg, ignoreSpecial bool) (prio float64, stopRecursion bool) { 624 // For a integer without a range of values, the priority is based on 625 // the number of bits occupied by the underlying type. 626 plainPrio := math.Log2(float64(t.TypeBitSize())) + 0.1*maxPriority 627 if t.Kind != IntRange { 628 return plainPrio, false 629 } 630 631 size := t.RangeEnd - t.RangeBegin + 1 632 if t.Align != 0 { 633 if t.RangeBegin == 0 && int64(t.RangeEnd) == -1 { 634 // Special [0:-1] range for all possible values. 635 size = (1<<t.TypeBitSize()-1)/t.Align + 1 636 } else { 637 size = (t.RangeEnd-t.RangeBegin)/t.Align + 1 638 } 639 } 640 switch { 641 case size <= 15: 642 // For a small range, we assume that it is effectively 643 // similar with FlagsType and we need to try all possible values. 644 prio = rangeSizePrio(size) 645 case size <= 256: 646 // We consider that a relevant range has at most 256 647 // values (the number of values that can be represented on a byte). 648 prio = maxPriority 649 default: 650 // Ranges larger than 256 are equivalent with a plain integer. 651 prio = plainPrio 652 } 653 return prio, false 654 } 655 656 func (t *StructType) getMutationPrio(target *Target, arg Arg, ignoreSpecial bool) (prio float64, stopRecursion bool) { 657 if target.SpecialTypes[t.Name()] == nil || ignoreSpecial { 658 return dontMutate, false 659 } 660 return maxPriority, true 661 } 662 663 func (t *UnionType) getMutationPrio(target *Target, arg Arg, ignoreSpecial bool) (prio float64, stopRecursion bool) { 664 if target.SpecialTypes[t.Name()] == nil && len(t.Fields) == 1 || ignoreSpecial { 665 return dontMutate, false 666 } 667 // For a non-special type union with more than one option 668 // we mutate the union itself and also the value of the current option. 669 if target.SpecialTypes[t.Name()] == nil { 670 return maxPriority, false 671 } 672 return maxPriority, true 673 } 674 675 func (t *FlagsType) getMutationPrio(target *Target, arg Arg, ignoreSpecial bool) (prio float64, stopRecursion bool) { 676 prio = rangeSizePrio(uint64(len(t.Vals))) 677 if t.BitMask { 678 // We want a higher priority because the mutation will include 679 // more possible operations (bitwise operations). 680 prio += 0.1 * maxPriority 681 } 682 return prio, false 683 } 684 685 // Assigns a priority based on the range size. 686 func rangeSizePrio(size uint64) (prio float64) { 687 switch size { 688 case 0: 689 prio = dontMutate 690 case 1: 691 prio = minPriority 692 default: 693 // Priority proportional with the number of values. After a threshold, the priority is constant. 694 // The threshold is 15 because most of the calls have <= 15 possible values for a flag. 695 prio = math.Min(float64(size)/3+0.4*maxPriority, 0.9*maxPriority) 696 } 697 return prio 698 } 699 700 func (t *PtrType) getMutationPrio(target *Target, arg Arg, ignoreSpecial bool) (prio float64, stopRecursion bool) { 701 if arg.(*PointerArg).IsSpecial() { 702 // TODO: we ought to mutate this, but we don't have code for this yet. 703 return dontMutate, false 704 } 705 return 0.3 * maxPriority, false 706 } 707 708 func (t *ConstType) getMutationPrio(target *Target, arg Arg, ignoreSpecial bool) (prio float64, stopRecursion bool) { 709 return dontMutate, false 710 } 711 712 func (t *CsumType) getMutationPrio(target *Target, arg Arg, ignoreSpecial bool) (prio float64, stopRecursion bool) { 713 return dontMutate, false 714 } 715 716 func (t *ProcType) getMutationPrio(target *Target, arg Arg, ignoreSpecial bool) (prio float64, stopRecursion bool) { 717 return 0.5 * maxPriority, false 718 } 719 720 func (t *ResourceType) getMutationPrio(target *Target, arg Arg, ignoreSpecial bool) (prio float64, stopRecursion bool) { 721 return 0.5 * maxPriority, false 722 } 723 724 func (t *VmaType) getMutationPrio(target *Target, arg Arg, ignoreSpecial bool) (prio float64, stopRecursion bool) { 725 return 0.5 * maxPriority, false 726 } 727 728 func (t *LenType) getMutationPrio(target *Target, arg Arg, ignoreSpecial bool) (prio float64, stopRecursion bool) { 729 // Mutating LenType only produces "incorrect" results according to descriptions. 730 return 0.1 * maxPriority, false 731 } 732 733 func (t *BufferType) getMutationPrio(target *Target, arg Arg, ignoreSpecial bool) (prio float64, stopRecursion bool) { 734 if arg.Dir() == DirOut && !t.Varlen() { 735 return dontMutate, false 736 } 737 if t.Kind == BufferString && len(t.Values) == 1 { 738 // These are effectively consts (and frequently file names). 739 return dontMutate, false 740 } 741 if t.Kind == BufferCompressed { 742 // Prioritise mutation of compressed buffers, e.g. disk images (`compressed_image`). 743 return maxPriority, false 744 } 745 return 0.8 * maxPriority, false 746 } 747 748 func (t *ArrayType) getMutationPrio(target *Target, arg Arg, ignoreSpecial bool) (prio float64, stopRecursion bool) { 749 if t.Kind == ArrayRangeLen && t.RangeBegin == t.RangeEnd { 750 return dontMutate, false 751 } 752 return maxPriority, false 753 } 754 755 func mutateData(r *randGen, data []byte, minLen, maxLen uint64) []byte { 756 for stop := false; !stop; stop = stop && r.oneOf(3) { 757 f := mutateDataFuncs[r.Intn(len(mutateDataFuncs))] 758 data, stop = f(r, data, minLen, maxLen) 759 } 760 return data 761 } 762 763 // The maximum delta for integer mutations. 764 const maxDelta = 35 765 766 var mutateDataFuncs = [...]func(r *randGen, data []byte, minLen, maxLen uint64) ([]byte, bool){ 767 // TODO(dvyukov): duplicate part of data. 768 // Flip bit in byte. 769 func(r *randGen, data []byte, minLen, maxLen uint64) ([]byte, bool) { 770 if len(data) == 0 { 771 return data, false 772 } 773 byt := r.Intn(len(data)) 774 bit := r.Intn(8) 775 data[byt] ^= 1 << uint(bit) 776 return data, true 777 }, 778 // Insert random bytes. 779 func(r *randGen, data []byte, minLen, maxLen uint64) ([]byte, bool) { 780 if len(data) == 0 || uint64(len(data)) >= maxLen { 781 return data, false 782 } 783 n := r.Intn(16) + 1 784 if r := int(maxLen) - len(data); n > r { 785 n = r 786 } 787 pos := r.Intn(len(data)) 788 for i := 0; i < n; i++ { 789 data = append(data, 0) 790 } 791 copy(data[pos+n:], data[pos:]) 792 for i := 0; i < n; i++ { 793 data[pos+i] = byte(r.Int31()) 794 } 795 if uint64(len(data)) > maxLen || r.bin() { 796 data = data[:len(data)-n] // preserve original length 797 } 798 return data, true 799 }, 800 // Remove bytes. 801 func(r *randGen, data []byte, minLen, maxLen uint64) ([]byte, bool) { 802 if len(data) == 0 { 803 return data, false 804 } 805 n := r.Intn(16) + 1 806 if n > len(data) { 807 n = len(data) 808 } 809 pos := 0 810 if n < len(data) { 811 pos = r.Intn(len(data) - n) 812 } 813 copy(data[pos:], data[pos+n:]) 814 data = data[:len(data)-n] 815 if uint64(len(data)) < minLen || r.bin() { 816 for i := 0; i < n; i++ { 817 data = append(data, 0) // preserve original length 818 } 819 } 820 return data, true 821 }, 822 // Append a bunch of bytes. 823 func(r *randGen, data []byte, minLen, maxLen uint64) ([]byte, bool) { 824 if uint64(len(data)) >= maxLen { 825 return data, false 826 } 827 const max = 256 828 n := max - r.biasedRand(max, 10) 829 if r := int(maxLen) - len(data); n > r { 830 n = r 831 } 832 for i := 0; i < n; i++ { 833 data = append(data, byte(r.rand(256))) 834 } 835 return data, true 836 }, 837 // Replace int8/int16/int32/int64 with a random value. 838 func(r *randGen, data []byte, minLen, maxLen uint64) ([]byte, bool) { 839 width := 1 << uint(r.Intn(4)) 840 if len(data) < width { 841 return data, false 842 } 843 i := r.Intn(len(data) - width + 1) 844 storeInt(data[i:], r.Uint64(), width) 845 return data, true 846 }, 847 // Add/subtract from an int8/int16/int32/int64. 848 func(r *randGen, data []byte, minLen, maxLen uint64) ([]byte, bool) { 849 width := 1 << uint(r.Intn(4)) 850 if len(data) < width { 851 return data, false 852 } 853 i := r.Intn(len(data) - width + 1) 854 v := loadInt(data[i:], width) 855 delta := r.rand(2*maxDelta+1) - maxDelta 856 if delta == 0 { 857 delta = 1 858 } 859 if r.oneOf(10) { 860 v = swapInt(v, width) 861 v += delta 862 v = swapInt(v, width) 863 } else { 864 v += delta 865 } 866 storeInt(data[i:], v, width) 867 return data, true 868 }, 869 // Set int8/int16/int32/int64 to an interesting value. 870 func(r *randGen, data []byte, minLen, maxLen uint64) ([]byte, bool) { 871 width := 1 << uint(r.Intn(4)) 872 if len(data) < width { 873 return data, false 874 } 875 i := r.Intn(len(data) - width + 1) 876 value := r.randInt64() 877 if r.oneOf(10) { 878 value = swap64(value) 879 } 880 storeInt(data[i:], value, width) 881 return data, true 882 }, 883 } 884 885 func swap16(v uint16) uint16 { 886 v0 := byte(v >> 0) 887 v1 := byte(v >> 8) 888 v = 0 889 v |= uint16(v1) << 0 890 v |= uint16(v0) << 8 891 return v 892 } 893 894 func swap32(v uint32) uint32 { 895 v0 := byte(v >> 0) 896 v1 := byte(v >> 8) 897 v2 := byte(v >> 16) 898 v3 := byte(v >> 24) 899 v = 0 900 v |= uint32(v3) << 0 901 v |= uint32(v2) << 8 902 v |= uint32(v1) << 16 903 v |= uint32(v0) << 24 904 return v 905 } 906 907 func swap64(v uint64) uint64 { 908 v0 := byte(v >> 0) 909 v1 := byte(v >> 8) 910 v2 := byte(v >> 16) 911 v3 := byte(v >> 24) 912 v4 := byte(v >> 32) 913 v5 := byte(v >> 40) 914 v6 := byte(v >> 48) 915 v7 := byte(v >> 56) 916 v = 0 917 v |= uint64(v7) << 0 918 v |= uint64(v6) << 8 919 v |= uint64(v5) << 16 920 v |= uint64(v4) << 24 921 v |= uint64(v3) << 32 922 v |= uint64(v2) << 40 923 v |= uint64(v1) << 48 924 v |= uint64(v0) << 56 925 return v 926 } 927 928 func swapInt(v uint64, size int) uint64 { 929 switch size { 930 case 1: 931 return v 932 case 2: 933 return uint64(swap16(uint16(v))) 934 case 4: 935 return uint64(swap32(uint32(v))) 936 case 8: 937 return swap64(v) 938 default: 939 panic(fmt.Sprintf("swapInt: bad size %v", size)) 940 } 941 } 942 943 func loadInt(data []byte, size int) uint64 { 944 switch size { 945 case 1: 946 return uint64(data[0]) 947 case 2: 948 return uint64(binary.LittleEndian.Uint16(data)) 949 case 4: 950 return uint64(binary.LittleEndian.Uint32(data)) 951 case 8: 952 return binary.LittleEndian.Uint64(data) 953 default: 954 panic(fmt.Sprintf("loadInt: bad size %v", size)) 955 } 956 } 957 958 func storeInt(data []byte, v uint64, size int) { 959 switch size { 960 case 1: 961 data[0] = uint8(v) 962 case 2: 963 binary.LittleEndian.PutUint16(data, uint16(v)) 964 case 4: 965 binary.LittleEndian.PutUint32(data, uint32(v)) 966 case 8: 967 binary.LittleEndian.PutUint64(data, v) 968 default: 969 panic(fmt.Sprintf("storeInt: bad size %v", size)) 970 } 971 }