Files
garble/testdata/script/syntax.txtar
Daniel Martí e6fc593f68 set testscript's RequireExplicitExec and RequireUniqueNames
The first makes our test scripts more consistent, as all external
program executions happen via "exec" and are not as easily confused
with custom builtin commands like our "generate-literals".

The second catches mistakes if any of our txtar files have duplicate
files, where all but one of the contents would be ignored before.
2023-04-30 14:58:37 +01:00

271 lines
5.2 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.20
-- extra/extra.go --
package extra
func Func() string {
return "This is a separate module to obfuscate."
}
-- go.mod --
module test/main
go 1.20
// 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.