skip literals used in constant expressions

Fixes #39.
pull/51/head
lu4p 4 years ago committed by GitHub
parent c9bc7bac3b
commit f1bf6f91ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

1
.gitignore vendored

@ -1 +1,2 @@
/garble /garble
/test

@ -386,8 +386,10 @@ func transformCompile(args []string) ([]string, error) {
return nil, fmt.Errorf("typecheck error: %v", err) return nil, fmt.Errorf("typecheck error: %v", err)
} }
blacklist := buildBlacklist(files, info, pkg)
if envGarbleLiterals { if envGarbleLiterals {
files = obfuscateLiterals(files, info) files = obfuscateLiterals(files, info, blacklist)
// ast changed so we need to typecheck again // ast changed so we need to typecheck again
pkg, err = origTypesConfig.Check(pkgPath, fset, files, info) pkg, err = origTypesConfig.Check(pkgPath, fset, files, info)
if err != nil { if err != nil {
@ -410,8 +412,6 @@ func transformCompile(args []string) ([]string, error) {
// log.Println(flags) // log.Println(flags)
args = flags args = flags
blacklist := buildBlacklist(files, info, pkg)
pkgDebugDir := "" pkgDebugDir := ""
if envGarbleDebugDir != "" { if envGarbleDebugDir != "" {
osPkgPath := filepath.FromSlash(pkgPath) osPkgPath := filepath.FromSlash(pkgPath)
@ -665,6 +665,10 @@ func buildBlacklist(files []*ast.File, info *types.Info, pkg *types.Package) map
} }
} }
visit := func(node ast.Node) bool { visit := func(node ast.Node) bool {
if envGarbleLiterals {
constBlacklist(node, info, blacklist)
}
if node == nil { if node == nil {
if level == reflectCallLevel { if level == reflectCallLevel {
reflectCallLevel = -1 reflectCallLevel = -1

@ -43,7 +43,7 @@ func containsTypeDefStr(expr ast.Expr, info *types.Info) bool {
return false return false
} }
func obfuscateLiterals(files []*ast.File, info *types.Info) []*ast.File { func obfuscateLiterals(files []*ast.File, info *types.Info, blacklist map[types.Object]struct{}) []*ast.File {
pre := func(cursor *astutil.Cursor) bool { pre := func(cursor *astutil.Cursor) bool {
switch x := cursor.Node().(type) { switch x := cursor.Node().(type) {
case *ast.ValueSpec: case *ast.ValueSpec:
@ -91,6 +91,15 @@ func obfuscateLiterals(files []*ast.File, info *types.Info) []*ast.File {
return false return false
} }
for _, name := range spec.Names {
obj := info.ObjectOf(name)
// The object itself is blacklisted, e.g. a value that needs to be constant
if _, ok := blacklist[obj]; ok {
return false
}
}
for _, val := range spec.Values { for _, val := range spec.Values {
if v, ok := val.(*ast.BasicLit); !ok || v.Kind != token.STRING { if v, ok := val.(*ast.BasicLit); !ok || v.Kind != token.STRING {
return false // skip the block if it contains non basic literals return false // skip the block if it contains non basic literals
@ -306,3 +315,49 @@ func keyStmt(key []byte) *ast.GenDecl {
}}, }},
} }
} }
func constBlacklist(node ast.Node, info *types.Info, blacklist map[types.Object]struct{}) {
blacklistObjects := func(node ast.Node) bool {
ident, ok := node.(*ast.Ident)
if !ok {
return true
}
obj := info.ObjectOf(ident)
blacklist[obj] = struct{}{}
return true
}
switch x := node.(type) {
// in a slice or array composite literal all explicit keys must be constant representable
case *ast.CompositeLit:
if _, ok := x.Type.(*ast.ArrayType); !ok {
break
}
for _, elt := range x.Elts {
if kv, ok := elt.(*ast.KeyValueExpr); ok {
ast.Inspect(kv.Key, blacklistObjects)
}
}
// in an array type the length must be a constant representable
case *ast.ArrayType:
if x.Len != nil {
ast.Inspect(x.Len, blacklistObjects)
}
// in a const declaration all values must be constant representable
case *ast.GenDecl:
if x.Tok != token.CONST {
break
}
for _, spec := range x.Specs {
spec := spec.(*ast.ValueSpec)
for _, val := range spec.Values {
ast.Inspect(val, blacklistObjects)
}
}
}
}

@ -78,6 +78,7 @@ func main() {
println(skip1, skip2) println(skip1, skip2)
println(i, foo, bar) println(i, foo, bar)
typedTest() typedTest()
constantTest()
} }
type stringType string type stringType string
@ -98,7 +99,7 @@ func typedTest() {
println(skipTypedConst, skipTypedVar, skipTypedVarAssign) println(skipTypedConst, skipTypedVar, skipTypedVarAssign)
y := stringTypeStruct{ y := stringTypeStruct{
str: "stringTypeField String", // obfuscate str: "stringTypeField String", // obfuscate
strType: "stringTypeField strType", // skip strType: "stringTypeField strType", // skip
} }
println(y.str, y.strType) println(y.str, y.strType)
@ -120,6 +121,37 @@ func typedTest() {
println(stringTypeFunc("stringType func param")) // skip println(stringTypeFunc("stringType func param")) // skip
} }
// constantTest tests that string constants which need to be constant are skipped
func constantTest() {
const a = "foo" // skip
const length = len(a)
const b = "bar" // skip
type T [len(b)]byte
const c = "foo" // skip
var _ [len(c)]byte
const d = "foo" // skip
var arr = [5]string{len(d): "foo"}
for _, elm := range arr {
if elm != "" {
println(elm)
}
}
const e = "foo" // skip
var slice = []string{len(e): "foo"}
for _, elm := range slice {
if elm != "" {
println(elm)
}
}
const f = "foo" // skip
const i = length + len(f)
}
func stringTypeFunc(s stringType) stringType { func stringTypeFunc(s stringType) stringType {
println(s) println(s)
return "stringType return" // skip return "stringType return" // skip
@ -141,4 +173,6 @@ skip typed const skip typed var skip typed var assign
stringTypeField String stringTypeField strType stringTypeField String stringTypeField strType
stringType lambda func return stringType lambda func return
stringType func param stringType func param
stringType return stringType return
foo
foo

Loading…
Cancel
Save