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  		b |= b >> 1
    27  		b |= b >> 2
    28  		b |= b >> 4
    29  		b -= b >> 1
    30  		coverageSnapshot[i] = b
    31  	}
    32  }
    33  
    34  // diffCoverage returns a set of bits set in snapshot but not in base.
    35  // If there are no new bits set, diffCoverage returns nil.
    36  func diffCoverage(base, snapshot []byte) []byte {
    37  	if len(base) != len(snapshot) {
    38  		panic(fmt.Sprintf("the number of coverage bits changed: before=%d, after=%d", len(base), len(snapshot)))
    39  	}
    40  	found := false
    41  	for i := range snapshot {
    42  		if snapshot[i]&^base[i] != 0 {
    43  			found = true
    44  			break
    45  		}
    46  	}
    47  	if !found {
    48  		return nil
    49  	}
    50  	diff := make([]byte, len(snapshot))
    51  	for i := range diff {
    52  		diff[i] = snapshot[i] &^ base[i]
    53  	}
    54  	return diff
    55  }
    56  
    57  // countNewCoverageBits returns the number of bits set in snapshot that are not
    58  // set in base.
    59  func countNewCoverageBits(base, snapshot []byte) int {
    60  	n := 0
    61  	for i := range snapshot {
    62  		n += bits.OnesCount8(snapshot[i] &^ base[i])
    63  	}
    64  	return n
    65  }
    66  
    67  // isCoverageSubset returns true if all the base coverage bits are set in
    68  // snapshot.
    69  func isCoverageSubset(base, snapshot []byte) bool {
    70  	for i, v := range base {
    71  		if v&snapshot[i] != v {
    72  			return false
    73  		}
    74  	}
    75  	return true
    76  }
    77  
    78  // hasCoverageBit returns true if snapshot has at least one bit set that is
    79  // also set in base.
    80  func hasCoverageBit(base, snapshot []byte) bool {
    81  	for i := range snapshot {
    82  		if snapshot[i]&base[i] != 0 {
    83  			return true
    84  		}
    85  	}
    86  	return false
    87  }
    88  
    89  func countBits(cov []byte) int {
    90  	n := 0
    91  	for _, c := range cov {
    92  		n += bits.OnesCount8(c)
    93  	}
    94  	return n
    95  }
    96  
    97  var (
    98  	coverageEnabled  = len(coverage()) > 0
    99  	coverageSnapshot = make([]byte, len(coverage()))
   100  
   101  	// _counters and _ecounters mark the start and end, respectively, of where
   102  	// the 8-bit coverage counters reside in memory. They're known to cmd/link,
   103  	// which specially assigns their addresses for this purpose.
   104  	_counters, _ecounters [0]byte
   105  )
   106  

View as plain text