Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

preliminary Go modules support #274

Merged
merged 5 commits into from
Oct 22, 2019
Merged

Conversation

thepudds
Copy link
Collaborator

@thepudds thepudds commented Oct 3, 2019

Summary

The heart of the change is very small -- we stop overwriting the user's value for the GO111MODULE env var in two places. This means we end up respecting whatever the user has set for GO111MODULE, and rely on cmd/go to interpret the meaning of an unset GO111MODULE (which defaults to auto for Go 1.11-1.13, and likely will default to on at some point during Go 1.14 development).

In addition, there are some comments added, as well as an explicit check for GOFLAGS=-mod=vendor, which is not supported.

The tests exercise 'replace' directives, v2+ modules, GO111MODULE set to on|off|auto, running inside GOPATH, running outside GOPATH, specifying pkg/func arguments to go-fuzz-build/go-fuzz, not specifying those arguments, the mechanisms by which go-fuzz/go-fuzz-dep is found, as well as vendoring (which is not supported, but it tests that a sensible error is emitted).

Fixes #195

Additional Details

Historically, go-fuzz has set up a clean GOPATH environment in a temp directory, instrumented the code for fuzzing coverage, and built the instrumented code in the temp directory.

The current approach is to keep doing that (and not set up a full-blown modules-based environment for building), but use modules to find the code to instrument.

v2+ modules are potentially problematic due to Semantic Import Versioning (where the major version is placed in the import path, such as github.com/my/mod/v2). However, it turns out to not be too bad to handle it. For a v2+ module created following the 'major branch' approach, the /vN is materialized into a physical directory. For example, the github.com/russross/blackfriday/v2 module ends up in the /tmp/blah/gopath/src/github.com/russross/blackfriday/v2 directory. This should be a valid layout, and people use this layout today (which is called the 'major subdirectory' approach for a v2+ module).

The approach does not copy go.mod files at all. (Before starting, I was thinking I would need to copy go.mod files to trigger "minimal module awareness", which is a transitional mechanism within cmd/go, but after some experimentation / thinking, I concluded it was not needed based on materializing the /vN).

