1
0
mirror of https://github.com/golang/go synced 2024-11-23 16:40:03 -07:00

cmd/vet: avoid crash in cgo test on recursive type

This CL also re-enables the cgo tests that were accidentally disabled
in CL 32754.

Fixes #18389.

Change-Id: I2fdc4fe3ec1f92b7da3db3fa66f4e0f806fc899f
Reviewed-on: https://go-review.googlesource.com/34660
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
Ian Lance Taylor 2016-12-20 18:16:17 -08:00
parent 9c6a5ef922
commit 27fb26c77c
3 changed files with 14 additions and 9 deletions

View File

@ -44,7 +44,7 @@ func checkCgoCall(f *File, node ast.Node) {
} }
for _, arg := range x.Args { for _, arg := range x.Args {
if !typeOKForCgoCall(cgoBaseType(f, arg)) { if !typeOKForCgoCall(cgoBaseType(f, arg), make(map[types.Type]bool)) {
f.Badf(arg.Pos(), "possibly passing Go type with embedded pointer to C") f.Badf(arg.Pos(), "possibly passing Go type with embedded pointer to C")
} }
@ -53,7 +53,7 @@ func checkCgoCall(f *File, node ast.Node) {
arg = conv.Args[0] arg = conv.Args[0]
} }
if u, ok := arg.(*ast.UnaryExpr); ok && u.Op == token.AND { if u, ok := arg.(*ast.UnaryExpr); ok && u.Op == token.AND {
if !typeOKForCgoCall(cgoBaseType(f, u.X)) { if !typeOKForCgoCall(cgoBaseType(f, u.X), make(map[types.Type]bool)) {
f.Badf(arg.Pos(), "possibly passing Go type with embedded pointer to C") f.Badf(arg.Pos(), "possibly passing Go type with embedded pointer to C")
} }
} }
@ -110,23 +110,24 @@ func cgoBaseType(f *File, arg ast.Expr) types.Type {
return f.pkg.types[arg].Type return f.pkg.types[arg].Type
} }
// typeOKForCgoCall returns true if the type of arg is OK to pass to a // typeOKForCgoCall reports whether the type of arg is OK to pass to a
// C function using cgo. This is not true for Go types with embedded // C function using cgo. This is not true for Go types with embedded
// pointers. // pointers. m is used to avoid infinite recursion on recursive types.
func typeOKForCgoCall(t types.Type) bool { func typeOKForCgoCall(t types.Type, m map[types.Type]bool) bool {
if t == nil { if t == nil || m[t] {
return true return true
} }
m[t] = true
switch t := t.Underlying().(type) { switch t := t.Underlying().(type) {
case *types.Chan, *types.Map, *types.Signature, *types.Slice: case *types.Chan, *types.Map, *types.Signature, *types.Slice:
return false return false
case *types.Pointer: case *types.Pointer:
return typeOKForCgoCall(t.Elem()) return typeOKForCgoCall(t.Elem(), m)
case *types.Array: case *types.Array:
return typeOKForCgoCall(t.Elem()) return typeOKForCgoCall(t.Elem(), m)
case *types.Struct: case *types.Struct:
for i := 0; i < t.NumFields(); i++ { for i := 0; i < t.NumFields(); i++ {
if !typeOKForCgoCall(t.Field(i).Type()) { if !typeOKForCgoCall(t.Field(i).Type(), m) {
return false return false
} }
} }

View File

@ -52,5 +52,8 @@ func CgoTests() {
C.f(*(*unsafe.Pointer)(unsafe.Pointer(&st2))) C.f(*(*unsafe.Pointer)(unsafe.Pointer(&st2)))
C.f(unsafe.Pointer(&st2)) C.f(unsafe.Pointer(&st2))
type cgoStruct struct{ p *cgoStruct }
C.f(unsafe.Pointer(&cgoStruct{}))
C.CBytes([]byte("hello")) C.CBytes([]byte("hello"))
} }

View File

@ -143,6 +143,7 @@ func TestVetDirs(t *testing.T) {
"divergent", "divergent",
"buildtag", "buildtag",
"incomplete", // incomplete examples "incomplete", // incomplete examples
"cgo",
} { } {
dir := dir dir := dir
t.Run(dir, func(t *testing.T) { t.Run(dir, func(t *testing.T) {