github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/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  type (
     8  	elemType uint64
     9  	prioType int8
    10  )
    11  
    12  // Signal was hard to refactor when we enabled recvcheck.
    13  type Signal map[elemType]prioType // nolint: recvcheck
    14  
    15  func (s Signal) Len() int {
    16  	return len(s)
    17  }
    18  
    19  func (s Signal) Empty() bool {
    20  	return len(s) == 0
    21  }
    22  
    23  func (s Signal) Copy() Signal {
    24  	c := make(Signal, len(s))
    25  	for e, p := range s {
    26  		c[e] = p
    27  	}
    28  	return c
    29  }
    30  
    31  func FromRaw(raw []uint64, prio uint8) Signal {
    32  	if len(raw) == 0 {
    33  		return nil
    34  	}
    35  	s := make(Signal, len(raw))
    36  	for _, e := range raw {
    37  		s[elemType(e)] = prioType(prio)
    38  	}
    39  	return s
    40  }
    41  
    42  func (s Signal) DiffRaw(raw []uint64, prio uint8) Signal {
    43  	var res Signal
    44  	for _, e := range raw {
    45  		if p, ok := s[elemType(e)]; ok && p >= prioType(prio) {
    46  			continue
    47  		}
    48  		if res == nil {
    49  			res = make(Signal)
    50  		}
    51  		res[elemType(e)] = prioType(prio)
    52  	}
    53  	return res
    54  }
    55  
    56  func (s Signal) IntersectsWith(other Signal) bool {
    57  	for e, p := range s {
    58  		if p1, ok := other[e]; ok && p1 >= p {
    59  			return true
    60  		}
    61  	}
    62  	return false
    63  }
    64  
    65  func (s Signal) Intersection(s1 Signal) Signal {
    66  	if s1.Empty() {
    67  		return nil
    68  	}
    69  	res := make(Signal, len(s))
    70  	for e, p := range s {
    71  		if p1, ok := s1[e]; ok && p1 >= p {
    72  			res[e] = p
    73  		}
    74  	}
    75  	return res
    76  }
    77  
    78  func (s *Signal) Merge(s1 Signal) {
    79  	if s1.Empty() {
    80  		return
    81  	}
    82  	s0 := *s
    83  	if s0 == nil {
    84  		s0 = make(Signal, len(s1))
    85  		*s = s0
    86  	}
    87  	for e, p1 := range s1 {
    88  		if p, ok := s0[e]; !ok || p < p1 {
    89  			s0[e] = p1
    90  		}
    91  	}
    92  }
    93  
    94  func (s Signal) ToRaw() []uint64 {
    95  	var raw []uint64
    96  	for e := range s {
    97  		raw = append(raw, uint64(e))
    98  	}
    99  	return raw
   100  }
   101  
   102  type Context struct {
   103  	Signal  Signal
   104  	Context interface{}
   105  }
   106  
   107  func Minimize(corpus []Context) []interface{} {
   108  	type ContextPrio struct {
   109  		prio prioType
   110  		idx  int
   111  	}
   112  	covered := make(map[elemType]ContextPrio)
   113  	for i, inp := range corpus {
   114  		for e, p := range inp.Signal {
   115  			if prev, ok := covered[e]; !ok || p > prev.prio {
   116  				covered[e] = ContextPrio{
   117  					prio: p,
   118  					idx:  i,
   119  				}
   120  			}
   121  		}
   122  	}
   123  	indices := make(map[int]struct{}, len(corpus))
   124  	for _, cp := range covered {
   125  		indices[cp.idx] = struct{}{}
   126  	}
   127  	result := make([]interface{}, 0, len(indices))
   128  	for idx := range indices {
   129  		result = append(result, corpus[idx].Context)
   130  	}
   131  	return result
   132  }