github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/prog/rand.go (about) 1 // Copyright 2015/2016 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 "bytes" 8 "fmt" 9 "math" 10 "math/rand" 11 "path/filepath" 12 "sort" 13 "strings" 14 15 "github.com/google/syzkaller/pkg/ifuzz" 16 ) 17 18 const ( 19 // "Recommended" number of calls in programs that we try to aim at during fuzzing. 20 RecommendedCalls = 30 21 // "Recommended" max number of calls in programs. 22 // If we receive longer programs from hub/corpus we discard them. 23 MaxCalls = 40 24 // "Recommended" number of calls in KFuzzTest mode. These targets test the behavior 25 // of internal kernel functions rather than system behavior, and for this reason 26 // it is more sensible to generate a smaller number of calls instead of long chains. 27 RecommendedCallsKFuzzTest = 5 28 ) 29 30 type randGen struct { 31 *rand.Rand 32 target *Target 33 inGenerateResource bool 34 patchConditionalDepth int 35 genKFuzzTest bool 36 recDepth map[string]int 37 } 38 39 func newRand(target *Target, rs rand.Source) *randGen { 40 return &randGen{ 41 Rand: rand.New(rs), 42 target: target, 43 recDepth: make(map[string]int), 44 } 45 } 46 47 func (r *randGen) rand(n int) uint64 { 48 return uint64(r.Intn(n)) 49 } 50 51 func (r *randGen) randRange(begin, end uint64) uint64 { 52 return begin + uint64(r.Intn(int(end-begin+1))) 53 } 54 55 func (r *randGen) bin() bool { 56 return r.Intn(2) == 0 57 } 58 59 func (r *randGen) oneOf(n int) bool { 60 return r.Intn(n) == 0 61 } 62 63 func (r *randGen) rand64() uint64 { 64 v := uint64(r.Int63()) 65 if r.bin() { 66 v |= 1 << 63 67 } 68 return v 69 } 70 71 var ( 72 // Some potentially interesting integers. 73 specialInts = []uint64{ 74 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 75 64, 127, 128, 129, 255, 256, 257, 511, 512, 76 1023, 1024, 1025, 2047, 2048, 4095, 4096, 77 (1 << 15) - 1, (1 << 15), (1 << 15) + 1, 78 (1 << 16) - 1, (1 << 16), (1 << 16) + 1, 79 (1 << 31) - 1, (1 << 31), (1 << 31) + 1, 80 (1 << 32) - 1, (1 << 32), (1 << 32) + 1, 81 (1 << 63) - 1, (1 << 63), (1 << 63) + 1, 82 (1 << 64) - 1, 83 } 84 // The indexes (exclusive) for the maximum specialInts values that fit in 1, 2, ... 8 bytes. 85 specialIntIndex [9]int 86 ) 87 88 func init() { 89 sort.Slice(specialInts, func(i, j int) bool { 90 return specialInts[i] < specialInts[j] 91 }) 92 for i := range specialIntIndex { 93 bitSize := uint64(8 * i) 94 specialIntIndex[i] = sort.Search(len(specialInts), func(i int) bool { 95 return specialInts[i]>>bitSize != 0 96 }) 97 } 98 } 99 100 func (r *randGen) randInt64() uint64 { 101 return r.randInt(64) 102 } 103 104 func (r *randGen) randInt(bits uint64) uint64 { 105 v := r.rand64() 106 switch { 107 case r.nOutOf(100, 182): 108 v %= 10 109 case bits >= 8 && r.nOutOf(50, 82): 110 v = specialInts[r.Intn(specialIntIndex[bits/8])] 111 case r.nOutOf(10, 32): 112 v %= 256 113 case r.nOutOf(10, 22): 114 v %= 4 << 10 115 case r.nOutOf(10, 12): 116 v %= 64 << 10 117 default: 118 v %= 1 << 31 119 } 120 switch { 121 case r.nOutOf(100, 107): 122 case r.nOutOf(5, 7): 123 v = uint64(-int64(v)) 124 default: 125 v <<= uint(r.Intn(int(bits))) 126 } 127 return truncateToBitSize(v, bits) 128 } 129 130 func truncateToBitSize(v, bitSize uint64) uint64 { 131 if bitSize == 0 || bitSize > 64 { 132 panic(fmt.Sprintf("invalid bitSize value: %d", bitSize)) 133 } 134 return v & uint64(1<<bitSize-1) 135 } 136 137 func (r *randGen) randRangeInt(begin, end, bitSize, align uint64) uint64 { 138 if r.oneOf(100) { 139 return r.randInt(bitSize) 140 } 141 if align != 0 { 142 if begin == 0 && int64(end) == -1 { 143 // Special [0:-1] range for all possible values. 144 end = uint64(1<<bitSize - 1) 145 } 146 endAlign := (end - begin) / align 147 return begin + r.randRangeInt(0, endAlign, bitSize, 0)*align 148 } 149 return begin + (r.Uint64() % (end - begin + 1)) 150 } 151 152 // biasedRand returns a random int in range [0..n), 153 // probability of n-1 is k times higher than probability of 0. 154 func (r *randGen) biasedRand(n, k int) int { 155 nf, kf := float64(n), float64(k) 156 rf := nf * (kf/2 + 1) * r.Float64() 157 bf := (-1 + math.Sqrt(1+2*kf*rf/nf)) * nf / kf 158 return int(bf) 159 } 160 161 const maxArrayLen = 10 162 163 func (r *randGen) randArrayLen() uint64 { 164 // biasedRand produces: 10, 9, ..., 1, 0, 165 // we want: 1, 2, ..., 9, 10, 0 166 return uint64(maxArrayLen-r.biasedRand(maxArrayLen+1, 10)+1) % (maxArrayLen + 1) 167 } 168 169 func (r *randGen) randBufLen() (n uint64) { 170 switch { 171 case r.nOutOf(50, 56): 172 n = r.rand(256) 173 case r.nOutOf(5, 6): 174 n = 4 << 10 175 } 176 return 177 } 178 179 func (r *randGen) randPageCount() (n uint64) { 180 switch { 181 case r.nOutOf(100, 106): 182 n = r.rand(4) + 1 183 case r.nOutOf(5, 6): 184 n = r.rand(20) + 1 185 default: 186 n = (r.rand(3) + 1) * r.target.NumPages / 4 187 } 188 return 189 } 190 191 // Change a flag value or generate a new one. 192 // If you are changing this function, run TestFlags and examine effect of results. 193 func (r *randGen) flags(vv []uint64, bitmask bool, oldVal uint64) uint64 { 194 // Get these simpler cases out of the way first. 195 // Once in a while we want to return completely random values, 196 // or 0 which is frequently special. 197 if r.oneOf(100) { 198 return r.rand64() 199 } 200 if r.oneOf(50) { 201 return 0 202 } 203 if !bitmask && oldVal != 0 && r.oneOf(100) { 204 // Slightly increment/decrement the old value. 205 // This is especially important during mutation when len(vv) == 1, 206 // otherwise in that case we produce almost no randomness 207 // (the value is always mutated to 0). 208 inc := uint64(1) 209 if r.bin() { 210 inc = ^uint64(0) 211 } 212 v := oldVal + inc 213 for r.bin() { 214 v += inc 215 } 216 return v 217 } 218 if len(vv) == 1 { 219 // This usually means that value or 0, 220 // at least that's our best (and only) bet. 221 if r.bin() { 222 return 0 223 } 224 return vv[0] 225 } 226 if !bitmask && !r.oneOf(10) { 227 // Enumeration, so just choose one of the values. 228 return vv[r.rand(len(vv))] 229 } 230 if r.oneOf(len(vv) + 4) { 231 return 0 232 } 233 // Flip rand bits. Do this for non-bitmask sometimes 234 // because we may have detected bitmask incorrectly for complex cases 235 // (e.g. part of the vlaue is bitmask and another is not). 236 v := oldVal 237 if v != 0 && r.oneOf(10) { 238 v = 0 // Ignore the old value sometimes. 239 } 240 // We don't want to return 0 here, because we already given 0 241 // fixed probability above (otherwise we get 0 too frequently). 242 // Note: this loop can hang if all values are equal to 0. We don't generate such flags in the compiler now, 243 // but it used to hang occasionally, so we keep the try < 10 logic b/c we don't have a local check for values. 244 for try := 0; try < 10 && (v == 0 || r.nOutOf(2, 3)); try++ { 245 flag := vv[r.rand(len(vv))] 246 if r.oneOf(20) { 247 // Try choosing adjacent bit values in case we forgot 248 // to add all relevant flags to the descriptions. 249 if r.bin() { 250 flag >>= 1 251 } else { 252 flag <<= 1 253 } 254 } 255 v ^= flag 256 } 257 return v 258 } 259 260 func (r *randGen) filename(s *state, typ *BufferType) string { 261 fn := r.filenameImpl(s) 262 if fn != "" && fn[len(fn)-1] == 0 { 263 panic(fmt.Sprintf("zero-terminated filename: %q", fn)) 264 } 265 if escapingFilename(fn) { 266 panic(fmt.Sprintf("sandbox escaping file name %q, s.files are %v", fn, s.files)) 267 } 268 if !typ.Varlen() { 269 size := typ.Size() 270 if uint64(len(fn)) < size { 271 fn += string(make([]byte, size-uint64(len(fn)))) 272 } 273 fn = fn[:size] 274 } else if !typ.NoZ { 275 fn += "\x00" 276 } 277 return fn 278 } 279 280 func escapingFilename(file string) bool { 281 file = filepath.Clean(file) 282 return len(file) >= 1 && file[0] == '/' || 283 len(file) >= 2 && file[0] == '.' && file[1] == '.' 284 } 285 286 var specialFiles = []string{"", "."} 287 288 const specialFileLenPad = "a" 289 290 func (r *randGen) filenameImpl(s *state) string { 291 if r.oneOf(100) { 292 return specialFiles[r.Intn(len(specialFiles))] 293 } 294 if len(s.files) == 0 || r.oneOf(10) { 295 // Generate a new name. 296 dir := "." 297 if r.oneOf(2) && len(s.files) != 0 { 298 dir = r.randFromMap(s.files) 299 if dir != "" && dir[len(dir)-1] == 0 { 300 dir = dir[:len(dir)-1] 301 } 302 if r.oneOf(10) && filepath.Clean(dir)[0] != '.' { 303 dir += "/.." 304 } 305 } 306 for i := 0; ; i++ { 307 f := fmt.Sprintf("%v/file%v", dir, i) 308 if r.oneOf(100) { 309 // Make file name very long using target.SpecialFileLenghts consts. 310 // Add/subtract some small const to account for our file name prefix 311 // and potential kernel off-by-one's. 312 fileLen := r.randFilenameLength() 313 if add := fileLen - len(f); add > 0 { 314 f += strings.Repeat(specialFileLenPad, add) 315 } 316 } 317 if !s.files[f] { 318 return f 319 } 320 } 321 } 322 return r.randFromMap(s.files) 323 } 324 325 func (r *randGen) randFilenameLength() int { 326 off := r.biasedRand(10, 5) 327 if r.bin() { 328 off = -off 329 } 330 lens := r.target.SpecialFileLenghts 331 return max(lens[r.Intn(len(lens))]+off, 0) 332 } 333 334 func (r *randGen) randFromMap(m map[string]bool) string { 335 files := make([]string, 0, len(m)) 336 for f := range m { 337 files = append(files, f) 338 } 339 sort.Strings(files) 340 return files[r.Intn(len(files))] 341 } 342 343 func (r *randGen) randString(s *state, t *BufferType) []byte { 344 if len(t.Values) != 0 { 345 return []byte(t.Values[r.Intn(len(t.Values))]) 346 } 347 if len(s.strings) != 0 && r.bin() { 348 // Return an existing string. 349 // TODO(dvyukov): make s.strings indexed by string SubKind. 350 return []byte(r.randFromMap(s.strings)) 351 } 352 punct := []byte{'!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '-', '+', '\\', 353 '/', ':', '.', ',', '-', '\'', '[', ']', '{', '}'} 354 buf := new(bytes.Buffer) 355 for r.nOutOf(3, 4) { 356 if r.nOutOf(10, 11) { 357 buf.Write([]byte{punct[r.Intn(len(punct))]}) 358 } else { 359 buf.Write([]byte{byte(r.Intn(256))}) 360 } 361 } 362 // We always null-terminate strings that are inputs to KFuzzTest calls to 363 // avoid false-positive buffer overflow reports. 364 if r.oneOf(100) == t.NoZ || r.genKFuzzTest { 365 buf.Write([]byte{0}) 366 } 367 return buf.Bytes() 368 } 369 370 func (r *randGen) allocAddr(s *state, typ Type, dir Dir, size uint64, data Arg) *PointerArg { 371 return MakePointerArg(typ, dir, s.ma.alloc(r, size, data.Type().Alignment()), data) 372 } 373 374 func (r *randGen) allocVMA(s *state, typ Type, dir Dir, numPages uint64) *PointerArg { 375 page := s.va.alloc(r, numPages) 376 return MakeVmaPointerArg(typ, dir, page*r.target.PageSize, numPages*r.target.PageSize) 377 } 378 379 func (r *randGen) pruneRecursion(name string) (bool, func()) { 380 if r.recDepth[name] >= 2 { 381 return false, nil 382 } 383 r.recDepth[name]++ 384 return true, func() { 385 r.recDepth[name]-- 386 if r.recDepth[name] == 0 { 387 delete(r.recDepth, name) 388 } 389 } 390 } 391 392 func (r *randGen) createResource(s *state, res *ResourceType, dir Dir) (Arg, []*Call) { 393 if !r.inGenerateResource { 394 panic("inGenerateResource is not set") 395 } 396 kind := res.Desc.Name 397 // Find calls that produce the necessary resources. 398 ctors := r.enabledCtors(s, kind) 399 // We may have no resources, but still be in createResource due to ANYRES. 400 if len(r.target.resourceMap) != 0 && r.oneOf(1000) { 401 // Spoof resource subkind. 402 var all []string 403 for kind1 := range r.target.resourceMap { 404 if r.target.isCompatibleResource(res.Desc.Kind[0], kind1) { 405 all = append(all, kind1) 406 } 407 } 408 if len(all) == 0 { 409 panic(fmt.Sprintf("got no spoof resources for %v in %v/%v", 410 kind, r.target.OS, r.target.Arch)) 411 } 412 sort.Strings(all) 413 kind1 := all[r.Intn(len(all))] 414 ctors1 := r.enabledCtors(s, kind1) 415 if len(ctors1) != 0 { 416 // Don't use the resource for which we don't have any ctors. 417 // It's fine per-se because below we just return nil in such case. 418 // But in TestCreateResource tests we want to ensure that we don't fail 419 // to create non-optional resources, and if we spoof a non-optional 420 // resource with ctors with a optional resource w/o ctors, then that check will fail. 421 kind, ctors = kind1, ctors1 422 } 423 } 424 if len(ctors) == 0 { 425 // We may not have any constructors for optional input resources because we don't disable 426 // syscalls based on optional inputs resources w/o ctors in TransitivelyEnabledCalls. 427 return nil, nil 428 } 429 // Now we have a set of candidate calls that can create the necessary resource. 430 // Generate one of them. 431 var meta *Syscall 432 // Prefer precise constructors. 433 var precise []*Syscall 434 for _, info := range ctors { 435 if info.Precise { 436 precise = append(precise, info.Call) 437 } 438 } 439 if len(precise) > 0 { 440 // If the argument is optional, it's not guaranteed that there'd be a 441 // precise constructor. 442 meta = precise[r.Intn(len(precise))] 443 } 444 if meta == nil || r.oneOf(3) { 445 // Sometimes just take a random one. 446 meta = ctors[r.Intn(len(ctors))].Call 447 } 448 449 calls := r.generateParticularCall(s, meta) 450 s1 := newState(r.target, s.ct, nil) 451 s1.analyze(calls[len(calls)-1]) 452 // Now see if we have what we want. 453 var allres []*ResultArg 454 for kind1, res1 := range s1.resources { 455 if r.target.isCompatibleResource(kind, kind1) { 456 allres = append(allres, res1...) 457 } 458 } 459 sort.SliceStable(allres, func(i, j int) bool { 460 return allres[i].Type().Name() < allres[j].Type().Name() 461 }) 462 if len(allres) == 0 { 463 panic(fmt.Sprintf("failed to create a resource %v (%v) with %v", 464 res.Desc.Kind[0], kind, meta.Name)) 465 } 466 arg := MakeResultArg(res, dir, allres[r.Intn(len(allres))], 0) 467 return arg, calls 468 } 469 470 func (r *randGen) enabledCtors(s *state, kind string) []ResourceCtor { 471 var ret []ResourceCtor 472 for _, info := range r.target.resourceCtors[kind] { 473 if s.ct.Generatable(info.Call.ID) { 474 ret = append(ret, info) 475 } 476 } 477 return ret 478 } 479 480 func (r *randGen) generateText(kind TextKind) []byte { 481 switch kind { 482 case TextTarget: 483 if cfg := createTargetIfuzzConfig(r.target); cfg != nil { 484 return ifuzz.Generate(cfg, r.Rand) 485 } 486 text := make([]byte, 50) 487 for i := range text { 488 text[i] = byte(r.Intn(256)) 489 } 490 return text 491 default: 492 cfg := createIfuzzConfig(kind) 493 return ifuzz.Generate(cfg, r.Rand) 494 } 495 } 496 497 func (r *randGen) mutateText(kind TextKind, text []byte) []byte { 498 switch kind { 499 case TextTarget: 500 if cfg := createTargetIfuzzConfig(r.target); cfg != nil { 501 return ifuzz.Mutate(cfg, r.Rand, text) 502 } 503 return mutateData(r, text, 40, 60) 504 default: 505 cfg := createIfuzzConfig(kind) 506 return ifuzz.Mutate(cfg, r.Rand, text) 507 } 508 } 509 510 func createTargetIfuzzConfig(target *Target) *ifuzz.Config { 511 cfg := &ifuzz.Config{ 512 Len: 10, 513 Priv: false, 514 Exec: true, 515 MemRegions: []ifuzz.MemRegion{ 516 {Start: target.DataOffset, Size: target.NumPages * target.PageSize}, 517 }, 518 } 519 for _, p := range target.SpecialPointers { 520 cfg.MemRegions = append(cfg.MemRegions, ifuzz.MemRegion{ 521 Start: p & ^target.PageSize, Size: p & ^target.PageSize + target.PageSize, 522 }) 523 } 524 switch target.Arch { 525 case "amd64": 526 cfg.Mode = ifuzz.ModeLong64 527 cfg.Arch = ifuzz.ArchX86 528 case "386": 529 cfg.Mode = ifuzz.ModeProt32 530 cfg.Arch = ifuzz.ArchX86 531 case "ppc64": 532 cfg.Mode = ifuzz.ModeLong64 533 cfg.Arch = ifuzz.ArchPowerPC 534 case "arm64": 535 cfg.Mode = ifuzz.ModeLong64 536 cfg.Arch = ifuzz.ArchArm64 537 default: 538 return nil 539 } 540 return cfg 541 } 542 543 func createIfuzzConfig(kind TextKind) *ifuzz.Config { 544 cfg := &ifuzz.Config{ 545 Len: 10, 546 Priv: true, 547 Exec: true, 548 MemRegions: []ifuzz.MemRegion{ 549 {Start: 0 << 12, Size: 1 << 12}, 550 {Start: 1 << 12, Size: 1 << 12}, 551 {Start: 2 << 12, Size: 1 << 12}, 552 {Start: 3 << 12, Size: 1 << 12}, 553 {Start: 4 << 12, Size: 1 << 12}, 554 {Start: 5 << 12, Size: 1 << 12}, 555 {Start: 6 << 12, Size: 1 << 12}, 556 {Start: 7 << 12, Size: 1 << 12}, 557 {Start: 8 << 12, Size: 1 << 12}, 558 {Start: 9 << 12, Size: 1 << 12}, 559 {Start: 0xfec00000, Size: 0x100}, // ioapic 560 }, 561 } 562 switch kind { 563 case TextX86Real: 564 cfg.Mode = ifuzz.ModeReal16 565 cfg.Arch = ifuzz.ArchX86 566 case TextX86bit16: 567 cfg.Mode = ifuzz.ModeProt16 568 cfg.Arch = ifuzz.ArchX86 569 case TextX86bit32: 570 cfg.Mode = ifuzz.ModeProt32 571 cfg.Arch = ifuzz.ArchX86 572 case TextX86bit64: 573 cfg.Mode = ifuzz.ModeLong64 574 cfg.Arch = ifuzz.ArchX86 575 case TextPpc64: 576 cfg.Mode = ifuzz.ModeLong64 577 cfg.Arch = ifuzz.ArchPowerPC 578 case TextArm64: 579 cfg.Mode = ifuzz.ModeLong64 580 cfg.Arch = ifuzz.ArchArm64 581 default: 582 panic(fmt.Sprintf("unknown text kind: %v", kind)) 583 } 584 return cfg 585 } 586 587 // nOutOf returns true n out of outOf times. 588 func (r *randGen) nOutOf(n, outOf int) bool { 589 if n <= 0 || n >= outOf { 590 panic("bad probability") 591 } 592 v := r.Intn(outOf) 593 return v < n 594 } 595 596 func (r *randGen) generateCall(s *state, p *Prog, insertionPoint int) []*Call { 597 biasCall := -1 598 if insertionPoint > 0 { 599 // Choosing the base call is based on the insertion point of the new calls sequence. 600 insertionCall := p.Calls[r.Intn(insertionPoint)].Meta 601 if !insertionCall.Attrs.NoGenerate { 602 // We must be careful not to bias towards a non-generatable call. 603 biasCall = insertionCall.ID 604 } 605 } 606 idx := s.ct.choose(r.Rand, biasCall) 607 meta := r.target.Syscalls[idx] 608 return r.generateParticularCall(s, meta) 609 } 610 611 func (r *randGen) generateParticularCall(s *state, meta *Syscall) (calls []*Call) { 612 if meta.Attrs.Disabled { 613 panic(fmt.Sprintf("generating disabled call %v", meta.Name)) 614 } 615 if meta.Attrs.NoGenerate { 616 panic(fmt.Sprintf("generating no_generate call: %v", meta.Name)) 617 } 618 c := MakeCall(meta, nil) 619 // KFuzzTest calls restrict mutation and generation. Since calls to 620 // generateParticularCall can be recursive, we save the previous value, and 621 // set it true. 622 if c.Meta.Attrs.KFuzzTest { 623 tmp := r.genKFuzzTest 624 r.genKFuzzTest = true 625 defer func() { 626 r.genKFuzzTest = tmp 627 }() 628 } 629 c.Args, calls = r.generateArgs(s, meta.Args, DirIn) 630 moreCalls, _ := r.patchConditionalFields(c, s) 631 r.target.assignSizesCall(c) 632 return append(append(calls, moreCalls...), c) 633 } 634 635 // GenerateAllSyzProg generates a program that contains all pseudo syz_ calls for testing. 636 func (target *Target) GenerateAllSyzProg(rs rand.Source) *Prog { 637 p := &Prog{ 638 Target: target, 639 } 640 r := newRand(target, rs) 641 s := newState(target, target.DefaultChoiceTable(), nil) 642 for _, meta := range target.PseudoSyscalls() { 643 calls := r.generateParticularCall(s, meta) 644 for _, c := range calls { 645 s.analyze(c) 646 p.Calls = append(p.Calls, c) 647 } 648 } 649 if err := p.validate(); err != nil { 650 panic(err) 651 } 652 return p 653 } 654 655 // PseudoSyscalls selects one *Syscall for each pseudosyscall. 656 func (target *Target) PseudoSyscalls() []*Syscall { 657 handled := make(map[string]bool) 658 var ret []*Syscall 659 for _, meta := range target.Syscalls { 660 if !strings.HasPrefix(meta.CallName, "syz_") || 661 handled[meta.CallName] || 662 meta.Attrs.Disabled || 663 meta.Attrs.NoGenerate { 664 continue 665 } 666 ret = append(ret, meta) 667 handled[meta.CallName] = true 668 } 669 return ret 670 } 671 672 // GenSampleProg generates a single sample program for the call. 673 func (target *Target) GenSampleProg(meta *Syscall, rs rand.Source, ct *ChoiceTable) *Prog { 674 r := newRand(target, rs) 675 s := newState(target, ct, nil) 676 p := &Prog{ 677 Target: target, 678 } 679 for _, c := range r.generateParticularCall(s, meta) { 680 s.analyze(c) 681 p.Calls = append(p.Calls, c) 682 } 683 if err := p.validate(); err != nil { 684 panic(err) 685 } 686 return p 687 } 688 689 // DataMmapProg creates program that maps data segment. 690 // Also used for testing as the simplest program. 691 func (target *Target) DataMmapProg() *Prog { 692 return &Prog{ 693 Target: target, 694 Calls: target.MakeDataMmap(), 695 isUnsafe: true, 696 } 697 } 698 699 func (r *randGen) generateArgs(s *state, fields []Field, dir Dir) ([]Arg, []*Call) { 700 var calls []*Call 701 args := make([]Arg, len(fields)) 702 703 // Generate all args. Size args have the default value 0 for now. 704 for i, field := range fields { 705 arg, calls1 := r.generateArg(s, field.Type, field.Dir(dir)) 706 if arg == nil { 707 panic(fmt.Sprintf("generated arg is nil for field '%v', fields: %+v", field.Type.Name(), fields)) 708 } 709 args[i] = arg 710 calls = append(calls, calls1...) 711 } 712 713 return args, calls 714 } 715 716 func (r *randGen) generateArg(s *state, typ Type, dir Dir) (arg Arg, calls []*Call) { 717 return r.generateArgImpl(s, typ, dir, false) 718 } 719 720 func (r *randGen) generateArgImpl(s *state, typ Type, dir Dir, ignoreSpecial bool) (arg Arg, calls []*Call) { 721 if dir == DirOut { 722 // No need to generate something interesting for output scalar arguments. 723 // But we still need to generate the argument itself so that it can be referenced 724 // in subsequent calls. For the same reason we do generate pointer/array/struct 725 // output arguments (their elements can be referenced in subsequent calls). 726 switch typ.(type) { 727 case *IntType, *FlagsType, *ConstType, *ProcType, *VmaType, *ResourceType: 728 return typ.DefaultArg(dir), nil 729 } 730 } 731 732 if typ.Optional() && r.oneOf(5) { 733 if res, ok := typ.(*ResourceType); ok { 734 v := res.Desc.Values[r.Intn(len(res.Desc.Values))] 735 return MakeResultArg(typ, dir, nil, v), nil 736 } 737 return typ.DefaultArg(dir), nil 738 } 739 740 if !ignoreSpecial && dir != DirOut { 741 switch typ.(type) { 742 case *StructType, *UnionType: 743 if gen := r.target.SpecialTypes[typ.Name()]; gen != nil { 744 return gen(&Gen{r, s}, typ, dir, nil) 745 } 746 } 747 } 748 749 return typ.generate(r, s, dir) 750 } 751 752 func (a *ResourceType) generate(r *randGen, s *state, dir Dir) (arg Arg, calls []*Call) { 753 canRecurse := false 754 if !r.inGenerateResource { 755 // Don't allow recursion for resourceCentric/createResource. 756 // That can lead to generation of huge programs and may be very slow 757 // (esp. if we are generating some failing attempts in createResource already). 758 r.inGenerateResource = true 759 defer func() { r.inGenerateResource = false }() 760 canRecurse = true 761 } 762 if canRecurse && r.nOutOf(8, 10) || 763 !canRecurse && r.nOutOf(19, 20) { 764 arg = r.existingResource(s, a, dir) 765 if arg != nil { 766 return 767 } 768 } 769 if canRecurse { 770 if r.oneOf(4) { 771 arg, calls = r.resourceCentric(s, a, dir) 772 if arg != nil { 773 return 774 } 775 } 776 if r.nOutOf(4, 5) { 777 // If we could not reuse a resource, let's prefer resource creation over 778 // random int substitution. 779 arg, calls = r.createResource(s, a, dir) 780 if arg != nil { 781 return 782 } 783 } 784 } 785 special := a.SpecialValues() 786 arg = MakeResultArg(a, dir, nil, special[r.Intn(len(special))]) 787 return 788 } 789 790 func (a *BufferType) generate(r *randGen, s *state, dir Dir) (arg Arg, calls []*Call) { 791 switch a.Kind { 792 case BufferBlobRand, BufferBlobRange: 793 sz := r.randBufLen() 794 if a.Kind == BufferBlobRange { 795 sz = r.randRange(a.RangeBegin, a.RangeEnd) 796 } 797 if dir == DirOut { 798 return MakeOutDataArg(a, dir, sz), nil 799 } 800 data := make([]byte, sz) 801 for i := range data { 802 data[i] = byte(r.Intn(256)) 803 } 804 return MakeDataArg(a, dir, data), nil 805 case BufferString: 806 data := r.randString(s, a) 807 if dir == DirOut { 808 return MakeOutDataArg(a, dir, uint64(len(data))), nil 809 } 810 return MakeDataArg(a, dir, data), nil 811 case BufferFilename: 812 if dir == DirOut { 813 var sz uint64 814 switch { 815 case !a.Varlen(): 816 sz = a.Size() 817 case r.nOutOf(1, 3): 818 sz = r.rand(100) 819 default: 820 sz = uint64(r.randFilenameLength()) 821 } 822 return MakeOutDataArg(a, dir, sz), nil 823 } 824 return MakeDataArg(a, dir, []byte(r.filename(s, a))), nil 825 case BufferGlob: 826 return MakeDataArg(a, dir, r.randString(s, a)), nil 827 case BufferText: 828 if dir == DirOut { 829 return MakeOutDataArg(a, dir, uint64(r.Intn(100))), nil 830 } 831 return MakeDataArg(a, dir, r.generateText(a.Text)), nil 832 case BufferCompressed: 833 panic(fmt.Sprintf("can't generate compressed type %v", a)) 834 default: 835 panic("unknown buffer kind") 836 } 837 } 838 839 func (a *VmaType) generate(r *randGen, s *state, dir Dir) (arg Arg, calls []*Call) { 840 npages := r.randPageCount() 841 if a.RangeBegin != 0 || a.RangeEnd != 0 { 842 npages = a.RangeBegin + uint64(r.Intn(int(a.RangeEnd-a.RangeBegin+1))) 843 } 844 return r.allocVMA(s, a, dir, npages), nil 845 } 846 847 func (a *FlagsType) generate(r *randGen, s *state, dir Dir) (arg Arg, calls []*Call) { 848 return MakeConstArg(a, dir, r.flags(a.Vals, a.BitMask, 0)), nil 849 } 850 851 func (a *ConstType) generate(r *randGen, s *state, dir Dir) (arg Arg, calls []*Call) { 852 return MakeConstArg(a, dir, a.Val), nil 853 } 854 855 func (a *IntType) generate(r *randGen, s *state, dir Dir) (arg Arg, calls []*Call) { 856 bits := a.TypeBitSize() 857 v := r.randInt(bits) 858 switch a.Kind { 859 case IntRange: 860 v = r.randRangeInt(a.RangeBegin, a.RangeEnd, bits, a.Align) 861 } 862 return MakeConstArg(a, dir, v), nil 863 } 864 865 func (a *ProcType) generate(r *randGen, s *state, dir Dir) (arg Arg, calls []*Call) { 866 return MakeConstArg(a, dir, r.rand(int(a.ValuesPerProc))), nil 867 } 868 869 func (a *ArrayType) generate(r *randGen, s *state, dir Dir) (arg Arg, calls []*Call) { 870 // Allow infinite recursion for arrays. 871 switch a.Elem.(type) { 872 case *StructType, *ArrayType, *UnionType: 873 ok, release := r.pruneRecursion(a.Elem.Name()) 874 if !ok { 875 return MakeGroupArg(a, dir, nil), nil 876 } 877 defer release() 878 } 879 var count uint64 880 switch a.Kind { 881 case ArrayRandLen: 882 count = r.randArrayLen() 883 case ArrayRangeLen: 884 count = r.randRange(a.RangeBegin, a.RangeEnd) 885 } 886 // The resource we are trying to generate may be in the array elements, so create at least 1. 887 if r.inGenerateResource && count == 0 { 888 count = 1 889 } 890 var inner []Arg 891 for i := uint64(0); i < count; i++ { 892 arg1, calls1 := r.generateArg(s, a.Elem, dir) 893 inner = append(inner, arg1) 894 calls = append(calls, calls1...) 895 } 896 return MakeGroupArg(a, dir, inner), calls 897 } 898 899 func (a *StructType) generate(r *randGen, s *state, dir Dir) (arg Arg, calls []*Call) { 900 args, calls := r.generateArgs(s, a.Fields, dir) 901 group := MakeGroupArg(a, dir, args) 902 return group, calls 903 } 904 905 func (a *UnionType) generate(r *randGen, s *state, dir Dir) (arg Arg, calls []*Call) { 906 if a.isConditional() { 907 // Conditions may reference other fields that may not have already 908 // been generated. We'll fill them in later. 909 return a.DefaultArg(dir), nil 910 } 911 index := r.Intn(len(a.Fields)) 912 optType, optDir := a.Fields[index].Type, a.Fields[index].Dir(dir) 913 opt, calls := r.generateArg(s, optType, optDir) 914 return MakeUnionArg(a, dir, opt, index), calls 915 } 916 917 func (a *PtrType) generate(r *randGen, s *state, dir Dir) (arg Arg, calls []*Call) { 918 // Allow infinite recursion for optional pointers. 919 if a.Optional() { 920 switch a.Elem.(type) { 921 case *StructType, *ArrayType, *UnionType: 922 ok, release := r.pruneRecursion(a.Elem.Name()) 923 if !ok { 924 return MakeSpecialPointerArg(a, dir, 0), nil 925 } 926 defer release() 927 } 928 } 929 // The resource we are trying to generate may be in the pointer, 930 // so don't try to create an empty special pointer during resource generation. 931 if !r.inGenerateResource && r.oneOf(1000) { 932 index := r.rand(len(r.target.SpecialPointers)) 933 return MakeSpecialPointerArg(a, dir, index), nil 934 } 935 inner, calls := r.generateArg(s, a.Elem, a.ElemDir) 936 arg = r.allocAddr(s, a, dir, inner.Size(), inner) 937 return arg, calls 938 } 939 940 func (a *LenType) generate(r *randGen, s *state, dir Dir) (arg Arg, calls []*Call) { 941 // Updated later in assignSizesCall. 942 return MakeConstArg(a, dir, 0), nil 943 } 944 945 func (a *CsumType) generate(r *randGen, s *state, dir Dir) (arg Arg, calls []*Call) { 946 // Filled at runtime by executor. 947 return MakeConstArg(a, dir, 0), nil 948 } 949 950 func (r *randGen) existingResource(s *state, res *ResourceType, dir Dir) Arg { 951 alltypes := make([][]*ResultArg, 0, len(s.resources)) 952 for _, res1 := range s.resources { 953 alltypes = append(alltypes, res1) 954 } 955 sort.Slice(alltypes, func(i, j int) bool { 956 return alltypes[i][0].Type().Name() < alltypes[j][0].Type().Name() 957 }) 958 var allres []*ResultArg 959 for _, res1 := range alltypes { 960 name1 := res1[0].Type().Name() 961 if r.target.isCompatibleResource(res.Desc.Name, name1) || 962 r.oneOf(50) && r.target.isCompatibleResource(res.Desc.Kind[0], name1) { 963 allres = append(allres, res1...) 964 } 965 } 966 if len(allres) == 0 { 967 return nil 968 } 969 return MakeResultArg(res, dir, allres[r.Intn(len(allres))], 0) 970 } 971 972 // Finds a compatible resource with the type `t` and the calls that initialize that resource. 973 func (r *randGen) resourceCentric(s *state, t *ResourceType, dir Dir) (arg Arg, calls []*Call) { 974 var p *Prog 975 var resource *ResultArg 976 for _, idx := range r.Perm(len(s.corpus)) { 977 corpusProg := s.corpus[idx] 978 resources := getCompatibleResources(corpusProg, t.TypeName, r) 979 if len(resources) == 0 { 980 continue 981 } 982 argMap := make(map[*ResultArg]*ResultArg) 983 p = corpusProg.cloneWithMap(argMap) 984 resource = argMap[resources[r.Intn(len(resources))]] 985 break 986 } 987 988 // No compatible resource was found. 989 if resource == nil { 990 return nil, nil 991 } 992 993 // Set that stores the resources that appear in the same calls with the selected resource. 994 relatedRes := map[*ResultArg]bool{resource: true} 995 996 // Remove unrelated calls from the program. 997 for idx := len(p.Calls) - 1; idx >= 0; idx-- { 998 includeCall := false 999 var newResources []*ResultArg 1000 ForeachArg(p.Calls[idx], func(arg Arg, _ *ArgCtx) { 1001 if a, ok := arg.(*ResultArg); ok { 1002 if a.Res != nil && !relatedRes[a.Res] { 1003 newResources = append(newResources, a.Res) 1004 } 1005 if relatedRes[a] || relatedRes[a.Res] { 1006 includeCall = true 1007 } 1008 } 1009 }) 1010 if !includeCall { 1011 p.RemoveCall(idx) 1012 } else { 1013 for _, res := range newResources { 1014 relatedRes[res] = true 1015 } 1016 } 1017 } 1018 1019 // Selects a biased random length of the returned calls (more calls could offer more 1020 // interesting programs). The values returned (n = len(calls): n, n-1, ..., 2. 1021 biasedLen := 2 + r.biasedRand(len(calls)-1, 10) 1022 1023 // Removes the references that are not used anymore. 1024 for i := biasedLen; i < len(calls); i++ { 1025 p.RemoveCall(i) 1026 } 1027 1028 return MakeResultArg(t, dir, resource, 0), p.Calls 1029 } 1030 1031 func getCompatibleResources(p *Prog, resourceType string, r *randGen) (resources []*ResultArg) { 1032 for _, c := range p.Calls { 1033 ForeachArg(c, func(arg Arg, _ *ArgCtx) { 1034 // Collect only initialized resources (the ones that are already used in other calls). 1035 a, ok := arg.(*ResultArg) 1036 if !ok || len(a.uses) == 0 || a.Dir() != DirOut { 1037 return 1038 } 1039 if !r.target.isCompatibleResource(resourceType, a.Type().Name()) { 1040 return 1041 } 1042 resources = append(resources, a) 1043 }) 1044 } 1045 return resources 1046 }