]> Cypherpunks repositories - gostls13.git/commitdiff
[release-branch.go1.16] cmd/compile: fix mishandling of unsafe-uintptr arguments...
authorCuong Manh Le <cuong.manhle.vn@gmail.com>
Fri, 26 Feb 2021 03:17:09 +0000 (10:17 +0700)
committerDmitri Shuralyov <dmitshur@golang.org>
Mon, 1 Mar 2021 20:38:01 +0000 (20:38 +0000)
In CL 253457, we did the same fix for direct function calls. But for
method calls, the receiver argument also need to be passed through the
wrapper function, which we are not doing so the compiler crashes with
the code in #44415.

It will be nicer if we can rewrite OCALLMETHOD to normal OCALLFUNC, but
that will be for future CL. The passing receiver argument to wrapper
function is easier for backporting to go1.16 branch.

Fixes #44464

Change-Id: I03607a64429042c6066ce673931db9769deb3124
Reviewed-on: https://go-review.googlesource.com/c/go/+/296490
Trust: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-on: https://go-review.googlesource.com/c/go/+/296769
Trust: Bryan C. Mills <bcmills@google.com>

src/cmd/compile/internal/gc/walk.go
test/fixedbugs/issue24491a.go

index 98ebb2399179f28996da59d90a9444221db75a90..02a7269ff83ed4538818108fd04f9cf10c00a770 100644 (file)
@@ -3927,15 +3927,22 @@ func wrapCall(n *Node, init *Nodes) *Node {
                }
        }
 
+       wrapArgs := n.List.Slice()
+       // If there's a receiver argument, it needs to be passed through the wrapper too.
+       if n.Op == OCALLMETH || n.Op == OCALLINTER {
+               recv := n.Left.Left
+               wrapArgs = append([]*Node{recv}, wrapArgs...)
+       }
+
        // origArgs keeps track of what argument is uintptr-unsafe/unsafe-uintptr conversion.
-       origArgs := make([]*Node, n.List.Len())
+       origArgs := make([]*Node, len(wrapArgs))
        t := nod(OTFUNC, nil, nil)
-       for i, arg := range n.List.Slice() {
+       for i, arg := range wrapArgs {
                s := lookupN("a", i)
                if !isBuiltinCall && arg.Op == OCONVNOP && arg.Type.IsUintptr() && arg.Left.Type.IsUnsafePtr() {
                        origArgs[i] = arg
                        arg = arg.Left
-                       n.List.SetIndex(i, arg)
+                       wrapArgs[i] = arg
                }
                t.List.Append(symfield(s, arg.Type))
        }
@@ -3953,6 +3960,12 @@ func wrapCall(n *Node, init *Nodes) *Node {
                arg.Type = origArg.Type
                args[i] = arg
        }
+       if n.Op == OCALLMETH || n.Op == OCALLINTER {
+               // Move wrapped receiver argument back to its appropriate place.
+               recv := typecheck(args[0], ctxExpr)
+               n.Left.Left = recv
+               args = args[1:]
+       }
        call := nod(n.Op, nil, nil)
        if !isBuiltinCall {
                call.Op = OCALL
@@ -3970,7 +3983,7 @@ func wrapCall(n *Node, init *Nodes) *Node {
 
        call = nod(OCALL, nil, nil)
        call.Left = fn.Func.Nname
-       call.List.Set(n.List.Slice())
+       call.List.Set(wrapArgs)
        call = typecheck(call, ctxStmt)
        call = walkexpr(call, init)
        return call
index 8accf8c0a376f0dca01e860560a1b2244c2f62e1..d30b65b233c98c90851fc52067bebec3d03424df 100644 (file)
@@ -48,6 +48,14 @@ func f() int {
        return test("return", uintptr(setup()), uintptr(setup()), uintptr(setup()), uintptr(setup()))
 }
 
+type S struct{}
+
+//go:noinline
+//go:uintptrescapes
+func (S) test(s string, p, q uintptr, rest ...uintptr) int {
+       return test(s, p, q, rest...)
+}
+
 func main() {
        test("normal", uintptr(setup()), uintptr(setup()), uintptr(setup()), uintptr(setup()))
        <-done
@@ -60,6 +68,29 @@ func main() {
        }()
        <-done
 
+       func() {
+               for {
+                       defer test("defer in for loop", uintptr(setup()), uintptr(setup()), uintptr(setup()), uintptr(setup()))
+                       break
+               }
+       }()
+
+       <-done
+       func() {
+               s := &S{}
+               defer s.test("method call", uintptr(setup()), uintptr(setup()), uintptr(setup()), uintptr(setup()))
+       }()
+       <-done
+
+       func() {
+               s := &S{}
+               for {
+                       defer s.test("defer method loop", uintptr(setup()), uintptr(setup()), uintptr(setup()), uintptr(setup()))
+                       break
+               }
+       }()
+       <-done
+
        f()
        <-done
 }