Skip to content

Commit b888a62

Browse files
committed
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. Fixes #24161 Change-Id: I32ca7e48eb4d4133c6242e91d1879636f5224ea9 Reviewed-on: https://go-review.googlesource.com/123177 Run-TryBot: Keith Randall <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent 85cfa4d commit b888a62

File tree

6 files changed

+169
-31
lines changed

6 files changed

+169
-31
lines changed

misc/cgo/test/issue24161_darwin_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ import (
88
"testing"
99

1010
"./issue24161arg"
11+
"./issue24161e0"
12+
"./issue24161e1"
13+
"./issue24161e2"
1114
"./issue24161res"
1215
)
1316

@@ -17,3 +20,12 @@ func Test24161Arg(t *testing.T) {
1720
func Test24161Res(t *testing.T) {
1821
issue24161res.Test(t)
1922
}
23+
func Test24161Example0(t *testing.T) {
24+
issue24161e0.Test(t)
25+
}
26+
func Test24161Example1(t *testing.T) {
27+
issue24161e1.Test(t)
28+
}
29+
func Test24161Example2(t *testing.T) {
30+
issue24161e2.Test(t)
31+
}

misc/cgo/test/issue24161e0/main.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2018 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// +build darwin
6+
7+
package issue24161e0
8+
9+
/*
10+
#cgo CFLAGS: -x objective-c
11+
#cgo LDFLAGS: -framework CoreFoundation -framework Security
12+
#include <CoreFoundation/CoreFoundation.h>
13+
#include <Security/Security.h>
14+
*/
15+
import "C"
16+
import "testing"
17+
18+
func f1() {
19+
C.SecKeyCreateSignature(0, C.kSecKeyAlgorithmECDSASignatureDigestX962SHA1, 0, nil)
20+
}
21+
22+
func Test(t *testing.T) {}

misc/cgo/test/issue24161e1/main.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright 2018 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// +build darwin
6+
7+
package issue24161e1
8+
9+
/*
10+
#cgo CFLAGS: -x objective-c
11+
#cgo LDFLAGS: -framework CoreFoundation -framework Security
12+
#include <CoreFoundation/CoreFoundation.h>
13+
#include <Security/Security.h>
14+
*/
15+
import "C"
16+
import (
17+
"fmt"
18+
"testing"
19+
)
20+
21+
func f1() {
22+
C.SecKeyCreateSignature(0, C.kSecKeyAlgorithmECDSASignatureDigestX962SHA1, 0, nil)
23+
}
24+
25+
func f2(e C.CFErrorRef) {
26+
if desc := C.CFErrorCopyDescription(e); desc != 0 {
27+
fmt.Println(desc)
28+
}
29+
}
30+
31+
func Test(t *testing.T) {}

misc/cgo/test/issue24161e2/main.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright 2018 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// +build darwin
6+
7+
package issue24161e2
8+
9+
/*
10+
#cgo CFLAGS: -x objective-c
11+
#cgo LDFLAGS: -framework CoreFoundation -framework Security
12+
#include <CoreFoundation/CoreFoundation.h>
13+
#include <Security/Security.h>
14+
*/
15+
import "C"
16+
import (
17+
"fmt"
18+
"testing"
19+
)
20+
21+
var _ C.CFStringRef
22+
23+
func f1() {
24+
C.SecKeyCreateSignature(0, C.kSecKeyAlgorithmECDSASignatureDigestX962SHA1, 0, nil)
25+
}
26+
27+
func f2(e C.CFErrorRef) {
28+
if desc := C.CFErrorCopyDescription(e); desc != 0 {
29+
fmt.Println(desc)
30+
}
31+
}
32+
33+
func Test(t *testing.T) {}

src/cmd/cgo/gcc.go

Lines changed: 66 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -164,24 +164,22 @@ func (p *Package) Translate(f *File) {
164164
cref.Name.C = cname(cref.Name.Go)
165165
}
166166
p.loadDefines(f)
167-
needType := p.guessKinds(f)
168-
if len(needType) > 0 {
169-
p.loadDWARF(f, needType)
170-
// If there are typedefs used as arguments, add those
171-
// types to the list of types we're interested in, and
172-
// try again.
173-
if len(p.ArgTypedefs) > 0 {
174-
for _, a := range p.ArgTypedefs {
175-
f.Name[a] = &Name{
176-
Go: a,
177-
C: a,
178-
}
179-
}
180-
needType := p.guessKinds(f)
181-
if len(needType) > 0 {
182-
p.loadDWARF(f, needType)
167+
p.typedefs = map[string]bool{}
168+
p.typedefList = nil
169+
numTypedefs := -1
170+
for len(p.typedefs) > numTypedefs {
171+
numTypedefs = len(p.typedefs)
172+
// Also ask about any typedefs we've seen so far.
173+
for _, a := range p.typedefList {
174+
f.Name[a] = &Name{
175+
Go: a,
176+
C: a,
183177
}
184178
}
179+
needType := p.guessKinds(f)
180+
if len(needType) > 0 {
181+
p.loadDWARF(f, needType)
182+
}
185183
}
186184
if p.rewriteCalls(f) {
187185
// Add `import _cgo_unsafe "unsafe"` after the package statement.
@@ -566,6 +564,7 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
566564
fatalf("malformed __cgo__ name: %s", name)
567565
}
568566
types[i] = t.Type
567+
p.recordTypedefs(t.Type)
569568
}
570569
if e.Tag != dwarf.TagCompileUnit {
571570
r.SkipChildren()
@@ -630,7 +629,43 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
630629
}
631630
conv.FinishType(pos)
632631
}
633-
p.ArgTypedefs = conv.argTypedefs
632+
}
633+
634+
// recordTypedefs remembers in p.typedefs all the typedefs used in dtypes and its children.
635+
func (p *Package) recordTypedefs(dtype dwarf.Type) {
636+
p.recordTypedefs1(dtype, map[dwarf.Type]bool{})
637+
}
638+
func (p *Package) recordTypedefs1(dtype dwarf.Type, visited map[dwarf.Type]bool) {
639+
if dtype == nil {
640+
return
641+
}
642+
if visited[dtype] {
643+
return
644+
}
645+
visited[dtype] = true
646+
switch dt := dtype.(type) {
647+
case *dwarf.TypedefType:
648+
if !p.typedefs[dt.Name] {
649+
p.typedefs[dt.Name] = true
650+
p.typedefList = append(p.typedefList, dt.Name)
651+
p.recordTypedefs1(dt.Type, visited)
652+
}
653+
case *dwarf.PtrType:
654+
p.recordTypedefs1(dt.Type, visited)
655+
case *dwarf.ArrayType:
656+
p.recordTypedefs1(dt.Type, visited)
657+
case *dwarf.QualType:
658+
p.recordTypedefs1(dt.Type, visited)
659+
case *dwarf.FuncType:
660+
p.recordTypedefs1(dt.ReturnType, visited)
661+
for _, a := range dt.ParamType {
662+
p.recordTypedefs1(a, visited)
663+
}
664+
case *dwarf.StructType:
665+
for _, f := range dt.Field {
666+
p.recordTypedefs1(f.Type, visited)
667+
}
668+
}
634669
}
635670

636671
// mangleName does name mangling to translate names
@@ -1712,9 +1747,6 @@ type typeConv struct {
17121747

17131748
ptrSize int64
17141749
intSize int64
1715-
1716-
// Typedefs used as argument types for C calls.
1717-
argTypedefs []string
17181750
}
17191751

17201752
var tagGen int
@@ -2275,9 +2307,6 @@ func (c *typeConv) FuncArg(dtype dwarf.Type, pos token.Pos) *Type {
22752307
C: tr,
22762308
}
22772309
case *dwarf.TypedefType:
2278-
// Keep track of all the typedefs used as arguments.
2279-
c.argTypedefs = append(c.argTypedefs, dt.Name)
2280-
22812310
// C has much more relaxed rules than Go for
22822311
// implicit type conversions. When the parameter
22832312
// is type T defined as *X, simulate a little of the
@@ -2290,7 +2319,7 @@ func (c *typeConv) FuncArg(dtype dwarf.Type, pos token.Pos) *Type {
22902319
}
22912320
// ...or the typedef is one in which we expect bad pointers.
22922321
// It will be a uintptr instead of *X.
2293-
if c.badPointerTypedef(dt) {
2322+
if c.baseBadPointerTypedef(dt) {
22942323
break
22952324
}
22962325

@@ -2334,9 +2363,6 @@ func (c *typeConv) FuncType(dtype *dwarf.FuncType, pos token.Pos) *FuncType {
23342363
gr = []*ast.Field{{Type: c.goVoid}}
23352364
} else if dtype.ReturnType != nil {
23362365
r = c.Type(unqual(dtype.ReturnType), pos)
2337-
if dt, ok := dtype.ReturnType.(*dwarf.TypedefType); ok {
2338-
c.argTypedefs = append(c.argTypedefs, dt.Name)
2339-
}
23402366
gr = []*ast.Field{{Type: r.Go}}
23412367
}
23422368
return &FuncType{
@@ -2645,6 +2671,19 @@ func (c *typeConv) badPointerTypedef(dt *dwarf.TypedefType) bool {
26452671
return false
26462672
}
26472673

2674+
// baseBadPointerTypedef reports whether the base of a chain of typedefs is a bad typedef
2675+
// as badPointerTypedef reports.
2676+
func (c *typeConv) baseBadPointerTypedef(dt *dwarf.TypedefType) bool {
2677+
for {
2678+
if t, ok := dt.Type.(*dwarf.TypedefType); ok {
2679+
dt = t
2680+
continue
2681+
}
2682+
break
2683+
}
2684+
return c.badPointerTypedef(dt)
2685+
}
2686+
26482687
func (c *typeConv) badCFType(dt *dwarf.TypedefType) bool {
26492688
// The real bad types are CFNumberRef and CFDateRef.
26502689
// Sometimes non-pointers are stored in these types.

src/cmd/cgo/main.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,11 @@ type Package struct {
4343
Name map[string]*Name // accumulated Name from Files
4444
ExpFunc []*ExpFunc // accumulated ExpFunc from Files
4545
Decl []ast.Decl
46-
GoFiles []string // list of Go files
47-
GccFiles []string // list of gcc output files
48-
Preamble string // collected preamble for _cgo_export.h
49-
ArgTypedefs []string // typedefs used as arguments to or results of C functions
46+
GoFiles []string // list of Go files
47+
GccFiles []string // list of gcc output files
48+
Preamble string // collected preamble for _cgo_export.h
49+
typedefs map[string]bool // type names that appear in the types of the objects we're interested in
50+
typedefList []string
5051
}
5152

5253
// A File collects information about a single Go input file.

0 commit comments

Comments
 (0)