mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/cgo: rewrite CFTypeRef and subytes on Darwin to uintptr
Cgo currently maps CFTypeRef and its subtypes to unsafe.Pointer or a pointer to a named empty struct. However, Darwin sometimes encodes some of CFTypeRef's subtypes as a few int fields packed in a pointer wrapper. This hackery confuses the Go runtime as the pointers can look like they point to things that shouldn't be pointed at. Switch CFTypeRef and its subtypes to map to uintptr. Detecting the affected set of types is tricky, there are over 200 of them, and the set isn't static across Darwin versions. Fortunately, downcasting from CFTypeRef to a subtype requires calling CFGetTypeID, getting a CFTypeID token, and comparing that with a known id from a *GetTypeID() call. So we can find all the type names by detecting all the *GetTypeID() prototypes and rewriting the corresponding *Ref types to uintptr. This strategy covers all the cases I've checked and is unlikely to have a false positive. Update #23091. Change-Id: I487eb4105c9b4785ba564de9c38d472c8c9a76ac Reviewed-on: https://go-review.googlesource.com/87615 Run-TryBot: Keith Randall <khr@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
parent
165e7523fb
commit
d162a297ed
3 changed files with 59 additions and 74 deletions
|
|
@ -224,6 +224,7 @@ func (p *Package) guessKinds(f *File) []*Name {
|
|||
// Determine kinds for names we already know about,
|
||||
// like #defines or 'struct foo', before bothering with gcc.
|
||||
var names, needType []*Name
|
||||
optional := map[*Name]bool{}
|
||||
for _, key := range nameKeys(f.Name) {
|
||||
n := f.Name[key]
|
||||
// If we've already found this name as a #define
|
||||
|
|
@ -260,6 +261,14 @@ func (p *Package) guessKinds(f *File) []*Name {
|
|||
continue
|
||||
}
|
||||
|
||||
if goos == "darwin" && strings.HasSuffix(n.C, "Ref") {
|
||||
// For FooRef, find out if FooGetTypeID exists.
|
||||
s := n.C[:len(n.C)-3] + "GetTypeID"
|
||||
n := &Name{Go: s, C: s}
|
||||
names = append(names, n)
|
||||
optional[n] = true
|
||||
}
|
||||
|
||||
// Otherwise, we'll need to find out from gcc.
|
||||
names = append(names, n)
|
||||
}
|
||||
|
|
@ -406,6 +415,11 @@ func (p *Package) guessKinds(f *File) []*Name {
|
|||
for i, n := range names {
|
||||
switch sniff[i] {
|
||||
default:
|
||||
if sniff[i]¬Declared != 0 && optional[n] {
|
||||
// Ignore optional undeclared identifiers.
|
||||
// Don't report an error, and skip adding n to the needType array.
|
||||
continue
|
||||
}
|
||||
error_(f.NamePos[n], "could not determine kind of name for C.%s", fixGo(n.Go))
|
||||
case notStrLiteral | notType:
|
||||
n.Kind = "iconst"
|
||||
|
|
@ -418,6 +432,7 @@ func (p *Package) guessKinds(f *File) []*Name {
|
|||
case notIntConst | notNumConst | notStrLiteral | notType:
|
||||
n.Kind = "not-type"
|
||||
}
|
||||
needType = append(needType, n)
|
||||
}
|
||||
if nerrors > 0 {
|
||||
// Check if compiling the preamble by itself causes any errors,
|
||||
|
|
@ -431,7 +446,6 @@ func (p *Package) guessKinds(f *File) []*Name {
|
|||
fatalf("unresolved names")
|
||||
}
|
||||
|
||||
needType = append(needType, names...)
|
||||
return needType
|
||||
}
|
||||
|
||||
|
|
@ -546,6 +560,11 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
|
|||
// Record types and typedef information.
|
||||
var conv typeConv
|
||||
conv.Init(p.PtrSize, p.IntSize)
|
||||
for i, n := range names {
|
||||
if strings.HasSuffix(n.Go, "GetTypeID") && types[i].String() == "func() CFTypeID" {
|
||||
conv.getTypeIDs[n.Go[:len(n.Go)-9]] = true
|
||||
}
|
||||
}
|
||||
for i, n := range names {
|
||||
if types[i] == nil {
|
||||
continue
|
||||
|
|
@ -1642,6 +1661,9 @@ type typeConv struct {
|
|||
// Keys of ptrs in insertion order (deterministic worklist)
|
||||
ptrKeys []dwarf.Type
|
||||
|
||||
// Type names X for which there exists an XGetTypeID function with type func() CFTypeID.
|
||||
getTypeIDs map[string]bool
|
||||
|
||||
// Predeclared types.
|
||||
bool ast.Expr
|
||||
byte ast.Expr // denotes padding
|
||||
|
|
@ -1671,6 +1693,7 @@ func (c *typeConv) Init(ptrSize, intSize int64) {
|
|||
c.intSize = intSize
|
||||
c.m = make(map[dwarf.Type]*Type)
|
||||
c.ptrs = make(map[dwarf.Type][]*Type)
|
||||
c.getTypeIDs = make(map[string]bool)
|
||||
c.bool = c.Ident("bool")
|
||||
c.byte = c.Ident("byte")
|
||||
c.int8 = c.Ident("int8")
|
||||
|
|
@ -2057,7 +2080,7 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
|
|||
name := c.Ident("_Ctype_" + dt.Name)
|
||||
goIdent[name.Name] = name
|
||||
sub := c.Type(dt.Type, pos)
|
||||
if badPointerTypedef(dt) {
|
||||
if c.badPointerTypedef(dt) {
|
||||
// Treat this typedef as a uintptr.
|
||||
s := *sub
|
||||
s.Go = c.uintptr
|
||||
|
|
@ -2223,7 +2246,7 @@ func (c *typeConv) FuncArg(dtype dwarf.Type, pos token.Pos) *Type {
|
|||
}
|
||||
// ...or the typedef is one in which we expect bad pointers.
|
||||
// It will be a uintptr instead of *X.
|
||||
if badPointerTypedef(dt) {
|
||||
if c.badPointerTypedef(dt) {
|
||||
break
|
||||
}
|
||||
|
||||
|
|
@ -2571,23 +2594,43 @@ func fieldPrefix(fld []*ast.Field) string {
|
|||
// A typedef is bad if C code sometimes stores non-pointers in this type.
|
||||
// TODO: Currently our best solution is to find these manually and list them as
|
||||
// they come up. A better solution is desired.
|
||||
func badPointerTypedef(dt *dwarf.TypedefType) bool {
|
||||
if badCFType(dt) {
|
||||
func (c *typeConv) badPointerTypedef(dt *dwarf.TypedefType) bool {
|
||||
if c.badCFType(dt) {
|
||||
return true
|
||||
}
|
||||
if badJNI(dt) {
|
||||
if c.badJNI(dt) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func badCFType(dt *dwarf.TypedefType) bool {
|
||||
func (c *typeConv) badCFType(dt *dwarf.TypedefType) bool {
|
||||
// The real bad types are CFNumberRef and CFDateRef.
|
||||
// Sometimes non-pointers are stored in these types.
|
||||
// CFTypeRef is a supertype of those, so it can have bad pointers in it as well.
|
||||
// We return true for the other CF*Ref types just so casting between them is easier.
|
||||
// We return true for the other *Ref types just so casting between them is easier.
|
||||
// We identify the correct set of types as those ending in Ref and for which
|
||||
// there exists a corresponding GetTypeID function.
|
||||
// See comment below for details about the bad pointers.
|
||||
return goos == "darwin" && strings.HasPrefix(dt.Name, "CF") && strings.HasSuffix(dt.Name, "Ref")
|
||||
if goos != "darwin" {
|
||||
return false
|
||||
}
|
||||
s := dt.Name
|
||||
if !strings.HasSuffix(s, "Ref") {
|
||||
return false
|
||||
}
|
||||
s = s[:len(s)-3]
|
||||
if s == "CFType" {
|
||||
return true
|
||||
}
|
||||
if c.getTypeIDs[s] {
|
||||
return true
|
||||
}
|
||||
if i := strings.Index(s, "Mutable"); i >= 0 && c.getTypeIDs[s[:i]+s[i+7:]] {
|
||||
// Mutable and immutable variants share a type ID.
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Comment from Darwin's CFInternal.h
|
||||
|
|
@ -2625,7 +2668,7 @@ enum {
|
|||
};
|
||||
*/
|
||||
|
||||
func badJNI(dt *dwarf.TypedefType) bool {
|
||||
func (c *typeConv) badJNI(dt *dwarf.TypedefType) bool {
|
||||
// In Dalvik and ART, the jobject type in the JNI interface of the JVM has the
|
||||
// property that it is sometimes (always?) a small integer instead of a real pointer.
|
||||
// Note: although only the android JVMs are bad in this respect, we declare the JNI types
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue