handle aliases to foreign named types properly

When such an alias name was used to define an embedded field, we handled
that case gracefully via the code using:

	tf.info.Uses[node].(*types.TypeName)

Unfortunately, when the same field name was used elsewhere, such as a
composite literal, tf.Info.Uses gave us a *types.Var, not a
*types.TypeName, meaning we could no longer tell if this was an alias,
or what it pointed to.

Thus, we failed to obfuscate the name properly in the added test case:

	> garble build
	[stderr]
	# test/main/sub
	xxWZf66u.go:36: unknown field 'foreignAlias' in struct literal of type smhWelwn

It doesn't seem like any of the go/types APIs allows us to obtain the
*types.TypeName directly in this scenario. Thus, use a trick that we
used before: after typechecking, but before obfuscating, record all
embedded struct field *types.Var which are aliases via a map, where the
value holds the *types.TypeName for the alias.

Updates #349.
pull/352/head
Daniel Martí 3 years ago committed by lu4p
parent e2ddce75a7
commit 64317883c9

@ -1062,10 +1062,16 @@ type transformer struct {
// obfuscated, for caching reasons; see transformGo.
ignoreObjects map[types.Object]bool
// These fields are used to locate struct types from any of their field
// objects. Useful when obfuscating field names.
fieldToStruct map[*types.Var]*types.Struct
// recordTypeDone helps avoid cycles in recordType.
recordTypeDone map[types.Type]bool
// fieldToStruct helps locate struct types from any of their field
// objects. Useful when obfuscating field names.
fieldToStruct map[*types.Var]*types.Struct
// fieldToAlias helps tell if an embedded struct field object is a type
// alias. Useful when obfuscating field names.
fieldToAlias map[*types.Var]*types.TypeName
}
// newTransformer helps initialize some maps.
@ -1078,6 +1084,7 @@ func newTransformer() *transformer {
},
recordTypeDone: make(map[types.Type]bool),
fieldToStruct: make(map[*types.Var]*types.Struct),
fieldToAlias: make(map[*types.Var]*types.TypeName),
}
}
@ -1096,8 +1103,14 @@ func (tf *transformer) typecheck(files []*ast.File) error {
tf.recordType(obj.Type())
}
}
for _, obj := range tf.info.Uses {
for name, obj := range tf.info.Uses {
if obj != nil {
if obj, ok := obj.(*types.TypeName); ok && obj.IsAlias() {
vr, _ := tf.info.Defs[name].(*types.Var)
if vr != nil {
tf.fieldToAlias[vr] = obj
}
}
tf.recordType(obj.Type())
}
}
@ -1169,7 +1182,10 @@ func (tf *transformer) transformGo(file *ast.File) *ast.File {
//
// Alternatively, if we don't have an alias, we want to
// use the embedded type, not the field.
if tname, ok := tf.info.Uses[node].(*types.TypeName); ok && tname.IsAlias() {
if tname := tf.fieldToAlias[vr]; tname != nil {
if !tname.IsAlias() {
panic("fieldToAlias recorded a non-alias TypeName?")
}
obj = tname
} else {
named := namedType(obj.Type())
@ -1213,7 +1229,7 @@ func (tf *transformer) transformGo(file *ast.File) *ast.File {
}
hashToUse := lpkg.GarbleActionID
// log.Printf("%#v %T", node, obj)
// log.Printf("%s: %#v %T", fset.Position(node.Pos()), node, obj)
parentScope := obj.Parent()
switch obj := obj.(type) {
case *types.Var:

@ -135,6 +135,8 @@ func input(localNameParam string) (localNameReturn string) { return localNamePar
-- sub/names.go --
package sub
import "io"
var someGlobalVar0 = "0"
var someGlobalVar1 = "1"
var someGlobalVar2 = "2"
@ -166,6 +168,22 @@ type EmbeddedStruct struct {
Foo int
}
// 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,
}
-- main.stderr --
nil case
1 1 1

Loading…
Cancel
Save