Commit 1bdf1c30 authored by Ian Lance Taylor's avatar Ian Lance Taylor

cmd/cgo: fix use of unsafe argument in new deferred function

The combination of https://golang.org/cl/23650 and
https://golang.org/cl/23675 did not work--they were tested separately
but not together.

The problem was that 23650 introduced deferred argument checking, and
the deferred function loses the type that 23675 started requiring. The
fix is to go back to using an empty interface type in a deferred
argument check.

No new test required--fixes broken build.

Change-Id: I5ea023c5aed71d70e57b11c4551242d3ef25986d
Reviewed-on: https://go-review.googlesource.com/23961
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: 's avatarAustin Clements <austin@google.com>
parent 837984f3
...@@ -657,7 +657,7 @@ func (p *Package) rewriteCall(f *File, call *Call, name *Name) { ...@@ -657,7 +657,7 @@ func (p *Package) rewriteCall(f *File, call *Call, name *Name) {
// Instead we use a local variant of _cgoCheckPointer. // Instead we use a local variant of _cgoCheckPointer.
var arg ast.Expr var arg ast.Expr
if n := p.unsafeCheckPointerName(param.Go); n != "" { if n := p.unsafeCheckPointerName(param.Go, call.Deferred); n != "" {
c.Fun = ast.NewIdent(n) c.Fun = ast.NewIdent(n)
arg = c arg = c
} else { } else {
...@@ -939,20 +939,31 @@ func (p *Package) isType(t ast.Expr) bool { ...@@ -939,20 +939,31 @@ func (p *Package) isType(t ast.Expr) bool {
// assertion to unsafe.Pointer in our copy of user code. We return // assertion to unsafe.Pointer in our copy of user code. We return
// the name of the _cgoCheckPointer function we are going to build, or // the name of the _cgoCheckPointer function we are going to build, or
// the empty string if the type does not use unsafe.Pointer. // the empty string if the type does not use unsafe.Pointer.
func (p *Package) unsafeCheckPointerName(t ast.Expr) string { //
// The deferred parameter is true if this check is for the argument of
// a deferred function. In that case we need to use an empty interface
// as the argument type, because the deferred function we introduce in
// rewriteCall will use an empty interface type, and we can't add a
// type assertion. This is handled by keeping a separate list, and
// writing out the lists separately in writeDefs.
func (p *Package) unsafeCheckPointerName(t ast.Expr, deferred bool) string {
if !p.hasUnsafePointer(t) { if !p.hasUnsafePointer(t) {
return "" return ""
} }
var buf bytes.Buffer var buf bytes.Buffer
conf.Fprint(&buf, fset, t) conf.Fprint(&buf, fset, t)
s := buf.String() s := buf.String()
for i, t := range p.CgoChecks { checks := &p.CgoChecks
if deferred {
checks = &p.DeferredCgoChecks
}
for i, t := range *checks {
if s == t { if s == t {
return p.unsafeCheckPointerNameIndex(i) return p.unsafeCheckPointerNameIndex(i, deferred)
} }
} }
p.CgoChecks = append(p.CgoChecks, s) *checks = append(*checks, s)
return p.unsafeCheckPointerNameIndex(len(p.CgoChecks) - 1) return p.unsafeCheckPointerNameIndex(len(*checks)-1, deferred)
} }
// hasUnsafePointer returns whether the Go type t uses unsafe.Pointer. // hasUnsafePointer returns whether the Go type t uses unsafe.Pointer.
...@@ -980,7 +991,10 @@ func (p *Package) hasUnsafePointer(t ast.Expr) bool { ...@@ -980,7 +991,10 @@ func (p *Package) hasUnsafePointer(t ast.Expr) bool {
// unsafeCheckPointerNameIndex returns the name to use for a // unsafeCheckPointerNameIndex returns the name to use for a
// _cgoCheckPointer variant based on the index in the CgoChecks slice. // _cgoCheckPointer variant based on the index in the CgoChecks slice.
func (p *Package) unsafeCheckPointerNameIndex(i int) string { func (p *Package) unsafeCheckPointerNameIndex(i int, deferred bool) string {
if deferred {
return fmt.Sprintf("_cgoCheckPointerInDefer%d", i)
}
return fmt.Sprintf("_cgoCheckPointer%d", i) return fmt.Sprintf("_cgoCheckPointer%d", i)
} }
......
...@@ -42,7 +42,10 @@ type Package struct { ...@@ -42,7 +42,10 @@ type Package struct {
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
CgoChecks []string // see unsafeCheckPointerName
// See unsafeCheckPointerName.
CgoChecks []string
DeferredCgoChecks []string
} }
// A File collects information about a single Go input file. // A File collects information about a single Go input file.
......
...@@ -112,11 +112,17 @@ func (p *Package) writeDefs() { ...@@ -112,11 +112,17 @@ func (p *Package) writeDefs() {
} }
for i, t := range p.CgoChecks { for i, t := range p.CgoChecks {
n := p.unsafeCheckPointerNameIndex(i) n := p.unsafeCheckPointerNameIndex(i, false)
fmt.Fprintf(fgo2, "\nfunc %s(p %s, args ...interface{}) %s {\n", n, t, t) fmt.Fprintf(fgo2, "\nfunc %s(p %s, args ...interface{}) %s {\n", n, t, t)
fmt.Fprintf(fgo2, "\treturn _cgoCheckPointer(p, args...).(%s)\n", t) fmt.Fprintf(fgo2, "\treturn _cgoCheckPointer(p, args...).(%s)\n", t)
fmt.Fprintf(fgo2, "}\n") fmt.Fprintf(fgo2, "}\n")
} }
for i, t := range p.DeferredCgoChecks {
n := p.unsafeCheckPointerNameIndex(i, true)
fmt.Fprintf(fgo2, "\nfunc %s(p interface{}, args ...interface{}) %s {\n", n, t)
fmt.Fprintf(fgo2, "\treturn _cgoCheckPointer(p, args...).(%s)\n", t)
fmt.Fprintf(fgo2, "}\n")
}
gccgoSymbolPrefix := p.gccgoSymbolPrefix() gccgoSymbolPrefix := p.gccgoSymbolPrefix()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment