aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCuong Manh Le <cuong.manhle.vn@gmail.com>2021-02-26 10:17:09 +0700
committerDmitri Shuralyov <dmitshur@golang.org>2021-03-01 20:38:01 +0000
commitca9cd629fb0609c9a2b6f6bf91ac6c6d33071be6 (patch)
treeb00e3382357e59f44a1db9eb6edb88a6bd5b1b42
parent18e5d75ffb3c8d2be8c92f801aded70321e0b84b (diff)
downloadgo-ca9cd629fb0609c9a2b6f6bf91ac6c6d33071be6.tar.gz
go-ca9cd629fb0609c9a2b6f6bf91ac6c6d33071be6.zip
[release-branch.go1.16] cmd/compile: fix mishandling of unsafe-uintptr arguments with call method in go/defer
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>
-rw-r--r--src/cmd/compile/internal/gc/walk.go21
-rw-r--r--test/fixedbugs/issue24491a.go31
2 files changed, 48 insertions, 4 deletions
diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go
index 98ebb23991..02a7269ff8 100644
--- a/src/cmd/compile/internal/gc/walk.go
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -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
diff --git a/test/fixedbugs/issue24491a.go b/test/fixedbugs/issue24491a.go
index 8accf8c0a3..d30b65b233 100644
--- a/test/fixedbugs/issue24491a.go
+++ b/test/fixedbugs/issue24491a.go
@@ -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
}