github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/pkg/signal/signal.go (about) 1 // Copyright 2018 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 signal provides types for working with feedback signal. 5 package signal 6 7 import "math/rand" 8 9 type ( 10 elemType uint32 11 prioType int8 12 ) 13 14 type Signal map[elemType]prioType 15 16 func (s Signal) Len() int { 17 return len(s) 18 } 19 20 func (s Signal) Empty() bool { 21 return len(s) == 0 22 } 23 24 func (s Signal) Copy() Signal { 25 c := make(Signal, len(s)) 26 for e, p := range s { 27 c[e] = p 28 } 29 return c 30 } 31 32 func (s *Signal) Split(n int) Signal { 33 if n >= s.Len() { 34 ret := *s 35 *s = nil 36 return ret 37 } 38 c := make(Signal, n) 39 for e, p := range *s { 40 delete(*s, e) 41 c[e] = p 42 n-- 43 if n == 0 { 44 break 45 } 46 } 47 if len(*s) == 0 { 48 *s = nil 49 } 50 return c 51 } 52 53 func FromRaw(raw []uint32, prio uint8) Signal { 54 if len(raw) == 0 { 55 return nil 56 } 57 s := make(Signal, len(raw)) 58 for _, e := range raw { 59 s[elemType(e)] = prioType(prio) 60 } 61 return s 62 } 63 64 func (s Signal) Diff(s1 Signal) Signal { 65 if s1.Empty() { 66 return nil 67 } 68 var res Signal 69 for e, p1 := range s1 { 70 if p, ok := s[e]; ok && p >= p1 { 71 continue 72 } 73 if res == nil { 74 res = make(Signal) 75 } 76 res[e] = p1 77 } 78 return res 79 } 80 81 func (s Signal) DiffRaw(raw []uint32, prio uint8) Signal { 82 var res Signal 83 for _, e := range raw { 84 if p, ok := s[elemType(e)]; ok && p >= prioType(prio) { 85 continue 86 } 87 if res == nil { 88 res = make(Signal) 89 } 90 res[elemType(e)] = prioType(prio) 91 } 92 return res 93 } 94 95 func (s Signal) IntersectsWith(other Signal) bool { 96 for e, p := range s { 97 if p1, ok := other[e]; ok && p1 >= p { 98 return true 99 } 100 } 101 return false 102 } 103 104 func (s Signal) Intersection(s1 Signal) Signal { 105 if s1.Empty() { 106 return nil 107 } 108 res := make(Signal, len(s)) 109 for e, p := range s { 110 if p1, ok := s1[e]; ok && p1 >= p { 111 res[e] = p 112 } 113 } 114 return res 115 } 116 117 func (s *Signal) Merge(s1 Signal) { 118 if s1.Empty() { 119 return 120 } 121 s0 := *s 122 if s0 == nil { 123 s0 = make(Signal, len(s1)) 124 *s = s0 125 } 126 for e, p1 := range s1 { 127 if p, ok := s0[e]; !ok || p < p1 { 128 s0[e] = p1 129 } 130 } 131 } 132 133 func (s *Signal) Subtract(s1 Signal) { 134 s0 := *s 135 if s0 == nil { 136 return 137 } 138 for e, p1 := range s1 { 139 if p, ok := s0[e]; ok && p == p1 { 140 delete(s0, e) 141 } 142 } 143 } 144 145 func (s Signal) RandomSubset(r *rand.Rand, size int) Signal { 146 if size > len(s) { 147 size = len(s) 148 } 149 keys := make([]elemType, 0, len(s)) 150 for e := range s { 151 keys = append(keys, e) 152 } 153 r.Shuffle(len(keys), func(i, j int) { keys[i], keys[j] = keys[j], keys[i] }) 154 155 ret := make(Signal, size) 156 for _, e := range keys[:size] { 157 ret[e] = s[e] 158 } 159 return ret 160 } 161 162 // FilterRaw returns a subset of original raw elements that either are not present in ignore, 163 // or coincides with the one in alwaysTake. 164 func FilterRaw(raw []uint32, ignore, alwaysTake Signal) []uint32 { 165 var ret []uint32 166 for _, e := range raw { 167 if _, ok := alwaysTake[elemType(e)]; ok { 168 ret = append(ret, e) 169 } else if _, ok := ignore[elemType(e)]; !ok { 170 ret = append(ret, e) 171 } 172 } 173 return ret 174 } 175 176 // DiffFromRaw returns a subset of the raw elements that is not present in Signal. 177 func (s Signal) DiffFromRaw(raw []uint32) []uint32 { 178 var ret []uint32 179 for _, e := range raw { 180 if _, ok := s[elemType(e)]; !ok { 181 ret = append(ret, e) 182 } 183 } 184 return ret 185 } 186 187 func (s Signal) ToRaw() []uint32 { 188 var raw []uint32 189 for e := range s { 190 raw = append(raw, uint32(e)) 191 } 192 return raw 193 } 194 195 type Context struct { 196 Signal Signal 197 Context interface{} 198 } 199 200 func Minimize(corpus []Context) []interface{} { 201 type ContextPrio struct { 202 prio prioType 203 idx int 204 } 205 covered := make(map[elemType]ContextPrio) 206 for i, inp := range corpus { 207 for e, p := range inp.Signal { 208 if prev, ok := covered[e]; !ok || p > prev.prio { 209 covered[e] = ContextPrio{ 210 prio: p, 211 idx: i, 212 } 213 } 214 } 215 } 216 indices := make(map[int]struct{}, len(corpus)) 217 for _, cp := range covered { 218 indices[cp.idx] = struct{}{} 219 } 220 result := make([]interface{}, 0, len(indices)) 221 for idx := range indices { 222 result = append(result, corpus[idx].Context) 223 } 224 return result 225 }