Files
garble/testdata/script/syntax.txtar
Daniel Martí 481e3a1f09 default to GOGARBLE=*, stop using GOPRIVATE
We can drop the code that kicked in when GOGARBLE was empty.
We can also add the value in addGarbleToHash unconditionally,
as we never allow it to be empty.

In the tests, remove all GOGARBLE lines where it just meant "obfuscate
everything" or "obfuscate the entire main module".

cgo.txtar had "obfuscate everything" as a separate step,
so remove it entirely.

linkname.txtar started failing because the imported package did not
import strings, so listPackage errored out. This wasn't a problem when
strings itself wasn't obfuscated, as transformLinkname silently left
strings.IndexByte untouched. It is a problem when IndexByte does get
obfuscated. Make that kind of listPackage error visible, and fix it.

reflect.txtar started failing with "unreachable method" runtime throws.
It's not clear to me why; it appears that GOGARBLE=* makes the linker
think that ExportedMethodName is suddenly unreachable.
Work around the problem by making the method explicitly reachable,
and leave a TODO as a reminder to investigate.

Finally, gogarble.txtar no longer needs to test for GOPRIVATE.
The rest of the test is left the same, as we still want the various
values for GOGARBLE to continue to work just like before.

Fixes #594.
2022-12-13 21:14:03 +00:00

271 lines
5.2 KiB
Plaintext

garble build
exec ./main$exe
cmp stderr main.stderr
! binsubstr main$exe 'localName' 'globalConst' 'globalVar' 'globalType' 'valuable information' 'private.source' 'remoteIntReturn' 'intReturn' 'neverInlined'
[short] stop # no need to verify this with -short
# Check that the program works as expected without garble.
go build
exec ./main$exe
cmp stderr main.stderr
binsubstr main$exe 'globalVar' # 'globalType' matches on some, but not all, platforms
! binsubstr main$exe 'localName' 'globalConst' 'remoteIntReturn' 'intReturn'
-- extra/go.mod --
module private.source/extra
go 1.19
-- extra/extra.go --
package extra
func Func() string {
return "This is a separate module to obfuscate."
}
-- go.mod --
module test/main
go 1.19
// We include an extra module to obfuscate, included in the same original source
// code via a replace directive.
require private.source/extra v0.0.0-00010101000000-000000000000
replace private.source/extra => ./extra
-- main.go --
package main
import (
"go/ast"
"runtime"
"private.source/extra"
"test/main/sub"
)
// This comment contains valuable information. Ensure it's not in the final binary.
var V any
type T struct {
ast.Node
*ast.Ident
}
type Embedded int
type Embedding struct {
Embedded
}
type embedded int
type embedding struct {
embedded
}
// embedded fields whose type is in the universe scope used to crash garble
type EmbeddingUniverseScope struct {
error
int
string
}
// TODO: test that go:noinline still works without using debugdir
func ensureInlined(wantInlined bool) {
pc := make([]uintptr, 1)
// We skip two caller frames; runtime.Callers, and ensureInlined.
// This way, the frame we get is our caller, like neverInlined.
n := runtime.Callers(2, pc)
if n == 0 {
panic("got zero callers?")
}
pc = pc[:n]
frames := runtime.CallersFrames(pc)
frame, _ := frames.Next()
gotInlined := frame.Func == nil
if wantInlined && !gotInlined {
panic("caller should be inlined but wasn't")
} else if !wantInlined && gotInlined {
panic("caller shouldn't be inlined but was")
}
}
//go:noinline
func neverInlined() {
ensureInlined(false)
println("This func is never inlined.")
}
func alwaysInlined() {
ensureInlined(true)
println("This func is always inlined.")
}
type EmbeddingOuter struct {
EmbeddingInner
}
type EmbeddingInner struct {
SomeField int
}
func main() {
switch V := V.(type) {
case int:
var _ int = V
case nil:
println("nil case")
}
scopesTest()
println(extra.Func())
sub.Test()
neverInlined()
alwaysInlined()
_ = sub.EmbeddingExternalForeignAlias{
ExternalForeignAlias: nil,
Reader: nil,
}
var emb sub.EmbeddingAlias
_ = emb.EmbeddedAlias
_ = emb.Foo
_ = emb.EmbeddedAliasSameName
_ = emb.Bar
}
-- scopes.go --
package main
const globalConst = 1
type globalType int
var (
globalVar = 1
globalVarTyped globalType = 1
)
func scopesTest() {
println(globalVar, globalConst, globalVarTyped)
const localNameConst = 1
localNameShort := 4
type localNameType int
var (
localNameVar = 5
localNameTypeVar localNameType = 1
)
println(localNameConst, localNameShort, localNameVar, localNameTypeVar, input("input"))
}
func input(localNameParam string) (localNameReturn string) { return localNameParam }
-- sub/names.go --
package sub
import (
"io"
"test/main/external"
)
var someGlobalVar0 = "0"
var someGlobalVar1 = "1"
var someGlobalVar2 = "2"
func Test() {
var A, B, C, D, E string
noop(A, B, C, D, E)
if someGlobalVar0 != "0" || someGlobalVar1 != "1" || someGlobalVar2 != "2"{
panic("name collision detected")
}
}
func noop(...any) {}
// Funcs that almost look like test funcs used to make garble panic.
func TestFoo(s string) {}
func TestBar(*struct{}) {}
// If we obfuscate the alias name, we must obfuscate its use here too.
type EmbeddingAlias struct {
EmbeddedAlias
EmbeddedAliasSameName
}
type EmbeddedAlias = external.NamedExternal
type EmbeddedAliasSameName = external.EmbeddedAliasSameName
// We obfuscate the name foreignAlias, but not the name Reader,
// as it's not declared in a private package.
// Both names must do the same when used as struct fields,
// both in the struct declaration and in the composite literal below.
type embeddingForeignAlias struct {
foreignAlias
io.Reader
}
type foreignAlias = io.Reader
var _ = embeddingForeignAlias{
foreignAlias: nil,
Reader: nil,
}
// Similar to embeddingForeignAlias,
// but the alias is declared in a dependency,
// and this type is used in a dependent.
type EmbeddingExternalForeignAlias struct {
external.ExternalForeignAlias
io.Reader
}
// Like the cases above,
// but this time the alias doesn't rename its destination named type.
// We can't tell this apart from "struct { io.Reader }" at the type info level.
// It's fine to ignore the alias entirely, in this case.
type embeddingAliasSameName struct {
external.Reader
}
var _ = embeddingAliasSameName{
Reader: nil,
}
-- external/external.go --
package external
import "io"
type NamedExternal struct {
Foo int
}
type EmbeddedAliasSameName struct {
Bar int
}
type ExternalForeignAlias = io.Reader
type Reader = io.Reader
-- main.stderr --
nil case
1 1 1
1 4 5 1 input
This is a separate module to obfuscate.
This func is never inlined.
This func is always inlined.