1
0
mirror of https://github.com/golang/go synced 2024-11-14 06:00:22 -07:00

[release-branch.go1.10] cmd/cgo: fix cgo bad typedefs

Two fixes:

1) Typedefs of the bad typedefs should also not be rewritten to the
   underlying type.  They shouldn't just be uintptr, though, they should
   retain the C naming structure.  For example, in C:

   typedef const __CFString * CFStringRef;
   typedef CFStringRef SecKeyAlgorithm;

   we want the Go:

   type _Ctype_CFStringRef uintptr
   type _Ctype_SecKeyAlgorithm = _Ctype_CFStringRef

2) We need more types than just function arguments/return values.
   At least we need types of global variables, so when we see a reference to:

   extern const SecKeyAlgorithm kSecKeyAlgorithmECDSASignatureDigestX962SHA1;

   we know that we need to investigate the type SecKeyAlgorithm.
   Might as well just find every typedef and check the badness of all of them.
   This requires looping until a fixed point of known types is reached.
   Usually it takes just 2 iterations, sometimes 3.

Update #25036

Change-Id: I32ca7e48eb4d4133c6242e91d1879636f5224ea9
Reviewed-on: https://go-review.googlesource.com/123177
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-on: https://go-review.googlesource.com/124215
This commit is contained in:
Keith Randall 2018-07-10 13:47:15 -07:00 committed by Ian Lance Taylor
parent 48016b89d9
commit 424f4ea0bd
6 changed files with 169 additions and 31 deletions

View File

