diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8611e8b..1f73049 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,7 +10,7 @@ jobs: test: strategy: matrix: - go-version: [1.16.x, 1.17.x] + go-version: [1.17.x] platform: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.platform }} steps: diff --git a/README.md b/README.md index 72395bf..2ed3fed 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ go install mvdan.cc/garble@latest -Obfuscate Go code by wrapping the Go toolchain. Requires Go 1.16 or later. +Obfuscate Go code by wrapping the Go toolchain. Requires Go 1.17 or later. garble build [build flags] [packages] @@ -41,12 +41,12 @@ what packages to obfuscate, set `GOPRIVATE`, documented at `go help private`. Note that commands like `garble build` will use the `go` version found in your `$PATH`. To use different versions of Go, you can [install them](https://golang.org/doc/manage-install#installing-multiple) -and set up `$PATH` with them. For example, for Go 1.16.1: +and set up `$PATH` with them. For example, for Go 1.17.1: ```sh -$ go install golang.org/dl/go1.16.1@latest -$ go1.16.1 download -$ PATH=$(go1.16.1 env GOROOT)/bin:${PATH} garble build +$ go install golang.org/dl/go1.17.1@latest +$ go1.17.1 download +$ PATH=$(go1.17.1 env GOROOT)/bin:${PATH} garble build ``` ### Literal obfuscation diff --git a/go.mod b/go.mod index feed7db..f89d920 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module mvdan.cc/garble -go 1.16 +go 1.17 require ( github.com/google/go-cmp v0.5.6 @@ -8,3 +8,9 @@ require ( golang.org/x/mod v0.5.0 golang.org/x/tools v0.1.5 ) + +require ( + github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e // indirect + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + gopkg.in/errgo.v2 v2.1.0 // indirect +) diff --git a/main.go b/main.go index 6ae9c95..00940c1 100644 --- a/main.go +++ b/main.go @@ -23,11 +23,11 @@ import ( "os" "os/exec" "path/filepath" + "regexp" "runtime" "runtime/debug" "strconv" "strings" - "time" "unicode" "unicode/utf8" @@ -248,15 +248,12 @@ func (e errJustExit) Error() string { return fmt.Sprintf("exit: %d", e) } func goVersionOK() bool { const ( - minGoVersionSemver = "v1.16.0" - suggestedGoVersion = "1.16.x" - - gitTimeFormat = "Mon Jan 2 15:04:05 2006 -0700" + minGoVersionSemver = "v1.17.0" + suggestedGoVersion = "1.17.x" ) - // Go 1.16 was released on Febuary 16th, 2021. - minGoVersionDate := time.Date(2021, 2, 16, 0, 0, 0, 0, time.UTC) - version := cache.GoEnv.GOVERSION + rxVersion := regexp.MustCompile(`go\d+\.\d+(\.\d)?`) + version := rxVersion.FindString(cache.GoEnv.GOVERSION) if version == "" { // Go 1.15.x and older do not have GOVERSION yet. // We could go the extra mile and fetch it via 'go version', @@ -265,37 +262,6 @@ func goVersionOK() bool { return false } - if strings.HasPrefix(version, "devel ") { - commitAndDate := strings.TrimPrefix(version, "devel ") - // Remove commit hash and architecture from version - startDateIdx := strings.IndexByte(commitAndDate, ' ') + 1 - if startDateIdx < 0 { - // Custom version; assume the user knows what they're doing. - // TODO: cover this in a test - return true - } - - // TODO: once we support Go 1.17 and later, use the major Go - // version included in its devel versions: - // - // go version devel go1.17-8518aac314 ... - - date := commitAndDate[startDateIdx:] - - versionDate, err := time.Parse(gitTimeFormat, date) - if err != nil { - // Custom version; assume the user knows what they're doing. - return true - } - - if versionDate.After(minGoVersionDate) { - return true - } - - fmt.Fprintf(os.Stderr, "Go version %q is too old; please upgrade to Go %s or a newer devel version\n", version, suggestedGoVersion) - return false - } - versionSemver := "v" + strings.TrimPrefix(version, "go") if semver.Compare(versionSemver, minGoVersionSemver) < 0 { fmt.Fprintf(os.Stderr, "Go version %q is too old; please upgrade to Go %s\n", version, suggestedGoVersion) @@ -369,23 +335,6 @@ func mainErr(args []string) error { toolexecImportPath := os.Getenv("TOOLEXEC_IMPORTPATH") - // Workaround for https://github.com/golang/go/issues/44963. - // TODO(mvdan): remove once we only support Go 1.17 and later. - if tool == "compile" && !strings.Contains(toolexecImportPath, ".test]") { - isTestPkg := false - _, paths := splitFlagsFromFiles(args, ".go") - for _, path := range paths { - if strings.HasSuffix(path, "_test.go") { - isTestPkg = true - break - } - } - if isTestPkg { - forPkg := strings.TrimSuffix(toolexecImportPath, "_test") - toolexecImportPath = fmt.Sprintf("%s [%s.test]", toolexecImportPath, forPkg) - } - } - curPkg = cache.ListedPackages[toolexecImportPath] if curPkg == nil { return fmt.Errorf("TOOLEXEC_IMPORTPATH not found in listed packages: %s", toolexecImportPath) @@ -673,10 +622,9 @@ func transformCompile(args []string) ([]string, error) { return nil, err } - if (curPkg.ImportPath == "runtime" && opts.Tiny) || curPkg.ImportPath == "runtime/internal/sys" { - // Even though these packages aren't private, we will still process - // them later to remove build information and strip code from the - // runtime. However, we only want flags to work on private packages. + if curPkg.ImportPath == "runtime" && opts.Tiny { + // When using -tiny, we call stripRuntime below. + // We don't want -literals and -debugdir to apply, though. opts.GarbleLiterals = false opts.DebugDir = "" } else if !curPkg.Private { @@ -706,29 +654,9 @@ func transformCompile(args []string) ([]string, error) { for i, file := range files { name := filepath.Base(paths[i]) - switch curPkg.ImportPath { - case "runtime": + if curPkg.ImportPath == "runtime" && opts.Tiny { // strip unneeded runtime code stripRuntime(name, file) - case "runtime/internal/sys": - // The first declaration in zversion.go contains the Go - // version as follows. Replace it here, since the - // linker's -X does not work with constants. - // - // const TheVersion = `devel ...` - // - // Don't touch the source in any other way. - // TODO: remove once we only support Go 1.17 and later, - // as from that point we can just rely on linking -X flags. - if name != "zversion.go" { - break - } - spec := file.Decls[0].(*ast.GenDecl).Specs[0].(*ast.ValueSpec) - if len(spec.Names) != 1 || spec.Names[0].Name != "TheVersion" { - break - } - lit := spec.Values[0].(*ast.BasicLit) - lit.Value = "`unknown`" } if strings.HasPrefix(name, "_cgo_") { // Don't obfuscate cgo code, since it's generated and it gets messy. @@ -848,7 +776,7 @@ func (tf *transformer) handleDirectives(comments []*ast.CommentGroup) { // Once we support go:linkname well and once we can obfuscate the runtime // package, this entire map can likely go away. // -// The list was obtained via scripts/runtime-related.sh on Go 1.16. +// The list was obtained via scripts/runtime-related.sh on Go 1.17. var runtimeRelated = map[string]bool{ "bufio": true, "bytes": true, @@ -861,9 +789,12 @@ var runtimeRelated = map[string]bool{ "fmt": true, "hash": true, "hash/crc32": true, + "internal/abi": true, "internal/bytealg": true, "internal/cpu": true, "internal/fmtsort": true, + "internal/goexperiment": true, + "internal/itoa": true, "internal/nettrace": true, "internal/oserror": true, "internal/poll": true, @@ -910,11 +841,6 @@ var runtimeRelated = map[string]bool{ "unsafe": true, "vendor/golang.org/x/net/dns/dnsmessage": true, "vendor/golang.org/x/net/route": true, - - // Manual additions for Go 1.17 as of June 2021. - "internal/abi": true, - "internal/itoa": true, - "internal/goexperiment": true, } // isPrivate checks if a package import path should be considered private, @@ -1791,7 +1717,7 @@ func alterTrimpath(flags []string) []string { return flagSetValue(flags, "-trimpath", sharedTempDir+"=>;"+trimpath) } -// buildFlags is obtained from 'go help build' as of Go 1.16. +// buildFlags is obtained from 'go help build' as of Go 1.17. var buildFlags = map[string]bool{ "-a": true, "-n": true, @@ -1819,7 +1745,7 @@ var buildFlags = map[string]bool{ "-overlay": true, } -// booleanFlags is obtained from 'go help build' and 'go help testflag' as of Go 1.16. +// booleanFlags is obtained from 'go help build' and 'go help testflag' as of Go 1.17. var booleanFlags = map[string]bool{ // Shared build flags. "-a": true, diff --git a/runtime_strip.go b/runtime_strip.go index cfc5a28..4dd6af0 100644 --- a/runtime_strip.go +++ b/runtime_strip.go @@ -139,8 +139,8 @@ func stripRuntime(filename string, file *ast.File) { switch filename { case "runtime1.go": - // On Go 1.16.x, the code above results in runtime1.go having an - // unused import. Mark it as used via "var _ = pkg.Func". + // On Go 1.17.x, the code above results in runtime1.go having an + // unused import. Make it an underscore import. // If this is a recurring problem, we could go for a more // generic solution like x/tools/imports. for _, imp := range file.Imports { diff --git a/testdata/mod/rsc.io_sampler_v1.99.99.txt b/testdata/mod/rsc.io_sampler_v1.99.99.txt index 547364e..e89cacc 100644 --- a/testdata/mod/rsc.io_sampler_v1.99.99.txt +++ b/testdata/mod/rsc.io_sampler_v1.99.99.txt @@ -1,4 +1,4 @@ -rsc.io/sampler@v1.99.99 +module rsc.io/sampler@v1.99.99 -- .mod -- module "rsc.io/sampler" diff --git a/testdata/mod/rsc.io_testonly_v1.0.0.txt b/testdata/mod/rsc.io_testonly_v1.0.0.txt new file mode 100644 index 0000000..dfb8ca2 --- /dev/null +++ b/testdata/mod/rsc.io_testonly_v1.0.0.txt @@ -0,0 +1,9 @@ +rsc.io/testonly v1.0.0 +written by hand + +-- .mod -- +module rsc.io/testonly +-- .info -- +{"Version":"v1.0.0"} +-- testonly.go -- +package testonly diff --git a/testdata/scripts/asm.txt b/testdata/scripts/asm.txt index 9f77c9e..3584a19 100644 --- a/testdata/scripts/asm.txt +++ b/testdata/scripts/asm.txt @@ -20,7 +20,7 @@ binsubstr main$exe 'privateAdd' 'PublicAdd' -- go.mod -- module test/main -go 1.16 +go 1.17 -- main.go -- package main diff --git a/testdata/scripts/basic.txt b/testdata/scripts/basic.txt index 228a858..32062eb 100644 --- a/testdata/scripts/basic.txt +++ b/testdata/scripts/basic.txt @@ -58,7 +58,7 @@ binsubstr main$exe 'garble_main.go' 'globalVar' 'globalFunc' $gofullversion -- go.mod -- module test/mainfoo -go 1.16 +go 1.17 -- garble_main.go -- package main diff --git a/testdata/scripts/cgo.txt b/testdata/scripts/cgo.txt index 98c4786..00b5bde 100644 --- a/testdata/scripts/cgo.txt +++ b/testdata/scripts/cgo.txt @@ -26,7 +26,7 @@ cmp stdout main.stdout -- go.mod -- module test/main -go 1.16 +go 1.17 -- main.go -- package main diff --git a/testdata/scripts/crossbuild.txt b/testdata/scripts/crossbuild.txt index 6a0c3b9..1ad0b14 100644 --- a/testdata/scripts/crossbuild.txt +++ b/testdata/scripts/crossbuild.txt @@ -17,7 +17,7 @@ garble build -- go.mod -- module test/main -go 1.16 +go 1.17 -- main.go -- package main diff --git a/testdata/scripts/debugdir.txt b/testdata/scripts/debugdir.txt index 8b7368b..e21758d 100644 --- a/testdata/scripts/debugdir.txt +++ b/testdata/scripts/debugdir.txt @@ -18,7 +18,7 @@ stderr 'test/main' # we force rebuilds with -debugdir -- go.mod -- module test/main -go 1.16 +go 1.17 -- main.go -- package main diff --git a/testdata/scripts/embed.txt b/testdata/scripts/embed.txt index 38dfc0e..2c885f8 100644 --- a/testdata/scripts/embed.txt +++ b/testdata/scripts/embed.txt @@ -14,7 +14,7 @@ cmp stdout main.stdout -- go.mod -- module test/main -go 1.16 +go 1.17 -- main.go -- package main diff --git a/testdata/scripts/goprivate.txt b/testdata/scripts/goprivate.txt index 1b89573..fe771e6 100644 --- a/testdata/scripts/goprivate.txt +++ b/testdata/scripts/goprivate.txt @@ -32,7 +32,7 @@ bincmp out_rebuild out -- go.mod -- module test/main -go 1.16 +go 1.17 -- standalone/main.go -- package main diff --git a/testdata/scripts/goversion.txt b/testdata/scripts/goversion.txt index 0e73997..444dfec 100644 --- a/testdata/scripts/goversion.txt +++ b/testdata/scripts/goversion.txt @@ -7,38 +7,44 @@ env PATH=${WORK}/.bin${:}${PATH} # An empty go version. env GOVERSION='' ! garble build -stderr 'Go version is too old' +stderr 'Go version is too old; please upgrade to Go 1.17.x or a newer devel version' # We should error on a devel version that's too old. +# Note that they lacked the "goN.M-" prefix. env GOVERSION='devel +afb5fca Sun Aug 07 00:00:00 2020 +0000' ! garble build -stderr 'Go version.*Aug 07.*too old; please upgrade to Go 1.16.x or a newer devel version' +stderr 'Go version is too old; please upgrade to Go 1.17.x or a newer devel version' -# A future devel timestamp should be fine. -env GOVERSION='devel +afb5fca Sun Sep 13 07:54:42 2021 +0000' +# Another form of old version; with an old "goN.M-" prefix. +env GOVERSION='devel go1.15-afb5fca Sun Aug 07 00:00:00 2020 +0000' +! garble build +stderr 'Go version "go1.15" is too old; please upgrade to Go 1.17.x' + +# A current devel version should be fine +env GOVERSION='devel go1.18-ad97d204f0 Sun Sep 12 16:46:58 2021 +0000' ! garble build stderr 'mocking the real build' # We should error on a stable version that's too old. env GOVERSION='go1.14' ! garble build -stderr 'Go version.*go1.14.*too old; please upgrade to Go 1.16.x' +stderr 'Go version "go1.14" is too old; please upgrade to Go 1.17.x' ! stderr 'or a newer devel version' # We should accept a future stable version. -env GOVERSION='go1.16.2' +env GOVERSION='go1.18.2' ! garble build stderr 'mocking the real build' # We should accept custom devel strings. -env GOVERSION='devel somecustomversion' +env GOVERSION='devel go1.18-somecustomversion' ! garble build stderr 'mocking the real build' -- go.mod -- module test/main -go 1.16 +go 1.17 -- main.go -- package main diff --git a/testdata/scripts/implement.txt b/testdata/scripts/implement.txt index 324733e..1695600 100644 --- a/testdata/scripts/implement.txt +++ b/testdata/scripts/implement.txt @@ -16,7 +16,7 @@ cmp stdout main.stdout -- go.mod -- module test/main -go 1.16 +go 1.17 -- main.go -- package main diff --git a/testdata/scripts/imports.txt b/testdata/scripts/imports.txt index 3a4813f..90e614a 100644 --- a/testdata/scripts/imports.txt +++ b/testdata/scripts/imports.txt @@ -44,11 +44,17 @@ cmp stdout main.stdout -- go.mod -- module test/main -go 1.16 +go 1.17 require ( - rsc.io/quote v1.5.2 gopkg.in/garbletest.v2 v2.999.0 + rsc.io/quote v1.5.2 +) + +require ( + golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect + rsc.io/sampler v1.3.0 // indirect + rsc.io/testonly v1.0.0 // indirect ) -- go.sum -- golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:pvCbr/wm8HzDD3fVywevekufpn6tCGPY3spdHeZJEsw= @@ -59,6 +65,8 @@ rsc.io/quote v1.5.2 h1:3fEykkD9k7lYzXqCYrwGAf7iNhbk4yCjHmKBN9td4L0= rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= rsc.io/sampler v1.3.0 h1:HLGR/BgEtI3r0uymSP/nl2uPLsUnNJX8toRyhfpBTII= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +rsc.io/testonly v1.0.0 h1:K/VWHdO+Jv7woUXG0GzVNx1czBXUt3Ib1deaMn+xk64= +rsc.io/testonly v1.0.0/go.mod h1:OqmGbIFOcF+XrFReLOGZ6BhMM7uMBiQwZsyNmh74SzY= -- garble_main.go -- package main diff --git a/testdata/scripts/init.txt b/testdata/scripts/init.txt index f3364d2..1a15df7 100644 --- a/testdata/scripts/init.txt +++ b/testdata/scripts/init.txt @@ -13,7 +13,7 @@ cmp stderr main.stderr -- go.mod -- module test/main -go 1.16 +go 1.17 -- main.go -- package main diff --git a/testdata/scripts/ldflags.txt b/testdata/scripts/ldflags.txt index 9c6ee60..bc2b347 100644 --- a/testdata/scripts/ldflags.txt +++ b/testdata/scripts/ldflags.txt @@ -23,7 +23,7 @@ binsubstr main$exe 'unexportedVersion' -- go.mod -- module domain.test/main -go 1.16 +go 1.17 -- main.go -- package main diff --git a/testdata/scripts/linkname.txt b/testdata/scripts/linkname.txt index d6cc144..b0cd89c 100644 --- a/testdata/scripts/linkname.txt +++ b/testdata/scripts/linkname.txt @@ -15,7 +15,7 @@ cmp stderr main.stderr -- go.mod -- module test/main -go 1.16 +go 1.17 replace big.chungus/meme => ./big.chungus/meme @@ -99,7 +99,7 @@ func ByteIndex(s string, c byte) int -- big.chungus/meme/go.mod -- module test/main -go 1.16 +go 1.17 -- big.chungus/meme/dante.go -- package meme diff --git a/testdata/scripts/literals.txt b/testdata/scripts/literals.txt index 0e2b39c..edbd31b 100644 --- a/testdata/scripts/literals.txt +++ b/testdata/scripts/literals.txt @@ -57,7 +57,7 @@ garble -literals build std -- go.mod -- module test/main -go 1.16 +go 1.17 -- main.go -- package main diff --git a/testdata/scripts/modinfo.txt b/testdata/scripts/modinfo.txt index 07c6020..fe5c261 100644 --- a/testdata/scripts/modinfo.txt +++ b/testdata/scripts/modinfo.txt @@ -15,7 +15,7 @@ binsubstr main$exe '(devel)' -- go.mod -- module test/main -go 1.16 +go 1.17 -- main.go -- package main diff --git a/testdata/scripts/plugin.txt b/testdata/scripts/plugin.txt index 762eabb..a41ca20 100644 --- a/testdata/scripts/plugin.txt +++ b/testdata/scripts/plugin.txt @@ -29,7 +29,7 @@ cmp stderr main.stderr -- go.mod -- module test/main -go 1.16 +go 1.17 -- plugin/main.go -- package main diff --git a/testdata/scripts/position.txt b/testdata/scripts/position.txt index e406765..571ce27 100644 --- a/testdata/scripts/position.txt +++ b/testdata/scripts/position.txt @@ -19,7 +19,7 @@ stdout 'varPositions is sorted' -- go.mod -- module test/main -go 1.16 +go 1.17 -- garble_main.go -- package main diff --git a/testdata/scripts/reflect.txt b/testdata/scripts/reflect.txt index b6a5697..77255b6 100644 --- a/testdata/scripts/reflect.txt +++ b/testdata/scripts/reflect.txt @@ -17,7 +17,7 @@ cmp stdout main.stdout -- go.mod -- module test/main -go 1.16 +go 1.17 -- garble_main.go -- package main diff --git a/testdata/scripts/reverse.txt b/testdata/scripts/reverse.txt index 3ee82b6..0cf9dad 100644 --- a/testdata/scripts/reverse.txt +++ b/testdata/scripts/reverse.txt @@ -50,7 +50,7 @@ cmp stdout main-literals.stderr -- go.mod -- module test/main -go 1.16 +go 1.17 -- main.go -- package main diff --git a/testdata/scripts/seed.txt b/testdata/scripts/seed.txt index 0f04b55..363ab88 100644 --- a/testdata/scripts/seed.txt +++ b/testdata/scripts/seed.txt @@ -78,7 +78,7 @@ exec ./main$exe funcName -- go.mod -- module test/main -go 1.16 +go 1.17 -- main.go -- package main diff --git a/testdata/scripts/syntax.txt b/testdata/scripts/syntax.txt index c44f87a..74c1da3 100644 --- a/testdata/scripts/syntax.txt +++ b/testdata/scripts/syntax.txt @@ -19,7 +19,7 @@ binsubstr main$exe 'globalVar' # 'globalType' matches on some, but not all, plat -- extra/go.mod -- module private.source/extra -go 1.16 +go 1.17 -- extra/extra.go -- package extra @@ -29,7 +29,7 @@ func Func() string { -- go.mod -- module test/main -go 1.16 +go 1.17 // We include an extra module to obfuscate, included in the same original source // code via a replace directive. diff --git a/testdata/scripts/test.txt b/testdata/scripts/test.txt index 0e3e08e..c7addd3 100644 --- a/testdata/scripts/test.txt +++ b/testdata/scripts/test.txt @@ -41,7 +41,7 @@ stdout 'package bar_test, func name: test/bar\.OriginalFuncName' -- go.mod -- module test/bar -go 1.16 +go 1.17 -- bar.go -- package bar diff --git a/testdata/scripts/tiny.txt b/testdata/scripts/tiny.txt index 6040da6..f017cbc 100644 --- a/testdata/scripts/tiny.txt +++ b/testdata/scripts/tiny.txt @@ -26,7 +26,7 @@ stderr 'panic: oh noes' -- go.mod -- module test/main -go 1.16 +go 1.17 -- garble_main.go -- package main