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

View as plain text