@ -8,6 +8,9 @@ import (
"testing" "testing"
"./issue24161arg" "./issue24161arg"
"./issue24161e0"
"./issue24161e1"
"./issue24161e2"
"./issue24161res" "./issue24161res"
) )
@ -17,3 +20,12 @@ func Test24161Arg(t *testing.T) {
func Test24161Res(t *testing.T) { func Test24161Res(t *testing.T) {
issue24161res.Test(t) issue24161res.Test(t)
} }
func Test24161Example0(t *testing.T) {
issue24161e0.Test(t)
}
func Test24161Example1(t *testing.T) {
issue24161e1.Test(t)
}
func Test24161Example2(t *testing.T) {
issue24161e2.Test(t)
}

View File

@ -0,0 +1,22 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin
package issue24161e0
/*
#cgo CFLAGS: -x objective-c
#cgo LDFLAGS: -framework CoreFoundation -framework Security
#include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>
*/
import "C"
import "testing"
func f1() {
C.SecKeyCreateSignature(0, C.kSecKeyAlgorithmECDSASignatureDigestX962SHA1, 0, nil)
}
func Test(t *testing.T) {}

View File

@ -0,0 +1,31 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin
package issue24161e1
/*
#cgo CFLAGS: -x objective-c
#cgo LDFLAGS: -framework CoreFoundation -framework Security
#include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>
*/
import "C"
import (
"fmt"
"testing"
)
func f1() {
C.SecKeyCreateSignature(0, C.kSecKeyAlgorithmECDSASignatureDigestX962SHA1, 0, nil)
}
func f2(e C.CFErrorRef) {
if desc := C.CFErrorCopyDescription(e); desc != 0 {
fmt.Println(desc)
}
}
func Test(t *testing.T) {}

View File

@ -0,0 +1,33 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin
package issue24161e2
/*
#cgo CFLAGS: -x objective-c
#cgo LDFLAGS: -framework CoreFoundation -framework Security
#include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>
*/
import "C"
import (
"fmt"
"testing"
)
var _ C.CFStringRef
func f1() {
C.SecKeyCreateSignature(0, C.kSecKeyAlgorithmECDSASignatureDigestX962SHA1, 0, nil)
}
func f2(e C.CFErrorRef) {
if desc := C.CFErrorCopyDescription(e); desc != 0 {
fmt.Println(desc)
}
}
func Test(t *testing.T) {}

View File

@ -164,24 +164,22 @@ func (p *Package) Translate(f *File) {
cref.Name.C = cname(cref.Name.Go) cref.Name.C = cname(cref.Name.Go)
} }
p.loadDefines(f) p.loadDefines(f)
needType := p.guessKinds(f) p.typedefs = map[string]bool{}
if len(needType) > 0 { p.typedefList = nil
p.loadDWARF(f, needType) numTypedefs := -1
// If there are typedefs used as arguments, add those for len(p.typedefs) > numTypedefs {
// types to the list of types we're interested in, and numTypedefs = len(p.typedefs)
// try again. // Also ask about any typedefs we've seen so far.
if len(p.ArgTypedefs) > 0 { for _, a := range p.typedefList {
for _, a := range p.ArgTypedefs { f.Name[a] = &Name{
f.Name[a] = &Name{ Go: a,
Go: a, C: a,
C: a,
}
}
needType := p.guessKinds(f)
if len(needType) > 0 {
p.loadDWARF(f, needType)
} }
} }
needType := p.guessKinds(f)
if len(needType) > 0 {
p.loadDWARF(f, needType)
}
} }
if p.rewriteCalls(f) { if p.rewriteCalls(f) {
// Add `import _cgo_unsafe "unsafe"` after the package statement. // Add `import _cgo_unsafe "unsafe"` after the package statement.
@ -566,6 +564,7 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
fatalf("malformed __cgo__ name: %s", name) fatalf("malformed __cgo__ name: %s", name)
} }
types[i] = t.Type types[i] = t.Type
p.recordTypedefs(t.Type)
} }
if e.Tag != dwarf.TagCompileUnit { if e.Tag != dwarf.TagCompileUnit {
r.SkipChildren() r.SkipChildren()
@ -612,7 +611,43 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
} }
conv.FinishType(pos) conv.FinishType(pos)
} }
p.ArgTypedefs = conv.argTypedefs }
// recordTypedefs remembers in p.typedefs all the typedefs used in dtypes and its children.
func (p *Package) recordTypedefs(dtype dwarf.Type) {
p.recordTypedefs1(dtype, map[dwarf.Type]bool{})
}
func (p *Package) recordTypedefs1(dtype dwarf.Type, visited map[dwarf.Type]bool) {
if dtype == nil {
return
}
if visited[dtype] {
return
}
visited[dtype] = true
switch dt := dtype.(type) {
case *dwarf.TypedefType:
if !p.typedefs[dt.Name] {
p.typedefs[dt.Name] = true
p.typedefList = append(p.typedefList, dt.Name)
p.recordTypedefs1(dt.Type, visited)
}
case *dwarf.PtrType:
p.recordTypedefs1(dt.Type, visited)
case *dwarf.ArrayType:
p.recordTypedefs1(dt.Type, visited)
case *dwarf.QualType:
p.recordTypedefs1(dt.Type, visited)
case *dwarf.FuncType:
p.recordTypedefs1(dt.ReturnType, visited)
for _, a := range dt.ParamType {
p.recordTypedefs1(a, visited)
}
case *dwarf.StructType:
for _, f := range dt.Field {
p.recordTypedefs1(f.Type, visited)
}
}
} }
// mangleName does name mangling to translate names // mangleName does name mangling to translate names
@ -1694,9 +1729,6 @@ type typeConv struct {
ptrSize int64 ptrSize int64
intSize int64 intSize int64
// Typedefs used as argument types for C calls.
argTypedefs []string
} }
var tagGen int var tagGen int
@ -2257,9 +2289,6 @@ func (c *typeConv) FuncArg(dtype dwarf.Type, pos token.Pos) *Type {
C: tr, C: tr,
} }
case *dwarf.TypedefType: case *dwarf.TypedefType:
// Keep track of all the typedefs used as arguments.
c.argTypedefs = append(c.argTypedefs, dt.Name)
// C has much more relaxed rules than Go for // C has much more relaxed rules than Go for
// implicit type conversions. When the parameter // implicit type conversions. When the parameter
// is type T defined as *X, simulate a little of the // is type T defined as *X, simulate a little of the
@ -2272,7 +2301,7 @@ func (c *typeConv) FuncArg(dtype dwarf.Type, pos token.Pos) *Type {
} }
// ...or the typedef is one in which we expect bad pointers. // ...or the typedef is one in which we expect bad pointers.
// It will be a uintptr instead of *X. // It will be a uintptr instead of *X.
if c.badPointerTypedef(dt) { if c.baseBadPointerTypedef(dt) {
break break
} }
@ -2316,9 +2345,6 @@ func (c *typeConv) FuncType(dtype *dwarf.FuncType, pos token.Pos) *FuncType {
gr = []*ast.Field{{Type: c.goVoid}} gr = []*ast.Field{{Type: c.goVoid}}
} else if dtype.ReturnType != nil { } else if dtype.ReturnType != nil {
r = c.Type(unqual(dtype.ReturnType), pos) r = c.Type(unqual(dtype.ReturnType), pos)
if dt, ok := dtype.ReturnType.(*dwarf.TypedefType); ok {
c.argTypedefs = append(c.argTypedefs, dt.Name)
}
gr = []*ast.Field{{Type: r.Go}} gr = []*ast.Field{{Type: r.Go}}
} }
return &FuncType{ return &FuncType{
@ -2627,6 +2653,19 @@ func (c *typeConv) badPointerTypedef(dt *dwarf.TypedefType) bool {
return false return false
} }
// baseBadPointerTypedef reports whether the base of a chain of typedefs is a bad typedef
// as badPointerTypedef reports.
func (c *typeConv) baseBadPointerTypedef(dt *dwarf.TypedefType) bool {
for {
if t, ok := dt.Type.(*dwarf.TypedefType); ok {
dt = t
continue
}
break
}
return c.badPointerTypedef(dt)
}
func (c *typeConv) badCFType(dt *dwarf.TypedefType) bool { func (c *typeConv) badCFType(dt *dwarf.TypedefType) bool {
// The real bad types are CFNumberRef and CFDateRef. // The real bad types are CFNumberRef and CFDateRef.
// Sometimes non-pointers are stored in these types. // Sometimes non-pointers are stored in these types.

View File

@ -42,10 +42,11 @@ type Package struct {
Name map[string]*Name // accumulated Name from Files Name map[string]*Name // accumulated Name from Files
ExpFunc []*ExpFunc // accumulated ExpFunc from Files ExpFunc []*ExpFunc // accumulated ExpFunc from Files
Decl []ast.Decl Decl []ast.Decl
GoFiles []string // list of Go files GoFiles []string // list of Go files
GccFiles []string // list of gcc output files GccFiles []string // list of gcc output files
Preamble string // collected preamble for _cgo_export.h Preamble string // collected preamble for _cgo_export.h
ArgTypedefs []string // typedefs used as arguments to or results of C functions typedefs map[string]bool // type names that appear in the types of the objects we're interested in
typedefList []string
} }
// A File collects information about a single Go input file. // A File collects information about a single Go input file.