github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/prog/heatmap_test.go (about) 1 // Copyright 2022 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 "math/rand" 8 "sort" 9 "testing" 10 11 "github.com/google/syzkaller/pkg/image" 12 "github.com/google/syzkaller/pkg/testutil" 13 ) 14 15 func TestGenericHeatmap(t *testing.T) { 16 t.Parallel() 17 // A test case is some data with the regions the heatmap is permitted to choose. 18 testData := []struct { 19 data []byte 20 regions []region 21 }{ 22 { 23 // Normal usage test. 24 []byte( 25 "4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh" + 26 "4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh" + 27 "4eHh4eHh4eHh4eHh4Q5GTbHh4eHh4eHh4eHh4eHhcOHh4eHh4eHh4eHh4eHh4eHh4eHh4eEfNuHh4XPh" + 28 "4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHjd+GRzcLh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh" + 29 "4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4dpiSwpoReHh4eHh4eHh4eHh4eHh4eHh4eHh" + 30 "4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4bGfM+Hh4eHh4eHh4eHh4eHh4eHh4eHh4eHh" + 31 "4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh" + 32 "4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh" + 33 "4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh" + 34 "mpNKOZnS4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh" + 35 "4eHh4eHh4eHh4eHh4eHh4Q=="), 36 []region{{128, 384}, {512, 576}}, 37 }, 38 { 39 // Test all constant bytes, i.e. falling back to uniform selection. 40 []byte( 41 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + 42 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + 43 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + 44 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + 45 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + 46 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"), 47 []region{{0, 324}}, // Anywhere in the data. 48 }, 49 } 50 51 const tries = 10 52 iters := testutil.IterCount() / tries 53 54 r := rand.New(testutil.RandSource(t)) 55 for _, test := range testData { 56 data, err := image.DecodeB64(test.data) 57 if err != nil { 58 t.Fatalf("bad decode: %v", err) 59 } 60 for i := 0; i < iters; i++ { 61 hm := MakeGenericHeatmap(data, r).(*GenericHeatmap) 62 63 for j := 0; j < tries; j++ { 64 index := hm.ChooseLocation() 65 if !checkIndex(index, len(data), test.regions) { 66 hm.debugPrint(t, data, test.regions) 67 t.Fatalf("selected index %d does not fall in a region", index) 68 } 69 } 70 } 71 } 72 } 73 74 // Check an index is within some regions. 75 func checkIndex(index, maxIndex int, regions []region) bool { 76 if index < 0 || index >= maxIndex { 77 return false 78 } 79 80 for _, region := range regions { 81 if region.start <= index && index < region.end { 82 return true 83 } 84 } 85 return false 86 } 87 88 type region struct { 89 start int 90 end int 91 } 92 93 func (hm *GenericHeatmap) debugPrint(t *testing.T, data []byte, regions []region) { 94 // Print data. 95 t.Logf("data: len = %d", len(data)) 96 for j := 0; j < len(data); j += granularity { 97 end := min(j+granularity, len(data)) 98 t.Logf("%8d: %x", j*granularity, data[j:end]) 99 } 100 t.Log("\n") 101 102 // Print selected regions in data. 103 sort.Slice(regions, func(i, j int) bool { 104 return regions[i].start < regions[j].start 105 }) 106 for j, region := range regions { 107 t.Logf("region %4d: %8v - %8v", j, region.start, region.end) 108 } 109 t.Log("\n") 110 111 // Print heatmap. 112 t.Logf("generic heatmap (total segment length %d)", hm.length) 113 for j, seg := range hm.segments { 114 t.Logf("segment %4d: %8v - %8v", j, seg.offset, seg.offset+seg.length) 115 } 116 t.Log("\n\n\n") 117 }