Source file src/internal/fuzz/coverage.go

     1  // Copyright 2021 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package fuzz
     6  
     7  import (
     8  	"fmt"
     9  	"math/bits"
    10  )
    11  
    12  // ResetCoverage sets all of the counters for each edge of the instrumented
    13  // source code to 0.
    14  func ResetCoverage() {
    15  	cov := coverage()
    16  	clear(cov)
    17  }
    18  
    19  // SnapshotCoverage copies the current counter values into coverageSnapshot,
    20  // preserving them for later inspection. SnapshotCoverage also rounds each
    21  // counter down to the nearest power of two. This lets the coordinator store
    22  // multiple values for each counter by OR'ing them together.
    23  func SnapshotCoverage() {
    24  	cov := coverage()
    25  	for i, b := range cov {
    26  		coverageSnapshot[i] = pow2Table[b]
    27  	}
    28  }
    29  
    30  // diffCoverage returns a set of bits set in snapshot but not in base.
    31  // If there are no new bits set, diffCoverage returns nil.
    32  func diffCoverage(base, snapshot []byte) []byte {
    33  	if len(base) != len(snapshot) {
    34  		panic(fmt.Sprintf("the number of coverage bits changed: before=%d, after=%d", len(base), len(snapshot)))
    35  	}
    36  	found := false
    37  	for i := range snapshot {
    38  		if snapshot[i]&^base[i] != 0 {
    39  			found = true
    40  			break
    41  		}
    42  	}
    43  	if !found {
    44  		return nil
    45  	}
    46  	diff := make([]byte, len(snapshot))
    47  	for i := range diff {
    48  		diff[i] = snapshot[i] &^ base[i]
    49  	}
    50  	return diff
    51  }
    52  
    53  // countNewCoverageBits returns the number of bits set in snapshot that are not
    54  // set in base.
    55  func countNewCoverageBits(base, snapshot []byte) int {
    56  	n := 0
    57  	for i := range snapshot {
    58  		n += bits.OnesCount8(snapshot[i] &^ base[i])
    59  	}
    60  	return n
    61  }
    62  
    63  // isCoverageSubset returns true if all the base coverage bits are set in
    64  // snapshot.
    65  func isCoverageSubset(base, snapshot []byte) bool {
    66  	for i, v := range base {
    67  		if v&snapshot[i] != v {
    68  			return false
    69  		}
    70  	}
    71  	return true
    72  }
    73  
    74  // hasCoverageBit returns true if snapshot has at least one bit set that is
    75  // also set in base.
    76  func hasCoverageBit(base, snapshot []byte) bool {
    77  	for i := range snapshot {
    78  		if snapshot[i]&base[i] != 0 {
    79  			return true
    80  		}
    81  	}
    82  	return false
    83  }
    84  
    85  func countBits(cov []byte) int {
    86  	n := 0
    87  	for _, c := range cov {
    88  		n += bits.OnesCount8(c)
    89  	}
    90  	return n
    91  }
    92  
    93  var (
    94  	coverageEnabled  = len(coverage()) > 0
    95  	coverageSnapshot = make([]byte, len(coverage()))
    96  
    97  	// _counters and _ecounters mark the start and end, respectively, of where
    98  	// the 8-bit coverage counters reside in memory. They're known to cmd/link,
    99  	// which specially assigns their addresses for this purpose.
   100  	_counters, _ecounters [0]byte
   101  
   102  	// lookup table for faster power of two rounding
   103  	pow2Table [256]byte
   104  )
   105  
   106  func init() {
   107  	for i := range pow2Table {
   108  		b := byte(i)
   109  		b |= b >> 1
   110  		b |= b >> 2
   111  		b |= b >> 4
   112  		b -= b >> 1
   113  		pow2Table[i] = b
   114  	}
   115  }
   116  

View as plain text