github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/prog/hints_test.go (about) 1 // Copyright 2017 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/hex" 8 "fmt" 9 "math/rand" 10 "reflect" 11 "sort" 12 "testing" 13 14 "github.com/google/go-cmp/cmp" 15 "github.com/google/syzkaller/pkg/image" 16 "github.com/stretchr/testify/assert" 17 ) 18 19 type ConstArgTest struct { 20 name string 21 in uint64 22 size uint64 23 bitsize uint64 24 comps CompMap 25 res []uint64 26 } 27 28 type DataArgTest struct { 29 name string 30 in string 31 comps CompMap 32 res map[string]bool 33 } 34 35 // Tests checkConstArg(). Is not intended to check correctness of any mutations. 36 // Mutation are checked in their own tests. 37 func TestHintsCheckConstArg(t *testing.T) { 38 target := initTargetTest(t, "test", "64") 39 var tests = []ConstArgTest{ 40 { 41 name: "one-replacer-test", 42 in: 0xdeadbeef, 43 size: 4, 44 comps: CompMap{0xdeadbeef: compSet(0xdeadbeef, 0xcafebabe)}, 45 res: []uint64{0xcafebabe}, 46 }, 47 // Test for cases when there's multiple comparisons (op1, op2), (op1, op3), ... 48 // Checks that for every such operand a program is generated. 49 { 50 name: "multiple-replacers-test", 51 in: 0xabcd, 52 size: 2, 53 comps: CompMap{0xabcd: compSet(0x2, 0x3)}, 54 res: []uint64{0x2, 0x3}, 55 }, 56 // Checks that special ints are not used. 57 { 58 name: "special-ints-test", 59 in: 0xabcd, 60 size: 2, 61 comps: CompMap{0xabcd: compSet(0x1, 0x2)}, 62 res: []uint64{0x2}, 63 }, 64 65 // The following tests check the size limits for each replacer and for the initial value 66 // of the argument. The checks are made for positive and negative values and also for bitfields. 67 { 68 name: "int8-invalid-positive-value", 69 in: 0x1234, 70 size: 1, 71 comps: CompMap{ 72 // void test8(i8 el) { 73 // i16 w = (i16) el 74 // if (w == 0x88) {...} 75 // i16 other = 0xfffe 76 // if (w == other) 77 // }; test8(i8(0x1234)); 78 0x34: compSet(0x88, 0x1122, 0xfffffffffffffffe, 0xffffffffffffff0a), 79 // This following args should be iggnored. 80 0x1234: compSet(0xa1), 81 0xffffffffffffff34: compSet(0xaa), 82 }, 83 res: []uint64{0x88, 0xfe}, 84 }, 85 { 86 name: "int8-invalid-negative-value", 87 in: 0x12ab, 88 size: 1, 89 comps: CompMap{ 90 0xab: compSet(0xab, 0xac, 0xabcd), 91 0xffffffffffffffab: compSet(0x11, 0x22, 0xffffffffffffff34), 92 }, 93 res: []uint64{0x11, 0x22, 0xac}, 94 }, 95 { 96 name: "int16-valid-value-bitsize-12", 97 in: 0x3ab, 98 size: 2, 99 bitsize: 12, 100 comps: CompMap{ 101 0x3ab: compSet(0x11, 0x1234, 0xfffffffffffffffe), 102 0x13ab: compSet(0xab, 0xffa), 103 0xffffffffffffffab: compSet(0xfffffffffffffff1), 104 0xfffffffffffff3ab: compSet(0xff1, 0x12), 105 }, 106 res: []uint64{0x11, 0x3f1, 0xffe}, 107 }, 108 { 109 name: "int16-invalid-value-bitsize-12", 110 in: 0x71ab, 111 size: 2, 112 bitsize: 12, 113 comps: CompMap{ 114 0x1ab: compSet(0x11, 0x1234, 0xfffffffffffffffe), 115 }, 116 res: []uint64{0x11, 0xffe}, 117 }, 118 { 119 name: "int16-negative-valid-value-bitsize-12", 120 in: 0x8ab, 121 size: 2, 122 bitsize: 12, 123 comps: CompMap{ 124 0x8ab: compSet(0x11), 125 0xffffffffffffffab: compSet(0x12, 0xffffffffffffff0a), 126 0xfffffffffffff8ab: compSet(0x13, 0xffffffffffffff00), 127 }, 128 res: []uint64{0x11, 0x13, 0x80a, 0x812, 0xf00}, 129 }, 130 { 131 name: "int16-negative-invalid-value-bitsize-12", 132 in: 0x88ab, 133 size: 2, 134 bitsize: 12, 135 comps: CompMap{ 136 0x8ab: compSet(0x13), 137 0xfffffffffffff8ab: compSet(0x11, 0xffffffffffffff11), 138 }, 139 res: []uint64{0x11, 0x13, 0xf11}, 140 }, 141 { 142 name: "int32-invalid-value", 143 in: 0xaabaddcafe, 144 size: 4, 145 comps: CompMap{0xbaddcafe: compSet(0xab, 0xabcd, 0xbaddcafe, 146 0xdeadbeef, 0xaabbccddeeff1122)}, 147 res: []uint64{0xab, 0xabcd, 0xdeadbeef}, 148 }, 149 { 150 name: "int64-valid-value", 151 in: 0xdeadc0debaddcafe, 152 size: 8, 153 comps: CompMap{0xdeadc0debaddcafe: compSet(0xab, 0xabcd, 0xdeadbeef, 0xdeadbeefdeadbeef)}, 154 res: []uint64{0xab, 0xabcd, 0xdeadbeef, 0xdeadbeefdeadbeef}, 155 }, 156 } 157 meta := target.SyscallMap["test$hint_int"] 158 structType := meta.Args[0].Type.(*PtrType).Elem.(*StructType) 159 types := make(map[string]Type) 160 for _, field := range structType.Fields { 161 types[field.Name] = field.Type 162 } 163 for _, test := range tests { 164 t.Run(fmt.Sprintf("%v", test.name), func(t *testing.T) { 165 var res []uint64 166 typ := types[fmt.Sprintf("int%v_%v", test.size, test.bitsize)] 167 constArg := MakeConstArg(typ, DirIn, test.in) 168 checkConstArg(constArg, test.comps, func() bool { 169 res = append(res, constArg.Val) 170 return true 171 }) 172 if !reflect.DeepEqual(res, test.res) { 173 t.Fatalf("\ngot : %v\nwant: %v", res, test.res) 174 } 175 }) 176 } 177 } 178 179 // Tests checkDataArg(). Is not intended to check correctness of any mutations. 180 // Mutation are checked in their own tests. 181 func TestHintsCheckDataArg(t *testing.T) { 182 target := initTargetTest(t, "test", "64") 183 // All inputs are in Little-Endian. 184 var tests = []DataArgTest{ 185 { 186 "one-replacer-test", 187 "\xef\xbe\xad\xde", 188 CompMap{ 189 0xdeadbeef: compSet(0xcafebabe, 0xdeadbeef), 190 0xbeef: compSet(0xbeef), 191 0xef: compSet(0xef), 192 }, 193 map[string]bool{ 194 "\xbe\xba\xfe\xca": true, 195 }, 196 }, 197 // Test for cases when there's multiple comparisons (op1, op2), (op1, op3), ... 198 // Checks that for every such operand a program is generated. 199 { 200 "multiple-replacers-test", 201 "\xcd\xab", 202 CompMap{0xabcd: compSet(0x2, 0x3)}, 203 map[string]bool{ 204 "\x02\x00": true, "\x03\x00": true, 205 }, 206 }, 207 // Checks that special ints are not used. 208 { 209 "special-ints-test", 210 "\xcd\xab", 211 CompMap{0xabcd: compSet(0x1, 0x2)}, 212 map[string]bool{ 213 "\x02\x00": true, 214 }, 215 }, 216 // Checks that ints of various sizes are extracted. 217 { 218 "different-sizes-test", 219 "\xef\xcd\xab\x90\x78\x56\x34\x12", 220 CompMap{ 221 0xef: compSet(0x11), 222 0xcdef: compSet(0x2222), 223 0x90abcdef: compSet(0x33333333), 224 0x1234567890abcdef: compSet(0x4444444444444444), 225 }, 226 map[string]bool{ 227 "\x11\xcd\xab\x90\x78\x56\x34\x12": true, 228 "\x22\x22\xab\x90\x78\x56\x34\x12": true, 229 "\x33\x33\x33\x33\x78\x56\x34\x12": true, 230 "\x44\x44\x44\x44\x44\x44\x44\x44": true, 231 }, 232 }, 233 // Checks that values with different offsets are extracted. 234 { 235 "different-offsets-test", 236 "\xab\xab\xab\xab\xab\xab\xab\xab\xab", 237 CompMap{ 238 0xab: compSet(0x11), 239 0xabab: compSet(0x2222), 240 0xabababab: compSet(0x33333333), 241 0xabababababababab: compSet(0x4444444444444444), 242 }, 243 map[string]bool{ 244 "\x11\xab\xab\xab\xab\xab\xab\xab\xab": true, 245 "\xab\x11\xab\xab\xab\xab\xab\xab\xab": true, 246 "\xab\xab\x11\xab\xab\xab\xab\xab\xab": true, 247 "\xab\xab\xab\x11\xab\xab\xab\xab\xab": true, 248 "\xab\xab\xab\xab\x11\xab\xab\xab\xab": true, 249 "\xab\xab\xab\xab\xab\x11\xab\xab\xab": true, 250 "\xab\xab\xab\xab\xab\xab\x11\xab\xab": true, 251 "\xab\xab\xab\xab\xab\xab\xab\x11\xab": true, 252 "\xab\xab\xab\xab\xab\xab\xab\xab\x11": true, 253 "\x22\x22\xab\xab\xab\xab\xab\xab\xab": true, 254 "\xab\x22\x22\xab\xab\xab\xab\xab\xab": true, 255 "\xab\xab\x22\x22\xab\xab\xab\xab\xab": true, 256 "\xab\xab\xab\x22\x22\xab\xab\xab\xab": true, 257 "\xab\xab\xab\xab\x22\x22\xab\xab\xab": true, 258 "\xab\xab\xab\xab\xab\x22\x22\xab\xab": true, 259 "\xab\xab\xab\xab\xab\xab\x22\x22\xab": true, 260 "\xab\xab\xab\xab\xab\xab\xab\x22\x22": true, 261 "\x33\x33\x33\x33\xab\xab\xab\xab\xab": true, 262 "\xab\x33\x33\x33\x33\xab\xab\xab\xab": true, 263 "\xab\xab\x33\x33\x33\x33\xab\xab\xab": true, 264 "\xab\xab\xab\x33\x33\x33\x33\xab\xab": true, 265 "\xab\xab\xab\xab\x33\x33\x33\x33\xab": true, 266 "\xab\xab\xab\xab\xab\x33\x33\x33\x33": true, 267 "\x44\x44\x44\x44\x44\x44\x44\x44\xab": true, 268 "\xab\x44\x44\x44\x44\x44\x44\x44\x44": true, 269 }, 270 }, 271 { 272 "replace-in-the-middle-of-a-larger-blob", 273 "\xef\xcd\xab\x90\x78\x56\x34\x12", 274 CompMap{0xffffffffffff90ab: compSet(0xffffffffffffaabb)}, 275 map[string]bool{ 276 "\xef\xcd\xbb\xaa\x78\x56\x34\x12": true, 277 }, 278 }, 279 { 280 281 "big-endian-replace", 282 "\xef\xcd\xab\x90\x78\x56\x34\x12", 283 CompMap{ 284 // 0xff07 is reversed special int. 285 0xefcd: compSet(0xaabb, 0xff07), 286 0x3412: compSet(0xaabb, 0xff07), 287 0x9078: compSet(0xaabb, 0x11223344, 0xff07), 288 0x90785634: compSet(0xaabbccdd, 0x11223344), 289 0xefcdab9078563412: compSet(0x1122334455667788), 290 }, 291 map[string]bool{ 292 "\xaa\xbb\xab\x90\x78\x56\x34\x12": true, 293 "\xef\xcd\xab\x90\x78\x56\xaa\xbb": true, 294 "\xef\xcd\xab\xaa\xbb\x56\x34\x12": true, 295 "\xef\xcd\xab\xaa\xbb\xcc\xdd\x12": true, 296 "\xef\xcd\xab\x11\x22\x33\x44\x12": true, 297 "\x11\x22\x33\x44\x55\x66\x77\x88": true, 298 }, 299 }, 300 } 301 meta := target.SyscallMap["test$hint_data"] 302 typ := meta.Args[0].Type.(*PtrType).Elem // array[int8] 303 for _, test := range tests { 304 t.Run(fmt.Sprintf("%v", test.name), func(t *testing.T) { 305 res := make(map[string]bool) 306 dataArg := MakeDataArg(typ, DirIn, []byte(test.in)) 307 checkDataArg(dataArg, test.comps, func() bool { 308 res[string(dataArg.Data())] = true 309 return true 310 }) 311 if !reflect.DeepEqual(res, test.res) { 312 s := "\ngot: [" 313 for x := range res { 314 s += fmt.Sprintf("0x%x, ", x) 315 } 316 s += "]\nwant: [" 317 for x := range test.res { 318 s += fmt.Sprintf("0x%x, ", x) 319 } 320 s += "]\n" 321 t.Fatalf(s) 322 } 323 }) 324 } 325 } 326 327 func TestHintsCompressedImage(t *testing.T) { 328 target := initTargetTest(t, "test", "64") 329 type Test struct { 330 input string 331 comps CompMap 332 output []string 333 } 334 var tests = []Test{ 335 { 336 "\x00\x11\x22\x33\x44\x55\x66\x77", 337 CompMap{ 338 // 1/2-bytes must not be replaced. 339 0x00: compSet(0xaa), 340 0x11: compSet(0xaa), 341 0x1122: compSet(0xaabb), 342 0x4455: compSet(0xaabb), 343 // Aligned 4-byte values are replaced in both little/big endian. 344 0x00112233: compSet(0xaabbccdd), 345 0x33221100: compSet(0xaabbccdd), 346 0x44556677: compSet(0xaabbccdd), 347 0x77665544: compSet(0xaabbccdd), 348 // Same for 8-byte values. 349 0x0011223344556677: compSet(0xaabbccddeeff9988), 350 0x7766554433221100: compSet(0xaabbccddeeff9988), 351 // Unaligned 4-bytes are not replaced. 352 0x11223344: compSet(0xaabbccdd), 353 0x22334455: compSet(0xaabbccdd), 354 }, 355 []string{ 356 // Mutants for 4-byte values. 357 "\xaa\xbb\xcc\xdd\x44\x55\x66\x77", 358 "\xdd\xcc\xbb\xaa\x44\x55\x66\x77", 359 "\x00\x11\x22\x33\xaa\xbb\xcc\xdd", 360 "\x00\x11\x22\x33\xdd\xcc\xbb\xaa", 361 // Mutants for 8-byte values. 362 "\xaa\xbb\xcc\xdd\xee\xff\x99\x88", 363 "\x88\x99\xff\xee\xdd\xcc\xbb\xaa", 364 }, 365 }, 366 { 367 "\x00\x11\x22\x33\x44\x55\x66\x77", 368 CompMap{ 369 // Special values are used as replacers. 370 0x00112233: compSet(0, 0xffffffff), 371 }, 372 []string{ 373 // Mutants for 4-byte values. 374 "\x00\x00\x00\x00\x44\x55\x66\x77", 375 "\xff\xff\xff\xff\x44\x55\x66\x77", 376 }, 377 }, 378 { 379 // All 0s and 0xff must not be replaced. 380 "\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00", 381 CompMap{ 382 0: compSet(0xaabbccdd), 383 0xffffffffffffffff: compSet(0xaabbccddaabbccdd), 384 }, 385 nil, 386 }, 387 } 388 typ := target.SyscallMap["serialize3"].Args[0].Type.(*PtrType).Elem.(*BufferType) 389 if typ.Kind != BufferCompressed { 390 panic("wrong arg type") 391 } 392 for i, test := range tests { 393 t.Run(fmt.Sprintf("%v", i), func(t *testing.T) { 394 var res []string 395 arg := MakeDataArg(typ, DirIn, image.Compress([]byte(test.input))) 396 generateHints(test.comps, arg, func() bool { 397 res = append(res, string(arg.Data())) 398 return true 399 }) 400 for i, compressed := range res { 401 data, dtor := image.MustDecompress([]byte(compressed)) 402 res[i] = string(data) 403 dtor() 404 } 405 sort.Strings(res) 406 sort.Strings(test.output) 407 if diff := cmp.Diff(test.output, res); diff != "" { 408 t.Fatalf("got wrong mutants: %v", diff) 409 } 410 data, dtor := image.MustDecompress(arg.Data()) 411 defer dtor() 412 if diff := cmp.Diff(test.input, string(data)); diff != "" { 413 t.Fatalf("argument got changed afterwards: %v", diff) 414 } 415 }) 416 } 417 } 418 419 func TestHintsShrinkExpand(t *testing.T) { 420 t.Parallel() 421 // Naming conventions: 422 // b - byte variable (i8 or u8) 423 // w - word variable (i16 or u16) 424 // dw - dword variable (i32 or u32) 425 // qw - qword variable (i64 or u64) 426 // ----------------------------------------------------------------- 427 // Shrink tests: 428 var tests = []ConstArgTest{ 429 { 430 // Models the following code: 431 // void f(u16 w) { 432 // u8 b = (u8) w; 433 // if (b == 0xab) {...} 434 // if (w == 0xcdcd) {...} 435 // }; f(0x1234); 436 name: "shrink-16-test", 437 in: 0x1234, 438 comps: CompMap{ 439 0x34: compSet(0xab), 440 0x1234: compSet(0xcdcd), 441 }, 442 res: []uint64{0x12ab, 0xcdcd}, 443 }, 444 { 445 // Models the following code: 446 // void f(u32 dw) { 447 // u8 b = (u8) dw 448 // i16 w = (i16) dw 449 // if (b == 0xab) {...} 450 // if (w == 0xcdcd) {...} 451 // if (dw == 0xefefefef) {...} 452 // }; f(0x12345678); 453 name: "shrink-32-test", 454 in: 0x12345678, 455 comps: CompMap{ 456 0x78: compSet(0xab), 457 0x5678: compSet(0xcdcd), 458 0x12345678: compSet(0xefefefef), 459 }, 460 res: []uint64{0x123456ab, 0x1234cdcd, 0xefefefef}, 461 }, 462 { 463 // Models the following code: 464 // void f(u64 qw) { 465 // u8 b = (u8) qw 466 // u16 w = (u16) qw 467 // u32 dw = (u32) qw 468 // if (b == 0xab) {...} 469 // if (w == 0xcdcd) {...} 470 // if (dw == 0xefefefef) {...} 471 // if (qw == 0x0101010101010101) {...} 472 // }; f(0x1234567890abcdef); 473 name: "shrink-64-test", 474 in: 0x1234567890abcdef, 475 comps: CompMap{ 476 0xef: compSet(0xab, 0xef), 477 0xcdef: compSet(0xcdcd), 478 0x90abcdef: compSet(0xefefefef), 479 0x1234567890abcdef: compSet(0x0101010101010101), 480 }, 481 res: []uint64{ 482 0x0101010101010101, 483 0x1234567890abcdab, 484 0x1234567890abcdcd, 485 0x12345678efefefef, 486 }, 487 }, 488 { 489 // Models the following code: 490 // void f(i16 w) { 491 // i8 b = (i8) w; 492 // i16 other = 0xabab; 493 // if (b == other) {...} 494 // }; f(0x1234); 495 // In such code the comparison will never be true, so we don't 496 // generate a hint for it. 497 name: "shrink-with-a-wider-replacer-test1", 498 in: 0x1234, 499 comps: CompMap{0x34: compSet(0x1bab)}, 500 res: nil, 501 }, 502 { 503 // Models the following code: 504 // void f(i16 w) { 505 // i8 b = (i8) w; 506 // i16 other = 0xfffd; 507 // if (b == other) {...} 508 // }; f(0x1234); 509 // In such code b will be sign extended to 0xff34 and, if we replace 510 // the lower byte, then the if statement will be true. 511 // Note that executor sign extends all the comparison operands to 512 // int64, so we model this accordingly. 513 name: "shrink-with-a-wider-replacer-test2", 514 in: 0x1234, 515 comps: CompMap{0x34: compSet(0xfffffffffffffffd)}, 516 res: []uint64{0x12fd}, 517 }, 518 // ----------------------------------------------------------------- 519 // Extend tests: 520 // Note that executor sign extends all the comparison operands to int64, 521 // so we model this accordingly. 522 { 523 // Models the following code: 524 // void f(i8 b) { 525 // i64 qw = (i64) b; 526 // if (qw == -2) {...}; 527 // }; f(-1); 528 name: "extend-8-test", 529 in: 0xff, 530 comps: CompMap{0xffffffffffffffff: compSet(0xfffffffffffffffe)}, 531 res: []uint64{0xfe}, 532 }, 533 { 534 // Models the following code: 535 // void f(i16 w) { 536 // i64 qw = (i64) w; 537 // if (qw == -2) {...}; 538 // }; f(-1); 539 name: "extend-16-test", 540 in: 0xffff, 541 comps: CompMap{0xffffffffffffffff: compSet(0xfffffffffffffffe)}, 542 res: []uint64{0xfffe}, 543 }, 544 { 545 // Models the following code: 546 // void f(i32 dw) { 547 // i64 qw = (i32) dw; 548 // if (qw == -2) {...}; 549 // }; f(-1); 550 name: "extend-32-test", 551 in: 0xffffffff, 552 comps: CompMap{0xffffffffffffffff: compSet(0xfffffffffffffffe)}, 553 res: []uint64{0xfffffffe}, 554 }, 555 { 556 // Models the following code: 557 // void f(i8 b) { 558 // i16 w = (i16) b; 559 // if (w == (i16) 0xfeff) {...}; 560 // }; f(-1); 561 // There's no value for b that will make the comparison true, 562 // so we don't generate hints. 563 name: "extend-with-a-wider-replacer-test", 564 in: 0xff, 565 comps: CompMap{0xffffffffffffffff: compSet(0xfffffffffffffeff)}, 566 res: nil, 567 }, 568 } 569 for _, test := range tests { 570 t.Run(fmt.Sprintf("%v", test.name), func(t *testing.T) { 571 res := shrinkExpand(test.in, test.comps, 64, false) 572 if !reflect.DeepEqual(res, test.res) { 573 t.Fatalf("\ngot : %v\nwant: %v", res, test.res) 574 } 575 }) 576 } 577 } 578 579 func TestHintsRandom(t *testing.T) { 580 target, rs, iters := initTest(t) 581 ct := target.DefaultChoiceTable() 582 iters /= 10 // the test takes long 583 r := newRand(target, rs) 584 for i := 0; i < iters; i++ { 585 p := target.Generate(rs, 5, ct) 586 for i, c := range p.Calls { 587 vals := extractValues(c) 588 for j := 0; j < 5; j++ { 589 vals[r.randInt64()] = true 590 } 591 comps := make(CompMap) 592 for v := range vals { 593 comps.AddComp(v, r.randInt64()) 594 } 595 p.MutateWithHints(i, comps, func(p1 *Prog) bool { return true }) 596 } 597 } 598 } 599 600 func extractValues(c *Call) map[uint64]bool { 601 vals := make(map[uint64]bool) 602 ForeachArg(c, func(arg Arg, _ *ArgCtx) { 603 if arg.Dir() == DirOut { 604 return 605 } 606 switch a := arg.(type) { 607 case *ConstArg: 608 vals[a.Val] = true 609 case *DataArg: 610 data := a.Data() 611 for i := range data { 612 vals[uint64(data[i])] = true 613 if i < len(data)-1 { 614 v := uint64(data[i]) | uint64(data[i+1])<<8 615 vals[v] = true 616 } 617 if i < len(data)-3 { 618 v := uint64(data[i]) | uint64(data[i+1])<<8 | 619 uint64(data[i+2])<<16 | uint64(data[i+3])<<24 620 vals[v] = true 621 } 622 if i < len(data)-7 { 623 v := uint64(data[i]) | uint64(data[i+1])<<8 | 624 uint64(data[i+2])<<16 | uint64(data[i+3])<<24 | 625 uint64(data[i+4])<<32 | uint64(data[i+5])<<40 | 626 uint64(data[i+6])<<48 | uint64(data[i+7])<<56 627 vals[v] = true 628 } 629 } 630 } 631 }) 632 delete(vals, 0) // replacing 0 can yield too many condidates 633 return vals 634 } 635 636 func TestHintsData(t *testing.T) { 637 target := initTargetTest(t, "test", "64") 638 type Test struct { 639 in string 640 comps CompMap 641 out []string 642 } 643 tests := []Test{ 644 { 645 in: "0809101112131415", 646 comps: CompMap{0x12111009: compSet(0x10)}, 647 out: []string{"0810000000131415"}, 648 }, 649 } 650 for _, test := range tests { 651 p, err := target.Deserialize([]byte(fmt.Sprintf("test$hint_data(&AUTO=\"%v\")", test.in)), Strict) 652 if err != nil { 653 t.Fatal(err) 654 } 655 var got []string 656 p.MutateWithHints(0, test.comps, func(newP *Prog) bool { 657 got = append(got, hex.EncodeToString( 658 newP.Calls[0].Args[0].(*PointerArg).Res.(*DataArg).Data())) 659 return true 660 }) 661 sort.Strings(test.out) 662 sort.Strings(got) 663 if !reflect.DeepEqual(got, test.out) { 664 t.Fatalf("comps: %v\ninput: %v\ngot : %+v\nwant: %+v", 665 test.comps, test.in, got, test.out) 666 } 667 } 668 } 669 670 func TestInplaceIntersect(t *testing.T) { 671 m1 := CompMap{ 672 0xdead: compSet(0x1, 0x2), 673 0xbeef: compSet(0x3, 0x4), 674 0xffff: compSet(0x5), 675 } 676 m2 := CompMap{ 677 0xdead: compSet(0x2), 678 0xbeef: compSet(0x3, 0x6), 679 0xeeee: compSet(0x6), 680 } 681 m1.InplaceIntersect(m2) 682 assert.Equal(t, CompMap{ 683 0xdead: compSet(0x2), 684 0xbeef: compSet(0x3), 685 }, m1) 686 } 687 688 func BenchmarkHints(b *testing.B) { 689 target, cleanup := initBench(b) 690 defer cleanup() 691 rs := rand.NewSource(0) 692 r := newRand(target, rs) 693 ct := target.DefaultChoiceTable() 694 p := target.Generate(rs, 30, ct) 695 comps := make([]CompMap, len(p.Calls)) 696 for i, c := range p.Calls { 697 vals := extractValues(c) 698 for j := 0; j < 5; j++ { 699 vals[r.randInt64()] = true 700 } 701 comps[i] = make(CompMap) 702 for v := range vals { 703 comps[i].AddComp(v, r.randInt64()) 704 } 705 } 706 b.RunParallel(func(pb *testing.PB) { 707 for pb.Next() { 708 for i := range p.Calls { 709 p.MutateWithHints(i, comps[i], func(p1 *Prog) bool { return true }) 710 } 711 } 712 }) 713 } 714 715 func compSet(vals ...uint64) map[uint64]bool { 716 m := make(map[uint64]bool) 717 for _, v := range vals { 718 m[v] = true 719 } 720 return m 721 }