drop Go 1.21 and start using go/version

Needing to awkwardly treat Go versions as if they were semver
is no longer necessary thanks to go/version being in Go 1.22.0 now.
pull/834/head
Daniel Martí 3 months ago committed by pagran
parent d76bc2eb47
commit ad2ecc7f2f

@ -25,7 +25,7 @@ jobs:
test:
strategy:
matrix:
go-version: [1.21.x, 1.22.x]
go-version: [1.22.x]
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:

@ -1,6 +1,6 @@
module mvdan.cc/garble
go 1.21
go 1.22
require (
github.com/bluekeyes/go-gitdiff v0.7.1

@ -1,6 +1,6 @@
// Code generated by scripts/gen-go-std-tables.sh; DO NOT EDIT.
// Generated from Go version devel go1.23-1400b26852 Thu Feb 8 03:02:00 2024 +0000.
// Generated from Go version go1.22.0.
package main
@ -54,8 +54,8 @@ var runtimeLinknamed = []string{
"syscall",
"syscall/js",
"time",
// Existed in Go 1.21; removed in Go 1.22.
"math/rand",
// The net package linknames to the runtime, not the other way around.
// TODO: support this automatically via our script.
"net",
}
@ -72,7 +72,6 @@ var compilerIntrinsicsPkgs = map[string]bool{
}
var compilerIntrinsicsFuncs = map[string]bool{
"runtime.mulUintptr": true, // Existed in Go 1.21; removed in Go 1.22.
"math.Abs": true,
"math/big.mulWW": true,
"math/bits.Add": true,

@ -1,36 +0,0 @@
From 62c7b9ef34098c1feddb18502331068277479875 Mon Sep 17 00:00:00 2001
From: pagran <pagran@protonmail.com>
Date: Mon, 9 Jan 2023 13:30:00 +0100
Subject: [PATCH 1/3] add custom magic value
---
cmd/link/internal/ld/pcln.go | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/cmd/link/internal/ld/pcln.go b/cmd/link/internal/ld/pcln.go
index aaf8ddef51..e93532e510 100644
--- a/cmd/link/internal/ld/pcln.go
+++ b/cmd/link/internal/ld/pcln.go
@@ -249,6 +249,19 @@ func (state *pclntab) generatePCHeader(ctxt *Link) {
if off != size {
panic(fmt.Sprintf("pcHeader size: %d != %d", off, size))
}
+
+ // Use garble prefix in variable names to minimize collision risk
+ garbleMagicStr := os.Getenv("GARBLE_LINK_MAGIC")
+ if garbleMagicStr == "" {
+ panic("[garble] magic value must be set")
+ }
+ var garbleMagicVal uint32
+ // Use fmt package instead of strconv to avoid importing a new package
+ if _, err := fmt.Sscan(garbleMagicStr, &garbleMagicVal); err != nil {
+ panic(fmt.Errorf("[garble] invalid magic value %s: %v", garbleMagicStr, err))
+ }
+
+ header.SetUint32(ctxt.Arch, 0, garbleMagicVal)
}
state.pcheader = state.addGeneratedSym(ctxt, "runtime.pcheader", size, writeHeader)
--
2.40.1

@ -1,86 +0,0 @@
From 1e3895a863cb122b8262b5bf51a2984998f0fd3e Mon Sep 17 00:00:00 2001
From: pagran <pagran@protonmail.com>
Date: Mon, 9 Jan 2023 13:30:36 +0100
Subject: [PATCH 2/3] add unexported function name removing
---
cmd/link/internal/ld/pcln.go | 44 +++++++++++++++++++++++++++++++++++-
1 file changed, 43 insertions(+), 1 deletion(-)
diff --git a/cmd/link/internal/ld/pcln.go b/cmd/link/internal/ld/pcln.go
index e93532e510..8b670135de 100644
--- a/cmd/link/internal/ld/pcln.go
+++ b/cmd/link/internal/ld/pcln.go
@@ -4,6 +4,11 @@
package ld
+import (
+ "strings"
+ "unicode"
+)
+
import (
"cmd/internal/goobj"
"cmd/internal/objabi"
@@ -301,19 +306,56 @@ func walkFuncs(ctxt *Link, funcs []loader.Sym, f func(loader.Sym)) {
func (state *pclntab) generateFuncnametab(ctxt *Link, funcs []loader.Sym) map[loader.Sym]uint32 {
nameOffsets := make(map[loader.Sym]uint32, state.nfunc)
+ garbleTiny := os.Getenv("GARBLE_LINK_TINY") == "true"
+
// Write the null terminated strings.
writeFuncNameTab := func(ctxt *Link, s loader.Sym) {
symtab := ctxt.loader.MakeSymbolUpdater(s)
+ if garbleTiny {
+ symtab.AddStringAt(0, "")
+ }
+
for s, off := range nameOffsets {
+ if garbleTiny && off == 0 {
+ continue
+ }
symtab.AddCStringAt(int64(off), ctxt.loader.SymName(s))
}
}
// Loop through the CUs, and calculate the size needed.
var size int64
+
+ if garbleTiny {
+ size = 1 // first byte is reserved for empty string used for all non-exportable method names
+ }
+ // Kinds of SymNames found in the wild:
+ //
+ // * reflect.Value.CanAddr
+ // * reflect.(*Value).String
+ // * reflect.w6cEoKc
+ // * internal/abi.(*RegArgs).IntRegArgAddr
+ // * type:.eq.runtime.special
+ // * runtime/internal/atomic.(*Pointer[go.shape.string]).Store
+ //
+ // Checking whether the first rune after the last dot is uppercase seems enough.
+ isExported := func(name string) bool {
+ for _, r := range name[strings.LastIndexByte(name, '.')+1:] {
+ return unicode.IsUpper(r)
+ }
+ return false
+ }
+
walkFuncs(ctxt, funcs, func(s loader.Sym) {
+ name := ctxt.loader.SymName(s)
+
+ if garbleTiny && !isExported(name) {
+ nameOffsets[s] = 0 // redirect name to empty string
+ return
+ }
+
nameOffsets[s] = uint32(size)
- size += int64(len(ctxt.loader.SymName(s)) + 1) // NULL terminate
+ size += int64(len(name) + 1) // NULL terminate
})
state.funcnametab = state.addGeneratedSym(ctxt, "runtime.funcnametab", size, writeFuncNameTab)
--
2.40.1

@ -1,43 +0,0 @@
From b5524a7c84a994b43027723b4bb05441db365a1e Mon Sep 17 00:00:00 2001
From: pagran <pagran@protonmail.com>
Date: Sat, 14 Jan 2023 21:36:16 +0100
Subject: [PATCH 3/3] add entryOff encryption
---
cmd/link/internal/ld/pcln.go | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/cmd/link/internal/ld/pcln.go b/cmd/link/internal/ld/pcln.go
index 8b670135de..e4ccfc9330 100644
--- a/cmd/link/internal/ld/pcln.go
+++ b/cmd/link/internal/ld/pcln.go
@@ -779,6 +779,26 @@ func writeFuncs(ctxt *Link, sb *loader.SymbolBuilder, funcs []loader.Sym, inlSym
sb.SetUint32(ctxt.Arch, dataoff, uint32(ldr.SymValue(fdsym)-gofuncBase))
}
}
+
+ // Moving next code higher is not recommended.
+ // Only at the end of the current function no edits between go versions
+ garbleEntryOffKeyStr := os.Getenv("GARBLE_LINK_ENTRYOFF_KEY")
+ if garbleEntryOffKeyStr == "" {
+ panic("[garble] entryOff key must be set")
+ }
+ var garbleEntryOffKey uint32
+ // Use fmt package instead of strconv to avoid importing a new package
+ if _, err := fmt.Sscan(garbleEntryOffKeyStr, &garbleEntryOffKey); err != nil {
+ panic(fmt.Errorf("[garble] invalid entryOff key %s: %v", garbleEntryOffKeyStr, err))
+ }
+
+ garbleData := sb.Data()
+ for _, off := range startLocations {
+ entryOff := ctxt.Arch.ByteOrder.Uint32(garbleData[off:])
+ nameOff := ctxt.Arch.ByteOrder.Uint32(garbleData[off+4:])
+
+ sb.SetUint32(ctxt.Arch, int64(off), entryOff^(nameOff*garbleEntryOffKey))
+ }
}
// pclntab initializes the pclntab symbol with
--
2.40.1

@ -20,6 +20,7 @@ import (
"go/parser"
"go/token"
"go/types"
"go/version"
"io"
"io/fs"
"log"
@ -40,7 +41,6 @@ import (
"golang.org/x/exp/maps"
"golang.org/x/exp/slices"
"golang.org/x/mod/module"
"golang.org/x/mod/semver"
"golang.org/x/tools/go/ast/astutil"
"golang.org/x/tools/go/ssa"
"mvdan.cc/garble/internal/ctrlflow"
@ -267,28 +267,21 @@ type errJustExit int
func (e errJustExit) Error() string { return fmt.Sprintf("exit: %d", e) }
func goVersionOK() bool {
// TODO(mvdan): use go/version once we can require Go 1.22 or later: https://go.dev/issue/62039
const (
minGoVersionSemver = "v1.21.0"
suggestedGoVersion = "1.21"
)
const minGoVersion = "go1.22"
// rxVersion looks for a version like "go1.2" or "go1.2.3"
// rxVersion looks for a version like "go1.2" or "go1.2.3" in `go env GOVERSION`.
rxVersion := regexp.MustCompile(`go\d+\.\d+(?:\.\d+)?`)
toolchainVersionFull := sharedCache.GoEnv.GOVERSION
toolchainVersion := rxVersion.FindString(toolchainVersionFull)
if toolchainVersion == "" {
// Go 1.15.x and older do not have GOVERSION yet.
// We could go the extra mile and fetch it via 'go toolchainVersion',
// but we'd have to error anyway.
fmt.Fprintf(os.Stderr, "Go version is too old; please upgrade to Go %s or newer\n", suggestedGoVersion)
sharedCache.GoVersion = rxVersion.FindString(toolchainVersionFull)
if sharedCache.GoVersion == "" {
// Go 1.15.x and older did not have GOVERSION yet; they are too old anyway.
fmt.Fprintf(os.Stderr, "Go version is too old; please upgrade to %s or newer\n", minGoVersion)
return false
}
sharedCache.GoVersionSemver = "v" + strings.TrimPrefix(toolchainVersion, "go")
if semver.Compare(sharedCache.GoVersionSemver, minGoVersionSemver) < 0 {
fmt.Fprintf(os.Stderr, "Go version %q is too old; please upgrade to Go %s or newer\n", toolchainVersionFull, suggestedGoVersion)
if version.Compare(sharedCache.GoVersion, minGoVersion) < 0 {
fmt.Fprintf(os.Stderr, "Go version %q is too old; please upgrade to %s or newer\n", toolchainVersionFull, minGoVersion)
return false
}
@ -304,10 +297,9 @@ func goVersionOK() bool {
// Fall back to not performing the check against the toolchain version.
return true
}
builtVersionSemver := "v" + strings.TrimPrefix(builtVersion, "go")
if semver.Compare(builtVersionSemver, sharedCache.GoVersionSemver) < 0 {
if version.Compare(builtVersion, sharedCache.GoVersion) < 0 {
fmt.Fprintf(os.Stderr, `
garble was built with %q and is being used with %q; rebuild it with a command like:
garble was built with %q and can't be used with the newer %q; rebuild it with a command like:
go install mvdan.cc/garble@latest
`[1:], builtVersionFull, toolchainVersionFull)
return false

@ -46,8 +46,8 @@ var runtimeLinknamed = []string{
$(for path in ${runtime_linknamed}; do
echo "\"${path}\"",
done)
// Existed in Go 1.21; removed in Go 1.22.
"math/rand",
// The net package linknames to the runtime, not the other way around.
// TODO: support this automatically via our script.
"net",
}
@ -58,7 +58,6 @@ done)
}
var compilerIntrinsicsFuncs = map[string]bool{
"runtime.mulUintptr": true, // Existed in Go 1.21; removed in Go 1.22.
$(while read path name; do
echo "\"${path}.${name}\": true,"
done <<<"${compiler_intrinsics_table}")

@ -18,7 +18,6 @@ import (
"time"
"golang.org/x/mod/module"
"golang.org/x/mod/semver"
)
//go:generate ./scripts/gen-go-std-tables.sh
@ -50,12 +49,12 @@ type sharedCacheType struct {
GOGARBLE string
// GoVersionSemver is a semver-compatible version of the Go toolchain
// currently being used, as reported by "go env GOVERSION".
// GoVersion is a version of the Go toolchain currently being used,
// as reported by "go env GOVERSION" and compatible with go/version.
// Note that the version of Go that built the garble binary might be newer.
// Also note that a devel version like "go1.22-231f290e51" is
// currently represented as "v1.22".
GoVersionSemver string
// currently represented as "go1.22", as the suffix is ignored by go/version.
GoVersion string
// Filled directly from "go env".
// Keep in sync with fetchGoEnv.
@ -267,8 +266,6 @@ func appendListedPackages(packages []string, mainBuild bool) error {
// Some packages in runtimeLinknamed need a build tag to be importable,
// like crypto/internal/boring/fipstls with boringcrypto,
// so any pkg.Error should be ignored when the build tag isn't set.
} else if pkg.ImportPath == "math/rand/v2" && semver.Compare(sharedCache.GoVersionSemver, "v1.22") < 0 {
// added in Go 1.22, so Go 1.21 runs into a "not found" error.
} else {
if pkgErrors.Len() > 0 {
pkgErrors.WriteString("\n")

@ -33,7 +33,7 @@ binsubstr main$exe 'addJmp' 'AddImpl'
-- go.mod --
module test/with.many.dots/main
go 1.21
go 1.22
-- main.go --
package main

@ -18,7 +18,7 @@ cmp stderr main.stderr
-- go.mod --
module test/main
go 1.21
go 1.22
-- main.go --
package main

@ -59,7 +59,7 @@ binsubstr main$exe 'garble_main.go' 'globalVar' 'globalFunc' $gofullversion
-- go.mod --
module test/mainfoo
go 1.21
go 1.22
-- garble_main.go --
package main

@ -28,7 +28,7 @@ cmp stderr main.stderr
-- go.mod --
module test/main
go 1.21
go 1.22
-- main.go --
package main

@ -29,7 +29,7 @@ binsubstr main$exe 'privateAdd'
-- go.mod --
module test/main
go 1.21
go 1.22
-- main.go --
package main

@ -31,7 +31,7 @@ exec garble build
-- go.mod --
module test/main
go 1.21
go 1.22
-- main.go --
package main

@ -30,7 +30,7 @@ grep 'func\(int\) int' $WORK/debug/test/main/GARBLE_controlflow.go
-- go.mod --
module test/main
go 1.21
go 1.22
-- garble_main.go --
package main

@ -18,7 +18,7 @@ stderr 'test/main' # we force rebuilds with -debugdir
-- go.mod --
module test/main
go 1.21
go 1.22
-- main.go --
package main

@ -11,7 +11,7 @@ cmp stdout main.stdout
-- go.mod --
module test/main
go 1.21
go 1.22
-- main.go --
package main

@ -46,7 +46,7 @@ exec $NAME/garble$exe build
-- go.mod --
module test/main
go 1.21
go 1.22
-- main.go --
package main

@ -54,7 +54,7 @@ bincmp out_rebuild out
-- go.mod --
module test/main
go 1.21
go 1.22
-- standalone/main.go --
package main

@ -7,30 +7,30 @@ env PATH=${WORK}/.bin${:}${PATH}
# An empty go version.
env TOOLCHAIN_GOVERSION=''
! exec garble build
stderr 'Go version is too old; please upgrade to Go 1\.21 or newer'
stderr 'Go version is too old; please upgrade to go1\.22 or newer'
# We should error on a devel version that's too old.
# Note that they lacked the "goN.M-" prefix.
env TOOLCHAIN_GOVERSION='devel +afb5fca Sun Aug 07 00:00:00 2020 +0000'
! exec garble build
stderr 'Go version is too old; please upgrade to Go 1\.21 or newer'
stderr 'Go version is too old; please upgrade to go1\.22 or newer'
# Another form of old version; with an old "goN.M-" prefix.
env TOOLCHAIN_GOVERSION='devel go1.15-afb5fca Sun Aug 07 00:00:00 2020 +0000'
! exec garble build
stderr 'Go version "devel go1\.15-.*2020.*" is too old; please upgrade to Go 1\.21'
stderr 'Go version "devel go1\.15-.*2020.*" is too old; please upgrade to go1\.22'
# A current devel version should be fine.
# Note that we don't look at devel version timestamps.
env GARBLE_TEST_GOVERSION='go1.21'
env TOOLCHAIN_GOVERSION='devel go1.21-ad97d204f0 Sun Sep 12 16:46:58 2023 +0000'
env GARBLE_TEST_GOVERSION='go1.22'
env TOOLCHAIN_GOVERSION='devel go1.22-ad97d204f0 Sun Sep 12 16:46:58 2023 +0000'
! exec garble build
stderr 'mocking the real build'
# We should error on a stable version that's too old.
env TOOLCHAIN_GOVERSION='go1.14'
! exec garble build
stderr 'Go version "go1\.14" is too old; please upgrade to Go 1\.21 or newer'
stderr 'Go version "go1\.14" is too old; please upgrade to go1\.22 or newer'
# We should accept a future stable version.
# Note that we need to bump the version of Go that supposedly built it, too.
@ -40,45 +40,45 @@ env TOOLCHAIN_GOVERSION='go1.28.2'
stderr 'mocking the real build'
# We should accept custom devel strings.
env TOOLCHAIN_GOVERSION='devel go1.22-somecustomversion'
env TOOLCHAIN_GOVERSION='devel go1.23-somecustomversion'
! exec garble build
stderr 'mocking the real build'
# The current toolchain may be older than the one that built garble.
env GARBLE_TEST_GOVERSION='go1.22'
env TOOLCHAIN_GOVERSION='go1.21.3'
env GARBLE_TEST_GOVERSION='go1.23'
env TOOLCHAIN_GOVERSION='go1.22.3'
! exec garble build
stderr 'mocking the real build'
# The current toolchain may be equal to the one that built garble.
env GARBLE_TEST_GOVERSION='devel go1.21-6673d5d701 Sun Mar 20 16:05:03 2023 +0000'
env TOOLCHAIN_GOVERSION='devel go1.21-6673d5d701 Sun Mar 20 16:05:03 2023 +0000'
env GARBLE_TEST_GOVERSION='devel go1.22-6673d5d701 Sun Mar 20 16:05:03 2023 +0000'
env TOOLCHAIN_GOVERSION='devel go1.22-6673d5d701 Sun Mar 20 16:05:03 2023 +0000'
! exec garble build
stderr 'mocking the real build'
# The current toolchain must not be newer than the one that built garble.
env GARBLE_TEST_GOVERSION='go1.18'
env TOOLCHAIN_GOVERSION='go1.21.1'
env TOOLCHAIN_GOVERSION='go1.22.1'
! exec garble build
stderr 'garble was built with "go1\.18" and is being used with "go1\.21\.1"; rebuild '
stderr 'garble was built with "go1\.18" and can''t be used with the newer "go1\.22\.1"; rebuild '
# We'll error even if the difference is a minor (bugfix) level.
# In practice it probably wouldn't matter, but in theory it could still lead to tricky bugs.
env GARBLE_TEST_GOVERSION='go1.21.11'
env TOOLCHAIN_GOVERSION='go1.21.14'
env GARBLE_TEST_GOVERSION='go1.22.11'
env TOOLCHAIN_GOVERSION='go1.22.14'
! exec garble build
stderr 'garble was built with "go1\.21\.11" and is being used with "go1\.21\.14"; rebuild '
stderr 'garble was built with "go1\.22\.11" and can''t be used with the newer "go1\.22\.14"; rebuild '
# If garble builds itself and is then used, it won't know what version built it.
# As a fallback, we drop the comparison against the toolchain's version.
env GARBLE_TEST_GOVERSION='bogus version'
env TOOLCHAIN_GOVERSION='go1.21.3'
env TOOLCHAIN_GOVERSION='go1.22.3'
! exec garble build
stderr 'mocking the real build'
-- go.mod --
module test/main
go 1.21
go 1.22
-- main.go --
package main

@ -117,6 +117,6 @@ stderr 'usage: garble version'
-- go.mod --
module dummy
go 1.21
go 1.22
-- dummy.go --
package dummy

@ -13,7 +13,7 @@ cmp stdout main.stdout
-- go.mod --
module test/main
go 1.21
go 1.22
-- main.go --
package main

@ -42,7 +42,7 @@ cmp stdout main.stdout
-- go.mod --
module test/main
go 1.21
go 1.22
require (
gopkg.in/garbletest.v2 v2.999.0

@ -12,7 +12,7 @@ cmp stderr main.stderr
-- go.mod --
module test/main
go 1.21
go 1.22
-- main.go --
package main

@ -28,7 +28,7 @@ binsubstr main$exe 'unexportedVersion' 'ExportedUnset' 'v1.22.33' 'garble_replac
-- go.mod --
module domain.test/main
go 1.21
go 1.22
-- main.go --
package main

@ -34,7 +34,7 @@ cmp stderr main.stderr
-- go.mod --
module test/main
go 1.21
go 1.22
-- main.go --
package main

@ -14,7 +14,7 @@ cmp stderr main.stderr
-- go.mod --
module test/main
go 1.21
go 1.22
replace big.chungus/meme => ./big.chungus/meme
@ -149,7 +149,7 @@ func ByteIndex(s string, c byte) int
-- big.chungus/meme/go.mod --
module test/main
go 1.21
go 1.22
-- big.chungus/meme/dante.go --
package meme

@ -8,7 +8,7 @@ imports_missing${/}imports.go:5:8: package test/main/missing is not in std (${GO
-- go.mod --
module test/main
go 1.21
go 1.22
-- broken/broken.go --
package broken

@ -59,7 +59,7 @@ exec garble -literals build std
-- go.mod --
module test/main
go 1.21
go 1.22
-- main.go --
package main

@ -26,7 +26,7 @@ stdout 'build\s*vcs.revision='${HEAD_COMMIT_SHA}
-- go.mod --
module test/main
go 1.21
go 1.22
-- main.go --
package main

@ -26,7 +26,7 @@ cmp stderr main.stderr
-- go.mod --
module test/main
go 1.21
go 1.22
-- plugin/main.go --
package main

@ -16,7 +16,7 @@ stdout 'varPositions is sorted'
-- go.mod --
module test/main
go 1.21
go 1.22
-- garble_main.go --
package main

@ -14,7 +14,7 @@ cmp stdout main.stdout
-- go.mod --
module test/main
go 1.21
go 1.22
-- garble_main.go --
package main

@ -46,7 +46,7 @@ cmp stdout main-literals.stderr
-- go.mod --
module test/main
go 1.21
go 1.22
-- long_main.go --
package main

@ -14,7 +14,7 @@ stdout 'garble_main\.go 9$'
-- go.mod --
module test/main
go 1.21
go 1.22
-- garble_main.go --
package main

@ -32,7 +32,7 @@ cd ..
-- mod1/go.mod --
module test/main/mod1
go 1.21
go 1.22
require gopkg.in/garbletest.v2 v2.999.0
@ -52,7 +52,7 @@ func main() { garbletest.Test() }
-- mod2/go.mod --
module test/main/mod2
go 1.21
go 1.22
require gopkg.in/garbletest.v2 v2.999.0

@ -97,7 +97,7 @@ cmp stderr importedpkg.stderr
-- go.mod --
module test/main
go 1.21
go 1.22
-- main.go --
package main

@ -16,7 +16,7 @@ binsubstr main$exe 'globalVar' # 'globalType' matches on some, but not all, plat
-- extra/go.mod --
module private.source/extra
go 1.21
go 1.22
-- extra/extra.go --
package extra
@ -26,7 +26,7 @@ func Func() string {
-- go.mod --
module test/main
go 1.21
go 1.22
// We include an extra module to obfuscate, included in the same original source
// code via a replace directive.

@ -52,7 +52,7 @@ stdout 'package bar_test, func name: test/bar\.OriginalFuncName'
-- go.mod --
module test/bar
go 1.21
go 1.22
-- bar.go --
package bar

@ -27,7 +27,7 @@ stderr 'funcStructExported false funcStructUnexported false'
-- go.mod --
module test/main
go 1.21
go 1.22
-- garble_main.go --
package main

@ -3,7 +3,7 @@ exec garble build
-- go.mod --
module test/main
go 1.21
go 1.22
-- garble_main.go --
package main

Loading…
Cancel
Save