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.
278 lines
5.3 KiB
Plaintext
278 lines
5.3 KiB
Plaintext
exec 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.23
|
|
-- extra/extra.go --
|
|
package extra
|
|
|
|
func Func() string {
|
|
return "This is a separate module to obfuscate."
|
|
}
|
|
-- go.mod --
|
|
module test/main
|
|
|
|
go 1.23
|
|
|
|
// 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,
|
|
}
|
|
|
|
type embeddingBuiltinAlias struct {
|
|
byte
|
|
}
|
|
|
|
var _ = embeddingBuiltinAlias{3}
|
|
var _ = embeddingBuiltinAlias{byte: 3}
|
|
|
|
-- 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.
|