Skip to content

Commit

Permalink
cmd/cgo: fix use of unsafe argument in new deferred function
Browse files Browse the repository at this point in the history
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: Austin Clements <austin@google.com>
  • Loading branch information
ianlancetaylor committed Jun 9, 2016
1 parent 837984f commit 1bdf1c3
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 9 deletions.
28 changes: 21 additions & 7 deletions src/cmd/cgo/gcc.go
Expand Up @@ -657,7 +657,7 @@ func (p *Package) rewriteCall(f *File, call *Call, name *Name) {
// Instead we use a local variant of _cgoCheckPointer.

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)
arg = c
} else {
Expand Down Expand Up @@ -939,20 +939,31 @@ func (p *Package) isType(t ast.Expr) bool {
// 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 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) {
return ""
}
var buf bytes.Buffer
conf.Fprint(&buf, fset, t)
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 {
return p.unsafeCheckPointerNameIndex(i)
return p.unsafeCheckPointerNameIndex(i, deferred)
}
}
p.CgoChecks = append(p.CgoChecks, s)
return p.unsafeCheckPointerNameIndex(len(p.CgoChecks) - 1)
*checks = append(*checks, s)
return p.unsafeCheckPointerNameIndex(len(*checks)-1, deferred)
}

// hasUnsafePointer returns whether the Go type t uses unsafe.Pointer.
Expand Down Expand Up @@ -980,7 +991,10 @@ func (p *Package) hasUnsafePointer(t ast.Expr) bool {

// unsafeCheckPointerNameIndex returns the name to use for a
// _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)
}

Expand Down
5 changes: 4 additions & 1 deletion src/cmd/cgo/main.go
Expand Up @@ -42,7 +42,10 @@ type Package struct {
GoFiles []string // list of Go files
GccFiles []string // list of gcc output files
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.
Expand Down
8 changes: 7 additions & 1 deletion src/cmd/cgo/out.go
Expand Up @@ -112,11 +112,17 @@ func (p *Package) writeDefs() {
}

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, "\treturn _cgoCheckPointer(p, args...).(%s)\n", t)
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()

Expand Down

0 comments on commit 1bdf1c3

Please sign in to comment.