You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
garble/testdata/script/seed.txtar

234 lines
6.6 KiB
Plaintext

# Note that in this test we use "! bincmp" on plaintext output files,
# as a workaround for "cmp" not supporting "! cmp".
# TODO: now that obfuscation with -seed is deterministic,
# can we just rely on the regular "cmp" with fixed output files?
# TODO: consider setting these seeds globally,
# so we can reuse them across tests and make better use of the shared build cache.
env SEED1=OQg9kACEECQ
env SEED2=NruiDmVz6/s
# Check the binary with a given base64 encoded seed.
exec garble -seed=${SEED1} build
exec ./main$exe
cmp stderr main.stderr
binsubstr main$exe 'teststring' 'imported var value'
! binsubstr main$exe 'ImportedVar' ${SEED1}
[short] stop # the extra checks are relatively expensive
exec ./main$exe test/main/imported
cp stderr importedpkg-seed-static-1
# Also check that the binary is reproducible.
# No packages should be rebuilt either, thanks to the build cache.
cp main$exe main_seed1$exe
rm main$exe
exec garble -seed=${SEED1}= build -v
! stderr .
bincmp main$exe main_seed1$exe
exec ./main$exe test/main/imported
cmp stderr importedpkg-seed-static-1
# Even if we use the same seed, the same names in a different package
# should still be obfuscated in a different way.
exec ./main$exe test/main
cp stderr mainpkg-seed-static-1
! bincmp mainpkg-seed-static-1 importedpkg-seed-static-1
# Using different flags which affect the build, such as -literals or -tiny,
# should result in the same obfuscation as long as the seed is constant.
# TODO: also test that changing non-garble build parameters,
# such as GOARCH or -tags, still results in the same hashing via the seed.
exec garble -seed=${SEED1} -literals build
exec ./main$exe test/main/imported
cmp stderr importedpkg-seed-static-1
exec garble -seed=${SEED1} -tiny build
exec ./main$exe test/main/imported
cmp stderr importedpkg-seed-static-1
# Also check that a different seed leads to a different binary.
# We can't know if caching happens here, because of previous test runs.
cp main$exe main_seed2$exe
rm main$exe
exec garble -seed=${SEED2} build
! bincmp main$exe main_seed2$exe
exec ./main$exe test/main/imported
cp stderr importedpkg-seed-static-2
! bincmp importedpkg-seed-static-2 importedpkg-seed-static-1
# Use a random seed, which should always trigger a full build.
exec garble -seed=random build -v
stderr -count=1 '^-seed chosen at random: .+'
stderr -count=1 '^runtime$'
stderr -count=1 '^test/main$'
exec ./main$exe
cmp stderr main.stderr
binsubstr main$exe 'teststring' 'imported var value'
! binsubstr main$exe 'ImportedVar'
exec ./main$exe test/main/imported
cp stderr importedpkg-seed-random-1
! bincmp importedpkg-seed-random-1 importedpkg-seed-static-1
# Also check that the random binary is not reproducible.
cp main$exe main_random$exe
rm main$exe
exec garble -seed=random build -v
stderr .
! bincmp main$exe main_random$exe
exec ./main$exe test/main/imported
cp stderr importedpkg-seed-random-2
! bincmp importedpkg-seed-random-2 importedpkg-seed-random-1
# Finally, ensure that our runtime and reflect test code does what we think.
go build
exec ./main$exe
cmp stderr main.stderr
exec ./main$exe test/main
cmp stderr mainpkg.stderr
exec ./main$exe test/main/imported
cmp stderr importedpkg.stderr
-- go.mod --
module test/main
go 1.21
-- main.go --
package main
import (
"os"
"test/main/imported"
)
var teststringVar = "teststring"
func main() { mainFunc() }
func mainFunc() {
if len(os.Args) > 1 {
switch os.Args[1] {
case "test/main":
imported.PrintNames(NamedTypeValue, NamedFunc)
case "test/main/imported":
imported.PrintNames(imported.NamedType{}, imported.NamedFunc)
default:
panic("unknown package")
}
} else {
println(teststringVar)
println(imported.ImportedVar)
// When we're obfuscating, check that the obfuscated name lengths vary.
// With sixteen hashed names, and a range of 7 (between 6 and 12),
// the chances of fourteen repeats are incredibly minuscule.
// If that happens, then our randomness is clearly broken.
if hashedNames[0] != "main.hashed_00" {
var count [16]int
for _, name := range hashedNames {
name = name[len("main."):]
if len(name) < 6 {
panic("ended up with a hashed name that's too short: "+name)
}
if len(name) > 12 {
panic("ended up with a hashed name that's too long: "+name)
}
count[len(name)]++
if count[len(name)] >= 14 {
for _, name := range hashedNames {
println(name)
}
panic("six or more hashed names with the same length")
}
}
}
}
}
// A workaround to fool garble's reflect detection,
// because we want it to show us the obfuscated NamedType.
var NamedTypeValue any = NamedType{}
type NamedType struct {
NamedField int
}
func NamedFunc() string {
return imported.CallerFuncName()
}
var hashedNames = []string{
hashed_00(), hashed_01(), hashed_02(), hashed_03(),
hashed_04(), hashed_05(), hashed_06(), hashed_07(),
hashed_08(), hashed_09(), hashed_10(), hashed_11(),
hashed_12(), hashed_13(), hashed_14(), hashed_15(),
}
func hashed_00() string { return imported.CallerFuncName() }
func hashed_01() string { return imported.CallerFuncName() }
func hashed_02() string { return imported.CallerFuncName() }
func hashed_03() string { return imported.CallerFuncName() }
func hashed_04() string { return imported.CallerFuncName() }
func hashed_05() string { return imported.CallerFuncName() }
func hashed_06() string { return imported.CallerFuncName() }
func hashed_07() string { return imported.CallerFuncName() }
func hashed_08() string { return imported.CallerFuncName() }
func hashed_09() string { return imported.CallerFuncName() }
func hashed_10() string { return imported.CallerFuncName() }
func hashed_11() string { return imported.CallerFuncName() }
func hashed_12() string { return imported.CallerFuncName() }
func hashed_13() string { return imported.CallerFuncName() }
func hashed_14() string { return imported.CallerFuncName() }
func hashed_15() string { return imported.CallerFuncName() }
-- imported/imported.go --
package imported
import (
"reflect"
"runtime"
)
var ImportedVar = "imported var value"
type NamedType struct {
NamedField int
}
func NamedFunc() string {
return CallerFuncName()
}
func PrintNames(v any, fn func() string) {
typ := reflect.TypeOf(v)
println("path:", typ.PkgPath())
println("type:", typ.Name())
println("field:", typ.Field(0).Name)
println("func: ", fn())
}
func CallerFuncName() string {
pc, _, _, _ := runtime.Caller(1)
fn := runtime.FuncForPC(pc)
return fn.Name()
}
-- main.stderr --
teststring
imported var value
-- mainpkg.stderr --
path: main
type: NamedType
field: NamedField
func: main.NamedFunc
-- importedpkg.stderr --
path: test/main/imported
type: NamedType
field: NamedField
func: test/main/imported.NamedFunc