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:
parent
48016b89d9
commit
424f4ea0bd
@ -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)
|
||||||
|
}
|
||||||
|
22
misc/cgo/test/issue24161e0/main.go
Normal file
22
misc/cgo/test/issue24161e0/main.go
Normal 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) {}
|
31
misc/cgo/test/issue24161e1/main.go
Normal file
31
misc/cgo/test/issue24161e1/main.go
Normal 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) {}
|
33
misc/cgo/test/issue24161e2/main.go
Normal file
33
misc/cgo/test/issue24161e2/main.go
Normal 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) {}
|
@ -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.
|
||||||
|
@ -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.
|
||||||
|
Loading…
Reference in New Issue
Block a user