Skip to content

Commit 23943a6

Browse files
committed
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 #44415 Change-Id: I03607a64429042c6066ce673931db9769deb3124 Reviewed-on: https://go-review.googlesource.com/c/go/+/296490 Trust: Cuong Manh Le <[email protected]> Run-TryBot: Cuong Manh Le <[email protected]> Reviewed-by: Matthew Dempsky <[email protected]> TryBot-Result: Go Bot <[email protected]>
1 parent e25040d commit 23943a6

File tree

2 files changed

+48
-4
lines changed

2 files changed

+48
-4
lines changed

src/cmd/compile/internal/walk/stmt.go

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -253,15 +253,22 @@ func wrapCall(n *ir.CallExpr, init *ir.Nodes) ir.Node {
253253
}
254254
}
255255

256+
wrapArgs := n.Args
257+
// If there's a receiver argument, it needs to be passed through the wrapper too.
258+
if n.Op() == ir.OCALLMETH || n.Op() == ir.OCALLINTER {
259+
recv := n.X.(*ir.SelectorExpr).X
260+
wrapArgs = append([]ir.Node{recv}, wrapArgs...)
261+
}
262+
256263
// origArgs keeps track of what argument is uintptr-unsafe/unsafe-uintptr conversion.
257-
origArgs := make([]ir.Node, len(n.Args))
264+
origArgs := make([]ir.Node, len(wrapArgs))
258265
var funcArgs []*ir.Field
259-
for i, arg := range n.Args {
266+
for i, arg := range wrapArgs {
260267
s := typecheck.LookupNum("a", i)
261268
if !isBuiltinCall && arg.Op() == ir.OCONVNOP && arg.Type().IsUintptr() && arg.(*ir.ConvExpr).X.Type().IsUnsafePtr() {
262269
origArgs[i] = arg
263270
arg = arg.(*ir.ConvExpr).X
264-
n.Args[i] = arg
271+
wrapArgs[i] = arg
265272
}
266273
funcArgs = append(funcArgs, ir.NewField(base.Pos, s, nil, arg.Type()))
267274
}
@@ -278,6 +285,12 @@ func wrapCall(n *ir.CallExpr, init *ir.Nodes) ir.Node {
278285
}
279286
args[i] = ir.NewConvExpr(base.Pos, origArg.Op(), origArg.Type(), args[i])
280287
}
288+
if n.Op() == ir.OCALLMETH || n.Op() == ir.OCALLINTER {
289+
// Move wrapped receiver argument back to its appropriate place.
290+
recv := typecheck.Expr(args[0])
291+
n.X.(*ir.SelectorExpr).X = recv
292+
args = args[1:]
293+
}
281294
call := ir.NewCallExpr(base.Pos, n.Op(), n.X, args)
282295
if !isBuiltinCall {
283296
call.SetOp(ir.OCALL)
@@ -291,6 +304,6 @@ func wrapCall(n *ir.CallExpr, init *ir.Nodes) ir.Node {
291304
typecheck.Stmts(fn.Body)
292305
typecheck.Target.Decls = append(typecheck.Target.Decls, fn)
293306

294-
call = ir.NewCallExpr(base.Pos, ir.OCALL, fn.Nname, n.Args)
307+
call = ir.NewCallExpr(base.Pos, ir.OCALL, fn.Nname, wrapArgs)
295308
return walkExpr(typecheck.Stmt(call), init)
296309
}

test/fixedbugs/issue24491a.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,14 @@ func f() int {
4848
return test("return", uintptr(setup()), uintptr(setup()), uintptr(setup()), uintptr(setup()))
4949
}
5050

51+
type S struct{}
52+
53+
//go:noinline
54+
//go:uintptrescapes
55+
func (S) test(s string, p, q uintptr, rest ...uintptr) int {
56+
return test(s, p, q, rest...)
57+
}
58+
5159
func main() {
5260
test("normal", uintptr(setup()), uintptr(setup()), uintptr(setup()), uintptr(setup()))
5361
<-done
@@ -60,6 +68,29 @@ func main() {
6068
}()
6169
<-done
6270

71+
func() {
72+
for {
73+
defer test("defer in for loop", uintptr(setup()), uintptr(setup()), uintptr(setup()), uintptr(setup()))
74+
break
75+
}
76+
}()
77+
78+
<-done
79+
func() {
80+
s := &S{}
81+
defer s.test("method call", uintptr(setup()), uintptr(setup()), uintptr(setup()), uintptr(setup()))
82+
}()
83+
<-done
84+
85+
func() {
86+
s := &S{}
87+
for {
88+
defer s.test("defer method loop", uintptr(setup()), uintptr(setup()), uintptr(setup()), uintptr(setup()))
89+
break
90+
}
91+
}()
92+
<-done
93+
6394
f()
6495
<-done
6596
}

0 commit comments

Comments
 (0)