aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2016-06-09 11:19:26 -0700
committerIan Lance Taylor <iant@golang.org>2016-06-09 19:05:19 +0000
commit1bdf1c3024d75a3c4913d031d55257b311f0133f (patch)
tree32fefa0986962617003440e2bec71000155580eb
parent837984f37291f4fc48f9c99b65b0ab3f050bf4b9 (diff)
downloadgo-1bdf1c3024d75a3c4913d031d55257b311f0133f.tar.gz
go-1bdf1c3024d75a3c4913d031d55257b311f0133f.zip
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: Austin Clements <austin@google.com>
-rw-r--r--src/cmd/cgo/gcc.go28
-rw-r--r--src/cmd/cgo/main.go5
-rw-r--r--src/cmd/cgo/out.go8
3 files changed, 32 insertions, 9 deletions
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
index 21854c5ea3..3766ff27f0 100644
--- a/src/cmd/cgo/gcc.go
+++ b/src/cmd/cgo/gcc.go
@@ -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 {
@@ -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.
@@ -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)
}
diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go
index e2a387a09d..72ac19ad39 100644
--- a/src/cmd/cgo/main.go
+++ b/src/cmd/cgo/main.go
@@ -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.
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
index 294c27994e..842b1c5ef8 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -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()