Skip to content

Commit fce40f8

Browse files
committed
cmd/compile, cmd/link: use libFuzzer 8-bit instead of extra counters
By using libFuzzer’s 8-bit counters instead of extra counters, the coverage instrumentation in libFuzzer mode is improved in three ways: 1- 8-bit counters are supported on all platforms, including macOS and Windows, with all relevant versions of libFuzzer, whereas extra counters are a Linux-only feature that only recently received support on Windows. 2- Newly covered blocks are now properly reported as new coverage by libFuzzer, not only as new features. 3- The NeverZero strategy is used to ensure that coverage counters never become 0 again after having been positive once. This resolves issues encountered when fuzzing loops with iteration counts that are multiples of 256 (e.g., larger powers of two).
1 parent c9fe126 commit fce40f8

File tree

17 files changed

+139
-56
lines changed

17 files changed

+139
-56
lines changed

src/cmd/compile/internal/gc/obj.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -281,8 +281,8 @@ func ggloblnod(nam *ir.Name) {
281281
flags |= obj.NOPTR
282282
}
283283
base.Ctxt.Globl(s, nam.Type().Size(), flags)
284-
if nam.LibfuzzerExtraCounter() {
285-
s.Type = objabi.SLIBFUZZER_EXTRA_COUNTER
284+
if nam.Libfuzzer8BitCounter() {
285+
s.Type = objabi.SLIBFUZZER_8BIT_COUNTER
286286
}
287287
if nam.Sym().Linkname != "" {
288288
// Make sure linkname'd symbol is non-package. When a symbol is

src/cmd/compile/internal/ir/name.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ const (
266266
nameInlFormal // PAUTO created by inliner, derived from callee formal
267267
nameInlLocal // PAUTO created by inliner, derived from callee local
268268
nameOpenDeferSlot // if temporary var storing info for open-coded defers
269-
nameLibfuzzerExtraCounter // if PEXTERN should be assigned to __libfuzzer_extra_counters section
269+
nameLibfuzzer8BitCounter // if PEXTERN should be assigned to __sancov_cntrs section
270270
nameAlias // is type name an alias
271271
)
272272

@@ -281,7 +281,7 @@ func (n *Name) Addrtaken() bool { return n.flags&nameAddrtaken !=
281281
func (n *Name) InlFormal() bool { return n.flags&nameInlFormal != 0 }
282282
func (n *Name) InlLocal() bool { return n.flags&nameInlLocal != 0 }
283283
func (n *Name) OpenDeferSlot() bool { return n.flags&nameOpenDeferSlot != 0 }
284-
func (n *Name) LibfuzzerExtraCounter() bool { return n.flags&nameLibfuzzerExtraCounter != 0 }
284+
func (n *Name) Libfuzzer8BitCounter() bool { return n.flags&nameLibfuzzer8BitCounter != 0 }
285285

286286
func (n *Name) setReadonly(b bool) { n.flags.set(nameReadonly, b) }
287287
func (n *Name) SetNeedzero(b bool) { n.flags.set(nameNeedzero, b) }
@@ -294,7 +294,7 @@ func (n *Name) SetAddrtaken(b bool) { n.flags.set(nameAddrtaken,
294294
func (n *Name) SetInlFormal(b bool) { n.flags.set(nameInlFormal, b) }
295295
func (n *Name) SetInlLocal(b bool) { n.flags.set(nameInlLocal, b) }
296296
func (n *Name) SetOpenDeferSlot(b bool) { n.flags.set(nameOpenDeferSlot, b) }
297-
func (n *Name) SetLibfuzzerExtraCounter(b bool) { n.flags.set(nameLibfuzzerExtraCounter, b) }
297+
func (n *Name) SetLibfuzzer8BitCounter(b bool) { n.flags.set(nameLibfuzzer8BitCounter, b) }
298298

299299
// OnStack reports whether variable n may reside on the stack.
300300
func (n *Name) OnStack() bool {

src/cmd/compile/internal/ssa/writebarrier.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -650,7 +650,7 @@ func IsSanitizerSafeAddr(v *Value) bool {
650650
// read-only once initialized.
651651
return true
652652
case OpAddr:
653-
return v.Aux.(*obj.LSym).Type == objabi.SRODATA || v.Aux.(*obj.LSym).Type == objabi.SLIBFUZZER_EXTRA_COUNTER
653+
return v.Aux.(*obj.LSym).Type == objabi.SRODATA || v.Aux.(*obj.LSym).Type == objabi.SLIBFUZZER_8BIT_COUNTER
654654
}
655655
return false
656656
}

src/cmd/compile/internal/typecheck/builtin.go

Lines changed: 5 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/cmd/compile/internal/typecheck/builtin/runtime.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,10 @@ func libfuzzerTraceConstCmp1(uint8, uint8)
265265
func libfuzzerTraceConstCmp2(uint16, uint16)
266266
func libfuzzerTraceConstCmp4(uint32, uint32)
267267
func libfuzzerTraceConstCmp8(uint64, uint64)
268+
func libfuzzerIncrementCounter(*uint8)
269+
270+
// This function should be called by the fuzz target on start to register the 8bit counters with libfuzzer
271+
func LibfuzzerInitializeCounters()
268272

269273
// architecture variants
270274
var x86HasPOPCNT bool

src/cmd/compile/internal/walk/order.go

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -440,21 +440,22 @@ func (o *orderState) edge() {
440440
return
441441
}
442442

443-
// Create a new uint8 counter to be allocated in section
444-
// __libfuzzer_extra_counters.
443+
// Create a new uint8 counter to be allocated in section __sancov_cntrs
445444
counter := staticinit.StaticName(types.Types[types.TUINT8])
446-
counter.SetLibfuzzerExtraCounter(true)
447-
// As well as setting SetLibfuzzerExtraCounter, we preemptively set the
448-
// symbol type to SLIBFUZZER_EXTRA_COUNTER so that the race detector
445+
counter.SetLibfuzzer8BitCounter(true)
446+
// As well as setting SetLibfuzzer8BitCounter, we preemptively set the
447+
// symbol type to SLIBFUZZER_8BIT_COUNTER so that the race detector
449448
// instrumentation pass (which does not have access to the flags set by
450-
// SetLibfuzzerExtraCounter) knows to ignore them. This information is
451-
// lost by the time it reaches the compile step, so SetLibfuzzerExtraCounter
449+
// SetLibfuzzer8BitCounter) knows to ignore them. This information is
450+
// lost by the time it reaches the compile step, so SetLibfuzzer8BitCounter
452451
// is still necessary.
453-
counter.Linksym().Type = objabi.SLIBFUZZER_EXTRA_COUNTER
452+
counter.Linksym().Type = objabi.SLIBFUZZER_8BIT_COUNTER
454453

455-
// counter += 1
456-
incr := ir.NewAssignOpStmt(base.Pos, ir.OADD, counter, ir.NewInt(1))
457-
o.append(incr)
454+
var init ir.Nodes
455+
init.Append(mkcall("libfuzzerIncrementCounter", nil, &init, ir.NewAddrExpr(base.Pos, counter)))
456+
for _, n := range init.Take() {
457+
o.append(n)
458+
}
458459
}
459460

460461
// orderBlock orders the block of statements in n into a new slice,

src/cmd/internal/goobj/builtinlist.go

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/cmd/internal/objabi/symkind.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ const (
6666
SDWARFLOC
6767
SDWARFLINES
6868
// Coverage instrumentation counter for libfuzzer.
69-
SLIBFUZZER_EXTRA_COUNTER
69+
SLIBFUZZER_8BIT_COUNTER
7070
// Update cmd/link/internal/sym/AbiSymKindToSymKind for new SymKind values.
7171

7272
)

src/cmd/internal/objabi/symkind_string.go

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/cmd/link/internal/ld/data.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1780,10 +1780,10 @@ func (state *dodataState) allocateDataSections(ctxt *Link) {
17801780
ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.end", 0), sect)
17811781

17821782
// Coverage instrumentation counters for libfuzzer.
1783-
if len(state.data[sym.SLIBFUZZER_EXTRA_COUNTER]) > 0 {
1784-
sect := state.allocateNamedSectionAndAssignSyms(&Segdata, "__libfuzzer_extra_counters", sym.SLIBFUZZER_EXTRA_COUNTER, sym.Sxxx, 06)
1785-
ldr.SetSymSect(ldr.LookupOrCreateSym("internal/fuzz._counters", 0), sect)
1786-
ldr.SetSymSect(ldr.LookupOrCreateSym("internal/fuzz._ecounters", 0), sect)
1783+
if len(state.data[sym.SLIBFUZZER_8BIT_COUNTER]) > 0 {
1784+
sect := state.allocateNamedSectionAndAssignSyms(&Segdata, "__sancov_cntrs", sym.SLIBFUZZER_8BIT_COUNTER, sym.Sxxx, 06)
1785+
ldr.SetSymSect(ldr.LookupOrCreateSym("__start___sancov_cntrs", 0), sect)
1786+
ldr.SetSymSect(ldr.LookupOrCreateSym("__stop___sancov_cntrs", 0), sect)
17871787
}
17881788

17891789
if len(state.data[sym.STLSBSS]) > 0 {
@@ -2561,7 +2561,7 @@ func (ctxt *Link) address() []*sym.Segment {
25612561
bss = s
25622562
case ".noptrbss":
25632563
noptrbss = s
2564-
case "__libfuzzer_extra_counters":
2564+
case "__sancov_cntrs":
25652565
fuzzCounters = s
25662566
}
25672567
}
@@ -2680,8 +2680,8 @@ func (ctxt *Link) address() []*sym.Segment {
26802680
ctxt.xdefine("runtime.end", sym.SBSS, int64(Segdata.Vaddr+Segdata.Length))
26812681

26822682
if fuzzCounters != nil {
2683-
ctxt.xdefine("internal/fuzz._counters", sym.SLIBFUZZER_EXTRA_COUNTER, int64(fuzzCounters.Vaddr))
2684-
ctxt.xdefine("internal/fuzz._ecounters", sym.SLIBFUZZER_EXTRA_COUNTER, int64(fuzzCounters.Vaddr+fuzzCounters.Length))
2683+
ctxt.xdefine("__start___sancov_cntrs", sym.SLIBFUZZER_8BIT_COUNTER, int64(fuzzCounters.Vaddr))
2684+
ctxt.xdefine("__stop___sancov_cntrs", sym.SLIBFUZZER_8BIT_COUNTER, int64(fuzzCounters.Vaddr+fuzzCounters.Length))
26852685
}
26862686

26872687
if ctxt.IsSolaris() {

0 commit comments

Comments
 (0)