For tests, I am using the script-driven test facility that the core Go team created for testing cmd/go, which is well tuned to testing the various permutations of modules, including it lets you relatively easily set up go.mod files and source files, run commands and check results. (Some more details of the capability here: https://github.com/golang/go/blob/master/src/cmd/go/testdata/script/README).

#### Summary 

The heart of the change is very small -- we stop overwriting the user's value for the `GO111MODULE` env var in two places. This means we end up respecting whatever the user has set for `GO111MODULE`, and relying on `cmd/go` to interpret the meaning of an unset `GO111MODULE` (which defaults to `auto` for Go 1.11-1.13, and likely will default to `on` at some point during Go 1.14 development).

In addition, there are some comments added, as well as an explicit check for `GOFLAGS=-mod=vendor`, which is not supported.

The tests exercises 'replace' directives, v2+ modules, GO111MODULE set to on|off|auto, running inside GOPATH, running outside GOPATH, the mechanisms by which go-fuzz/go-fuzz-dep is found, as well as vendoring (which is not supported, but it tests that a sensible error is emitted). 

#### Additional Details

Historically, go-fuzz has set up a clean GOPATH environment in a temp directory, instrumented the code for fuzzing coverage, and built the instrumented code in the temp directory.

The current approach is to keep doing that (and not set up a full-blown modules-based environment for building), but use modules to find the code to instrument.

v2+ modules are potentially problematic due to Semantic Import Versioning (with the major version in the import path). However, it turns out to not be too bad to handle it. For a v2+ module created following the 'major branch' approach, the /vN is materialized into a physical directory. For example, the github.com/russross/blackfriday/v2 module ends up in the /tmp/blah/gopath/src/github.com/russross/blackfriday/v2 directory. This should be a valid layout, and people use this layout today (including when manually switching to a 'major subdirectory' approach for a v2+ module, which involves creating a /v2 or /vN directory so that pre-modules toolchains follow a /v2 or /vN import path and find an on-disk layout that they expect without any knowledge of modules).

The approach does not copy go.mod files at all. (Before starting, I was thinking I would need to copy go.mod files to trigger "minimal module awareness", which is a transitional mechanism within cmd/go, but after some experimentation / thinking, I concluded it was not needed based on materializing the /v2).

For tests, I am using the script-driven test facility that the core Go team created for testing cmd/go, which is well tuned to testing the various permutations of modules, including it lets you relatively easily set up go.mod files and source files, run commands and check results. (Some more details of the capability here: https://github.com/golang/go/blob/master/src/cmd/go/testdata/script/README).
@thepudds
Copy link
Collaborator Author

thepudds commented Oct 4, 2019

@thepudds
Copy link
Collaborator Author

thepudds commented Oct 4, 2019

There had been a few moving parts for this:

  1. This had been waiting on Explicitly disable Go modules via GO111MODULE=off for go-fuzz corpus google/oss-fuzz#2878, which is addressed as of today.

  2. All of the recent modules-related go-fuzz PRs increase the chances of version skew between the binaries (e.g., go-fuzz, go-fuzz-build) and the source code for go-fuzz/go-fuzz-defs and go-fuzz/go-fuzz-deps. After discussing this concern out-of-band with @josharian, he kindly sent all: add basic version skew detection #273. That is not strictly needed immediately, but does increase robustness, especially in the medium/long term.

  3. Addressing go-fuzz-build: embed support packages in binary? #252 by embedding the support packages in the binaries would simplify things here a bit and avoid the need for this in the readme, but my take is it is reasonable for go-fuzz-build: embed support packages in binary? #252 to be a separate effort from this.

Given item 1 is now addressed and items 2 and 3 both affect all the recent PRs equally, I think this PR is ready for review as a viable candidate.

@frioux
Copy link

frioux commented Oct 4, 2019

Figured this might be worth trying out and I hit a wall pretty quickly. I cloned https://github.com/thepudds/go-fuzz, added a go.mod like this:

module github.com/dvyukov/go-fuzz

go 1.13

require golang.org/x/tools v0.0.0-20191004034534-88641d98b32a

Build it by doing

cd go-fuzz-build
go build -o ~/bin/go-fuzz-build .

In my app I did this to ensure I'd get the module aware version:

go mod edit -replace github.com/dvyukov/go-fuzz=github.com/thepudds/go-fuzz@latest

Then when I try to build I get this:

$ go-fuzz-build ./config/epoxy/internal/apps/fuzz
failed to execute go build: exit status 1
/run/shm/go-fuzz-build601694876/gopath/src/go.zr.org/config/epoxy/internal/apps/fuzz/go.fuzz.main/main.go:6:2: cannot find package "go-fuzz-dep" in any of:
        /home/frew/sdk/go1.13/src/go-fuzz-dep (from $GOROOT)
        /run/shm/go-fuzz-build601694876/gopath/src/go-fuzz-dep (from $GOPATH)

@yevgenypats
Copy link
Contributor

@frioux thanks for reporting! can you please create a small github repo so we can reproduce this correctly?

@frioux
Copy link

frioux commented Oct 4, 2019

frioux/leatherman@2c7fe8f reproduces it in an OSS repo; just clone the repo, switch to branch fuzz, and run go-fuzz-build ./fuzz. You should see:

$ go-fuzz-build ./fuzz          
failed to execute go build: exit status 1
fuzz/fuzz.go:1: cannot find package "go-fuzz-dep" in any of:
        /home/frew/sdk/go1.13/src/go-fuzz-dep (from $GOROOT)
        /run/shm/go-fuzz-build553619940/gopath/src/go-fuzz-dep (from $GOPATH)

@thepudds
Copy link
Collaborator Author

thepudds commented Oct 4, 2019

Hello @frioux , thanks for the extra eyes here. I really appreciate the extra scrutiny.

I'm not sure though exactly what steps you were following when you were testing.

You appear to have made go-fuzz itself into a module, which is not what this change supports. (We are getting progressively closer to go-fuzz being a module itself, but that is still a future issue; this change is just about fuzzing modules).

Also, what branch did you use when building github.com/thepudds/go-fuzz?

The changes in this PR are in the dev-modules-2 branch there.

Separately, I'm not sure that replace in your module is needed for thepudds/go-fuzz (and if it is needed for some reason, it probably shouldn't point to master on thepudds/go-fuzz; that's not the branch in question).

FWIW, maybe I made a mistake when trying this, but these steps seemed to work for me to fuzz the module in your fuzz branch of frioux/leatherman, where the starting point was a clean machine with Go 1.13.1:

# install go-fuzz
go get -u github.com/dvyukov/go-fuzz/...

# build go-fuzz from dev-modules-2 branch of thepudds/go-fuzz
rm -rf $(go env GOPATH)/src/github.com/dvyukov/go-fuzz/
git clone -b dev-modules-2 https://github.com/thepudds/go-fuzz $(go env GOPATH)/src/github.com/dvyukov/go-fuzz/
cd $(go env GOPATH)/src/github.com/dvyukov/go-fuzz/
go install ./...

# clone frioux/leatherman module
git clone -b fuzz https://github.com/frioux/leatherman /tmp/scratchpad/leatherman
cd /tmp/scratchpad/leatherman

# fuzz
go-fuzz-build ./fuzz
go-fuzz -bin=fuzz-fuzz.zip

which outputs:

2019/10/04 14:19:31 workers: 4, corpus: 2 (2s ago), crashers: 0, restarts: 1/0, execs: 0 (0/sec), cover: 0, uptime: 3s
2019/10/04 14:19:34 workers: 4, corpus: 2 (5s ago), crashers: 0, restarts: 1/0, execs: 0 (0/sec), cover: 4, uptime: 6s
$ go version
go version go1.13.1 linux/amd64

@frioux
Copy link

frioux commented Oct 4, 2019

@thepudds thanks for the quick response. You're right, I tried to convert to a module, mostly because that felt easier than using GOPATH at this point, but that was surely a mistake. Even still, I tried following your steps and was unsuccessful:

$ export GO111MODULE=auto # I have mine set to on, normally
$ go get -u github.com/dvyukov/go-fuzz/...
$ rm -rf $(go env GOPATH)/src/github.com/dvyukov/go-fuzz/
$ git clone -b dev-modules-2 https://github.com/thepudds/go-fuzz $(go env GOPATH)/src/github.com/dvyukov/go-fuzz/
Cloning into '/home/frew/go/src/github.com/dvyukov/go-fuzz'...
remote: Enumerating objects: 6581, done.
remote: Total 6581 (delta 0), reused 0 (delta 0), pack-reused 6581
Receiving objects: 100% (6581/6581), 5.36 MiB | 5.10 MiB/s, done.
Resolving deltas: 100% (2195/2195), done.
$ cd $(go env GOPATH)/src/github.com/dvyukov/go-fuzz/
$ go install ./...
$ git clone -b fuzz https://github.com/frioux/leatherman $TMPDIR/leatherman
Cloning into '/run/shm/leatherman'...
remote: Enumerating objects: 124, done.
remote: Counting objects: 100% (124/124), done.
remote: Compressing objects: 100% (93/93), done.
remote: Total 2058 (delta 39), reused 72 (delta 26), pack-reused 1934
Receiving objects: 100% (2058/2058), 458.65 KiB | 3.55 MiB/s, done.
Resolving deltas: 100% (1127/1127), done.
$ cd $TMPDIR/leatherman
$ rm ~/bin/go-fuzz-build 
$ go-fuzz-build ./fuzz
failed to execute go build: exit status 1
fuzz/fuzz.go:1: cannot find package "go-fuzz-dep" in any of:
        /home/frew/sdk/go1.13/src/go-fuzz-dep (from $GOROOT)
        /run/shm/go-fuzz-build842956865/gopath/src/go-fuzz-dep (from $GOPATH)

In case it's helpful, here's my go env:

GO111MODULE="auto"
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/frew/.cache/go-build"
GOENV="/home/frew/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/frew/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org"
GOROOT="/home/frew/sdk/go1.13"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/home/frew/sdk/go1.13/pkg/tool/linux_amd64"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/run/shm/leatherman/go.mod"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/run/shm/go-build227369656=/tmp/go-build -gno-record-gcc-switches"

Also, just for kicks, I did a go fuzz build, keeping the work dir. Here's the tree:

/run/shm/go-fuzz-build797413636/
├── gopath
│   └── src
│       └── github.com
│           ├── dvyukov
│           │   └── go-fuzz
│           │       ├── go-fuzz-defs
│           │       │   └── defs.go
│           │       └── go-fuzz-dep
│           │           ├── cover.go
│           │           ├── doc.go
│           │           ├── main.go
│           │           ├── sonar.go
│           │           └── sys_posix.go
│           └── frioux
│               └── leatherman
│                   └── fuzz
│                       ├── fuzz.go
│                       └── go.fuzz.main
│                           └── main.go
└── goroot
    ├── pkg
    │   ├── include
    │   │   ├── asm_ppc64x.h
    │   │   ├── funcdata.h
    │   │   └── textflag.h
    │   └── tool
    │       └── linux_amd64
    │           ├── addr2line
    │           ├── asm
    │           ├── buildid
    │           ├── cgo
    │           ├── compile
    │           ├── cover
    │           ├── dist
    │           ├── doc
    │           ├── fix
    │           ├── link
    │           ├── nm
    │           ├── objdump
    │           ├── pack
    │           ├── pprof
    │           ├── test2json
    │           ├── trace
    │           └── vet
    └── src
        ├── errors
        │   ├── errors.go
        │   └── wrap.go
        ├── go-fuzz-dep
        │   ├── cover.go
        │   ├── defs.go
        │   ├── doc.go
        │   ├── main.go
        │   ├── sonar.go
        │   └── sys_posix.go
        ├── internal
        │   ├── bytealg
        │   │   ├── bytealg.go
        │   │   ├── compare_amd64.s
        │   │   ├── compare_native.go
        │   │   ├── count_amd64.s
        │   │   ├── count_native.go
        │   │   ├── equal_amd64.s
        │   │   ├── equal_generic.go
        │   │   ├── equal_native.go
        │   │   ├── index_amd64.go
        │   │   ├── index_amd64.s
        │   │   ├── indexbyte_amd64.s
        │   │   ├── indexbyte_native.go
        │   │   └── index_native.go
        │   ├── cpu
        │   │   ├── cpu_amd64.go
        │   │   ├── cpu.go
        │   │   ├── cpu_x86.go
        │   │   └── cpu_x86.s
        │   ├── oserror
        │   │   └── errors.go
        │   ├── race
        │   │   ├── doc.go
        │   │   └── norace.go
        │   └── reflectlite
        │       ├── asm.s
        │       ├── swapper.go
        │       ├── type.go
        │       └── value.go
        ├── runtime
        │   ├── alg.go
        │   ├── asm_amd64.s
        │   ├── asm_ppc64x.h
        │   ├── asm.s
        │   ├── atomic_pointer.go
        │   ├── cgocallback.go
        │   ├── cgocall.go
        │   ├── cgocheck.go
        │   ├── cgo.go
        │   ├── cgo_mmap.go
        │   ├── cgo_sigaction.go
        │   ├── chan.go
        │   ├── compiler.go
        │   ├── complex.go
        │   ├── cpuflags_amd64.go
        │   ├── cpuflags.go
        │   ├── cpuprof.go
        │   ├── cputicks.go
        │   ├── debugcall.go
        │   ├── debug.go
        │   ├── debuglog.go
        │   ├── debuglog_off.go
        │   ├── defs_linux_amd64.go
        │   ├── duff_amd64.s
        │   ├── env_posix.go
        │   ├── error.go
        │   ├── extern.go
        │   ├── fastlog2.go
        │   ├── fastlog2table.go
        │   ├── float.go
        │   ├── funcdata.h
        │   ├── go_tls.h
        │   ├── hash64.go
        │   ├── heapdump.go
        │   ├── iface.go
        │   ├── internal
        │   │   ├── atomic
        │   │   │   ├── asm_amd64.s
        │   │   │   ├── atomic_amd64x.go
        │   │   │   └── stubs.go
        │   │   ├── math
        │   │   │   └── math.go
        │   │   └── sys
        │   │       ├── arch_amd64.go
        │   │       ├── arch.go
        │   │       ├── intrinsics.go
        │   │       ├── stubs.go
        │   │       ├── sys.go
        │   │       ├── zgoarch_amd64.go
        │   │       ├── zgoos_linux.go
        │   │       └── zversion.go
        │   ├── lfstack_64bit.go
        │   ├── lfstack.go
        │   ├── lock_futex.go
        │   ├── malloc.go
        │   ├── map_fast32.go
        │   ├── map_fast64.go
        │   ├── map_faststr.go
        │   ├── map.go
        │   ├── mbarrier.go
        │   ├── mbitmap.go
        │   ├── mcache.go
        │   ├── mcentral.go
        │   ├── memclr_amd64.s
        │   ├── mem_linux.go
        │   ├── memmove_amd64.s
        │   ├── mfinal.go
        │   ├── mfixalloc.go
        │   ├── mgc.go
        │   ├── mgclarge.go
        │   ├── mgcmark.go
        │   ├── mgcscavenge.go
        │   ├── mgcstack.go
        │   ├── mgcsweepbuf.go
        │   ├── mgcsweep.go
        │   ├── mgcwork.go
        │   ├── mheap.go
        │   ├── mprof.go
        │   ├── msan0.go
        │   ├── msize.go
        │   ├── mstats.go
        │   ├── mwbbuf.go
        │   ├── netpoll_epoll.go
        │   ├── netpoll.go
        │   ├── os_linux_generic.go
        │   ├── os_linux.go
        │   ├── os_linux_noauxv.go
        │   ├── os_nonopenbsd.go
        │   ├── panic.go
        │   ├── plugin.go
        │   ├── print.go
        │   ├── proc.go
        │   ├── profbuf.go
        │   ├── proflabel.go
        │   ├── race0.go
        │   ├── rdebug.go
        │   ├── relax_stub.go
        │   ├── rt0_linux_amd64.s
        │   ├── runtime1.go
        │   ├── runtime2.go
        │   ├── runtime.go
        │   ├── rwmutex.go
        │   ├── select.go
        │   ├── sema.go
        │   ├── signal_amd64x.go
        │   ├── signal_linux_amd64.go
        │   ├── signal_sighandler.go
        │   ├── signal_unix.go
        │   ├── sigqueue.go
        │   ├── sigqueue_note.go
        │   ├── sigtab_linux_generic.go
        │   ├── sizeclasses.go
        │   ├── slice.go
        │   ├── softfloat64.go
        │   ├── stack.go
        │   ├── string.go
        │   ├── stubs2.go
        │   ├── stubs3.go
        │   ├── stubs_amd64x.go
        │   ├── stubs.go
        │   ├── stubs_linux.go
        │   ├── symtab.go
        │   ├── sys_linux_amd64.s
        │   ├── sys_nonppc64x.go
        │   ├── sys_x86.go
        │   ├── textflag.h
        │   ├── time.go
        │   ├── timestub2.go
        │   ├── timestub.go
        │   ├── traceback.go
        │   ├── trace.go
        │   ├── type.go
        │   ├── typekind.go
        │   ├── utf8.go
        │   ├── vdso_elf64.go
        │   ├── vdso_linux_amd64.go
        │   ├── vdso_linux.go
        │   └── write_err.go
        ├── sync
        │   ├── atomic
        │   │   ├── asm.s
        │   │   ├── doc.go
        │   │   └── value.go
        │   ├── cond.go
        │   ├── map.go
        │   ├── mutex.go
        │   ├── once.go
        │   ├── pool.go
        │   ├── poolqueue.go
        │   ├── runtime.go
        │   ├── rwmutex.go
        │   └── waitgroup.go
        ├── syscall
        │   ├── asm_linux_amd64.s
        │   ├── dirent.go
        │   ├── endian_little.go
        │   ├── env_unix.go
        │   ├── exec_linux.go
        │   ├── exec_unix.go
        │   ├── flock.go
        │   ├── lsf_linux.go
        │   ├── msan0.go
        │   ├── net.go
        │   ├── netlink_linux.go
        │   ├── setuidgid_linux.go
        │   ├── sockcmsg_linux.go
        │   ├── sockcmsg_unix.go
        │   ├── str.go
        │   ├── syscall.go
        │   ├── syscall_linux_amd64.go
        │   ├── syscall_linux.go
        │   ├── syscall_unix.go
        │   ├── timestruct.go
        │   ├── zerrors_linux_amd64.go
        │   ├── zsyscall_linux_amd64.go
        │   ├── zsysnum_linux_amd64.go
        │   └── ztypes_linux_amd64.go
        ├── time
        │   ├── format.go
        │   ├── sleep.go
        │   ├── sys_unix.go
        │   ├── tick.go
        │   ├── time.go
        │   ├── zoneinfo.go
        │   ├── zoneinfo_read.go
        │   └── zoneinfo_unix.go
        └── unsafe
            └── unsafe.go

35 directories, 239 files

@thepudds
Copy link
Collaborator Author

thepudds commented Oct 4, 2019

@frioux I don't know that this is it, but could you remove the replace in your module for thepudds/go-fuzz, which also means you'll need to remove the corresponding require? It shouldn't be needed (and if it is needed for some reason, it currently points to the wrong branch).

In other words, remove these two lines from your module's go.mod:

replace github.com/dvyukov/go-fuzz => github.com/thepudds/go-fuzz v0.0.0-20190808141544-193030f1cb16

github.com/dvyukov/go-fuzz v0.0.0-00010101000000-000000000000 // indirect

Also, can you send go version output?

@thepudds
Copy link
Collaborator Author

thepudds commented Oct 4, 2019

@frioux Also, this is probably not it, but could you explain the rm here in your steps:

$ cd $TMPDIR/leatherman
$ rm ~/bin/go-fuzz-build 
$ go-fuzz-build ./fuzz

As a sanity check, could you do which go-fuzz-build and ls -l $(which go-fuzz-build) and see if the results are as you expect (vs. maybe there is an older binary somewhere else in your $PATH?)

@frioux
Copy link

frioux commented Oct 4, 2019

Ok, removed the fuzz related stuff from my module files (see frioux/leatherman@4ce327c.)

The rm was to make absolutely sure I had no old version of go-fuzz-build installed;

$ which go-fuzz-build
/home/frew/go/bin/go-fuzz-build

Just to rebuild and everything, here is a removal and fresh install:

$ rm $(which go-fuzz-build)
$ rm -rf $(go env GOPATH)/src/github.com/dvyukov/go-fuzz/
$ git clone -b dev-modules-2 https://github.com/thepudds/go-fuzz $(go env GOPATH)/src/github.com/dvyukov/go-fuzz/
Cloning into '/home/frew/go/src/github.com/dvyukov/go-fuzz'...
remote: Enumerating objects: 6581, done.
remote: Total 6581 (delta 0), reused 0 (delta 0), pack-reused 6581
Receiving objects: 100% (6581/6581), 5.36 MiB | 3.75 MiB/s, done.
Resolving deltas: 100% (2195/2195), done.
$ cd $(go env GOPATH)/src/github.com/dvyukov/go-fuzz/
$ GO111MODULE=auto go install ./...
$ ls -lh /home/frew/go/bin/go-fuzz-build
-rwxrwxr-x 1 frew frew 7.5M Oct  4 09:53 /home/frew/go/bin/go-fuzz-build
$ cd ~/code/leatherman 
$ go-fuzz-build ./fuzz
failed to execute go build: exit status 1
fuzz/fuzz.go:1: cannot find package "go-fuzz-dep" in any of:
        /home/frew/sdk/go1.13/src/go-fuzz-dep (from $GOROOT)
        /run/shm/go-fuzz-build120318659/gopath/src/go-fuzz-dep (from $GOPATH)
$ go version
go version go1.13 linux/amd64

@thepudds
Copy link
Collaborator Author

thepudds commented Oct 4, 2019

@frioux Are you doing anything special with GOROOT? Are you setting it somewhere?

I wonder if it is correct here, or maybe not being handled correctly.

According to the error message you are seeing, GOROOT seems to be pointing to /home/frew/sdk/go1.13 when go build is invoked by go-fuzz-build:

fuzz/fuzz.go:1: cannot find package "go-fuzz-dep" in any of:
        /home/frew/sdk/go1.13/src/go-fuzz-dep (from $GOROOT)
        /run/shm/go-fuzz-build120318659/gopath/src/go-fuzz-dep (from $GOPATH)

However, it probably should be pointing to /run/shm/go-fuzz-build[...]/goroot at that point?

According to your tree output in #274 (comment), it appears go-fuzz-dep is located in the temporary goroot directory, which I think is an expected location:

[...]
└── goroot
    ├── pkg
        [...]
    └── src
        ├── errors
        │   ├── errors.go
        │   └── wrap.go
        ├── go-fuzz-dep
        │   ├── cover.go
            [...]

For a new workdir, could you do:

head /tmp/go-fuzz-build[...]/gopath/src/github.com/frioux/leatherman/fuzz/fuzz.go
head /tmp/go-fuzz-build[...]/gopath/src/github.com/dvyukov/go-fuzz/go-fuzz-dep/cover.go
head /tmp/go-fuzz-build[...]/goroot/src/go-fuzz-dep/cover.go 

@thepudds
Copy link
Collaborator Author

thepudds commented Oct 4, 2019

For anyone else following this PR, I would be curious if anyone else can reproduce the issue that @frioux encountered (e.g., following the steps I outlined in #274 (comment)).

@frioux
Copy link

frioux commented Oct 4, 2019

Here's the tops of those files:

$ head /run/shm/go-fuzz-build278060644/gopath/src/github.com/frioux/leatherman/fuzz/fuzz.go 
//line /home/frew/code/leatherman/fuzz/fuzz.go:1
package fuzz

//line /home/frew/code/leatherman/fuzz/fuzz.go:1
import _go_fuzz_dep_ "go-fuzz-dep"

func Fuzz(data []byte) int {
//line /home/frew/code/leatherman/fuzz/fuzz.go:3
        _go_fuzz_dep_.CoverTab[22588]++
                                                        if len(data) < 1 {
$ head /run/shm/go-fuzz-build278060644/gopath/src/github.com/dvyukov/go-fuzz/go-fuzz-dep/cover.go 
// Copyright 2019 go-fuzz project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

// +build gofuzz

package gofuzzdep

import (
        . "github.com/dvyukov/go-fuzz/go-fuzz-defs"
)
$ head /run/shm/go-fuzz-build278060644/goroot/src/go-fuzz-dep/cover.go  
// Copyright 2019 go-fuzz project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

// +build gofuzz

package gofuzzdep

import (

)

As for GOROOT; I don't explicitly set it, but it is set by the go binary itself to /home/frew/sdk/go1.13 since that's where go1.13 is installed (via go get golang.org/dl/go1.13 etc).

@yevgenypats
Copy link
Contributor

hey @frioux :) can you send instructions with a clean docker image i.e something like that:

docker run -it golang:1.13 /bin/bash
git clone ...
....

I think this will make a reproducible environment for everyone

@thepudds
Copy link
Collaborator Author

thepudds commented Oct 4, 2019

@frioux If you are installing the go command via go get golang.org/dl/go1.13, I think that is a wrapper command that then juggles GOROOT.

For example, if I use a normally installed go command, I can set GOROOT via an env variable, and it is respected (though in this example, the directory doesn't exist, so it triggers an error):

$ GOROOT=/tmp/foo go env
go: cannot find GOROOT directory: /tmp/foo

However, using the binary from go get golang.org/dl/go1.13 does not respect GOROOT env variable:

$ go get golang.org/dl/go1.13
$ go1.13 download
$ GOROOT=/tmp/foo go1.13 env GOROOT
/home/[...]/sdk/go1.13

Can you try instead with a normally installed go command? E.g., something like the following in a fresh environment:

wget https://dl.google.com/go/go1.13.1.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.13.1.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin/
export PATH=$PATH:$HOME/go/bin

@frioux
Copy link

frioux commented Oct 4, 2019

Bypassing the wrapper (/home/frew/go/bin/go1.13) and using the actual go tool (/home/frew/sdk/go1.13/bin/go) resolved the issue. Thanks for your help all. It might be nice if this were to error more clearly when GOROOT isn't being respected but I understand that that's maybe pathological.

Copy link
Contributor

@mvdan mvdan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First pass on the code; I'll read the tests on the second pass.

.travis.yml Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
go-fuzz-build/main.go Show resolved Hide resolved
go-fuzz-build/main.go Show resolved Hide resolved
go-fuzz-build/main.go Show resolved Hide resolved
go-fuzz/main.go Show resolved Hide resolved
testscripts/fuzz_help.txt Show resolved Hide resolved
@thepudds
Copy link
Collaborator Author

thepudds commented Oct 7, 2019

FWIW, I believe the issue @frioux hit has nothing to do this the changes in this PR. I believe it would affect current master in the same way. (That's what I would think in theory, as well as confirmed master breaks in the same way with a quick test).

@josharian
Copy link
Collaborator

FWIW, I believe the issue @frioux hit has nothing to do this the changes in this PR.

Copy. The delay here is simply me taking the time to read and understand this thoroughly.

@thepudds
Copy link
Collaborator Author

thepudds commented Oct 7, 2019

One other quick comment in case it wasn't clear -- the actual code-level changes in my PR are very small. The only material code change is to stop setting GO111MODULE in two spots (plus some comments, and one sanity check to get a slightly friendlier error if someone tries to force vendoring to be on.... which I'd be happy to drop because its not super important).

The bigger volume by far is the tests, but don't feel too obligated to spend an enormous amount of time reading them, especially if short on time.

@josharian
Copy link
Collaborator

Good to know.

I'm afraid merging #271 has caused a merge conflict here. Sorry. :( Can I bother you to update, at your leisure?

@thepudds
Copy link
Collaborator Author

thepudds commented Oct 7, 2019

For next steps, I didn’t quite follow what you were saying.

Are you saying I should change my PR to stop respecting GO111MODULE by default, and only use the new GOFUZZ111MODULE?

Or you saying my PR should respect GO111MODULE by default, but treat GOFUZZ111MODULE as an override?

(If you are saying the latter, then that's what I don't quite follow -- the current escape hatch in my current PR is the user can set GO111MODULE=off if needed, including it's mentioned at the top of the readme. Are you saying the goal is to have two escape hatches of GOFUZZ111MODULE=off and GO111MODULE=off supported at the same time? Those would be redundant based on my understanding, though of course my understanding might not be correct ;-)

@josharian
Copy link
Collaborator

Or you saying my PR should respect GO111MODULE by default, but treat GOFUZZ111MODULE as an override?

This was what I had in mind. I see now that it doesn't necessarily make a lot of sense. Sorry.

Two options for fixing the merge conflict:

  • remove GOFUZZ111MODULE, on the grounds that it was always intended to be temporary anyway
  • treat GOFUZZ111MODULE as an override, on the grounds that it does no harm

I'm open to either. This is what I get for merging #271 without taking the time to understand everything.

@mvdan
Copy link
Contributor

mvdan commented Oct 7, 2019

I'm all for option 1; the override is undocumented and temporary. Good gofuzz users who really want modules support are likely pinning the gofuzz version, anyway.

Copy link
Collaborator

@josharian josharian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I took a look over the non-test changes, and a glance over the tests. All looks good. I will finish reviewing when @mvdan and my first round of comments are addressed and the merge conflict is resolved.

README.md Outdated Show resolved Hide resolved
go-fuzz-build/main.go Show resolved Hide resolved
go-fuzz-build/main.go Outdated Show resolved Hide resolved
go-fuzz/main.go Outdated Show resolved Hide resolved
@thepudds
Copy link
Collaborator Author

thepudds commented Oct 7, 2019

I resolved the conflict by removing GOFUZZ111MODULE. (Full disclosure: that was while waiting at the doctor's office, but the diff looks right and travis passed).

One other comment is the current GOFUZZ111MODULE implementation can fail with confusing error messages for some modules depending on how you specify your pkg and fuzz func on the command line. (I think it might be a type checking failed error or similar, but don't recall the exact error).

@mvdan
Copy link
Contributor

mvdan commented Oct 13, 2019

If it's of any help to move things along, I've started forcing module-mode fuzz builds with GOFUZZ111MODULE, and it works fine: mvdan/sh@eae16fe

…e vendor test (#3)

* travis: attempt to install cmd/testscript

* testing: initial check of 'go-fuzz-build -h' output to see if any testscripts work

* testing: change name of first test script

* travis: check if the 'testscript' cmd seems to function at all.

* testing: use the exec command to invoke 'go-fuzz-build -h'

* testing: create initially failing test case for v2 modules

* travis: run testscript for v2 modules

* testing: remember to use 'exec' to invoke go-fuzz-build

* testing: adjust comments in v2 module testscript

* go-fuzz-build: preliminary module support

* testing: flip  from an expected failure to an expected pass for a module test

* go-fuzz-build: update comments for preliminary modules support

* go-fuzz: preliminary modules support for go-fuzz itself

* travis: go-fuzz-defs sanity check

* travis: additional temp sanity check

* travis: add more comments, some additional sanity checks in case we need to debug in future

* travis: s/go-fuzz-deps/go-fuzz-dep/

* testing: validate behavior of v2 modules

* testing: renamed fuzz_help.txt

* testing: update travis to use the renamed testscripts

* travis: conditionally set GO111MODULE=auto, and test Go 1.13 rather than 1.11

* testing: validate modules outside GOPATH

* testing: validate modules inside GOPATH

* testing: invoke timeout properly

* testing: preliminary test for vendored modules (not yet supported)

* testing: validate how go-fuzz-dep and go-fuzz-defs are found

* travis: run the latest testscripts for modules testing

* testing: fix typo in mod_outside_gopath.txt file name

* travis: fix typo in file name

* go-fuzz-build: detect -mod=vendor

* testing: validate we get a proper error for -mod=vendor

* readme: describe preliminary modules support

* readme: correct typo in modules support

* readme: adjust modules support section

* readme: tweak wording based on PR review

* go-fuzz: tweak comment wording by removing "preliminary modules support"

* go-fuzz-build: tweak comment wording by removing "preliminary modules support"

* mod_vendor.txt: avoid triggering Go 1.14 auto detection of a vendor directory
@thepudds
Copy link
Collaborator Author

thepudds commented Oct 20, 2019

@josharian @mvdan I attempted to address or respond to each of your comments/questions. PTAL when convenient. Thanks for the feedback!

Copy link
Collaborator

@josharian josharian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking good to me. On another read, I have a few suggested documentation tweaks. And I'd like to hear back from @mvdan on your replies to his questions. Other that than, I'm happy.

README.md Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
README.md Show resolved Hide resolved
@mvdan
Copy link
Contributor

mvdan commented Oct 22, 2019

My comments were more suggestions than concerns per se. All are resolved. :shipit:

@josharian
Copy link
Collaborator

LGTM then. I'll merge as soon as there are no conflicts and CI is green.

@thepudds
Copy link
Collaborator Author

thepudds commented Oct 22, 2019

The prior CI failure looks like travis flaked out on Mac for Go 1.13. (That VM failed to boot; other versions on Mac passed).

Re-triggered travis and they all seem to have passed.

Thanks very much @josharian and @mvdan for the review!!

@josharian josharian merged commit 8cb2038 into dvyukov:master Oct 22, 2019
@mvdan
Copy link
Contributor

mvdan commented Oct 22, 2019

I feel like we need to throw a go-fuzz module support party now :)

@mholt
Copy link

mholt commented Oct 22, 2019

Woohoo! Can't wait to fuzz Caddy 2 😄 Thanks for this everyone!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

go-fuzz-build doesn't work with go modules (go 1.11.2)
6 participants