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  }