]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/cgo: fix use of unsafe argument in new deferred function
authorIan Lance Taylor <iant@golang.org>
Thu, 9 Jun 2016 18:19:26 +0000 (11:19 -0700)
committerIan Lance Taylor <iant@golang.org>
Thu, 9 Jun 2016 19:05:19 +0000 (19:05 +0000)
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>
src/cmd/cgo/gcc.go
src/cmd/cgo/main.go
src/cmd/cgo/out.go

index 21854c5ea326f7a4c4686a6152eb2e65330734d8..3766ff27f0982ae7b613e84f91a01493650bf19b 100644 (file)
@@ -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)
 }
 
index e2a387a09d33f150a1613ceb1c2029ad89dfcd8a..72ac19ad3972ca44317b7cf079b2d77a43acac75 100644 (file)
@@ -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.
index 294c27994e3af0ff87fb8c2b914a698940b18c00..842b1c5ef8081c25b178c56450e7e6f774b8538a 100644 (file)
@@ -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()