Skip to content

Commit

Permalink
Currently, there isn't a reliable way to build
Browse files Browse the repository at this point in the history
Go test binaries with libfuzzer instrumentation [1].
An attempt such as
`bazel run --@io_bazel_rules_go//go/config:gc_goopts=-d=libfuzzer ...`
fails to compile owing to unresolved symbols, e.g.,
runtime.libfuzzerTraceConstCmp8 [2].

This patch adds `libfuzzer_shim.go` (identical to `trace.go` [2])
to the `bzltestutil` package, which ensures the shim is linked
with a Go test binary. Furthermore, we exclude `-d=libfuzzer`
when compiling any of the _external_ dependencies.

[1] bazel-contrib#3088 (comment)
[2] golang/go@74f49f3
  • Loading branch information
srosenberg committed May 22, 2024
1 parent 0e7e4e3 commit e104af2
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 0 deletions.
12 changes: 12 additions & 0 deletions go/tools/builders/compilepkg.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"os/exec"
"path"
"path/filepath"
"slices"
"sort"
"strings"
)
Expand Down Expand Up @@ -343,6 +344,17 @@ func compileArchive(
cgoSrcs[i-len(goSrcs)] = coverSrc
}
}
if strings.Contains(outLinkObj, "external/") && slices.Contains(gcFlags, "-d=libfuzzer") {
// Remove -d=libfuzzer from gcFlags when compiling external packages. We don't really want to instrument them,
// and they may not link without libfuzzer_shim.go.
gcFlags = slices.DeleteFunc(gcFlags, func(s string) bool {
return s == "-d=libfuzzer"
})
}
// Log instrumented objs for ease of tracking/debugging.
if slices.Contains(gcFlags, "-d=libfuzzer") {
fmt.Printf("%s -- gcFlags=%s\n", outLinkObj, gcFlags)
}

// If we have cgo, generate separate C and go files, and compile the
// C files.
Expand Down
7 changes: 7 additions & 0 deletions go/tools/builders/stdlib.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"path/filepath"
"regexp"
"strings"
"slices"
)

// stdlib builds the standard library in the appropriate mode into a new goroot.
Expand Down Expand Up @@ -154,6 +155,12 @@ You may need to use the flags --cpu=x64_windows --compiler=mingw-gcc.`)
break
}
}
// Remove -d=libfuzzer from gcflags when compiling stdlib. We only want our code to be instrumented.
// N.B. allowing this flag to pass may cause issues when linking external tools, e.g., protoc-bin, owing
// to unresolved symbols, i.e., libfuzzer_shim.go isn't included.
gcflags = slices.DeleteFunc(gcflags, func(s string) bool {
return s == "-d=libfuzzer"
})
installArgs = append(installArgs, "-gcflags="+allSlug+strings.Join(gcflags, " "))
installArgs = append(installArgs, "-ldflags="+allSlug+strings.Join(ldflags, " "))
installArgs = append(installArgs, "-asmflags="+allSlug+strings.Join(asmflags, " "))
Expand Down
41 changes: 41 additions & 0 deletions go/tools/bzltestutil/libfuzzer_shim.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// N.B. This source is lifted verbatim from trace.go, added in
// https://github.com/golang/go/commit/74f49f3366826f95a464cc15838a0668c92e3357
//
// It's essentially a shim to allow linking a Go test binary without libfuzzer.
// We chose the 'bzltestutil' package because it's a bazel dependency for all Go test binaries.

//go:build !libfuzzer

package bzltestutil

import _ "unsafe" // for go:linkname

//go:linkname libfuzzerTraceCmp1 runtime.libfuzzerTraceCmp1
//go:linkname libfuzzerTraceCmp2 runtime.libfuzzerTraceCmp2
//go:linkname libfuzzerTraceCmp4 runtime.libfuzzerTraceCmp4
//go:linkname libfuzzerTraceCmp8 runtime.libfuzzerTraceCmp8

//go:linkname libfuzzerTraceConstCmp1 runtime.libfuzzerTraceConstCmp1
//go:linkname libfuzzerTraceConstCmp2 runtime.libfuzzerTraceConstCmp2
//go:linkname libfuzzerTraceConstCmp4 runtime.libfuzzerTraceConstCmp4
//go:linkname libfuzzerTraceConstCmp8 runtime.libfuzzerTraceConstCmp8

//go:linkname libfuzzerHookStrCmp runtime.libfuzzerHookStrCmp
//go:linkname libfuzzerHookEqualFold runtime.libfuzzerHookEqualFold

func libfuzzerTraceCmp1(arg0, arg1 uint8, fakePC int) {}
func libfuzzerTraceCmp2(arg0, arg1 uint16, fakePC int) {}
func libfuzzerTraceCmp4(arg0, arg1 uint32, fakePC int) {}
func libfuzzerTraceCmp8(arg0, arg1 uint64, fakePC int) {}

func libfuzzerTraceConstCmp1(arg0, arg1 uint8, fakePC int) {}
func libfuzzerTraceConstCmp2(arg0, arg1 uint16, fakePC int) {}
func libfuzzerTraceConstCmp4(arg0, arg1 uint32, fakePC int) {}
func libfuzzerTraceConstCmp8(arg0, arg1 uint64, fakePC int) {}

func libfuzzerHookStrCmp(arg0, arg1 string, fakePC int) {}
func libfuzzerHookEqualFold(arg0, arg1 string, fakePC int) {}

0 comments on commit e104af2

Please sign in to comment.