Skip to content

Commit 1a3e968

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. As we already rewrite t.M(...) into T.M(t, ...) during walkCall1, to fix this, we can do the same trick in wrapCall, so the receiver argument will be treated as others. Fixes #44415 Change-Id: I396182983c85d9c5e4494657da79d25636e8a079 Reviewed-on: https://go-review.googlesource.com/c/go/+/294849 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 ee2a45e commit 1a3e968

File tree

4 files changed

+72
-14
lines changed

4 files changed

+72
-14
lines changed

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

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -503,21 +503,8 @@ func walkCall1(n *ir.CallExpr, init *ir.Nodes) {
503503
}
504504
n.SetWalked(true)
505505

506-
// If this is a method call t.M(...),
507-
// rewrite into a function call T.M(t, ...).
508506
// TODO(mdempsky): Do this right after type checking.
509-
if n.Op() == ir.OCALLMETH {
510-
withRecv := make([]ir.Node, len(n.Args)+1)
511-
dot := n.X.(*ir.SelectorExpr)
512-
withRecv[0] = dot.X
513-
copy(withRecv[1:], n.Args)
514-
n.Args = withRecv
515-
516-
dot = ir.NewSelectorExpr(dot.Pos(), ir.OXDOT, ir.TypeNode(dot.X.Type()), dot.Selection.Sym)
517-
518-
n.SetOp(ir.OCALLFUNC)
519-
n.X = typecheck.Expr(dot)
520-
}
507+
rewriteMethodCall(n)
521508

522509
args := n.Args
523510
params := n.X.Type().Params()
@@ -547,6 +534,23 @@ func walkCall1(n *ir.CallExpr, init *ir.Nodes) {
547534
n.Args = args
548535
}
549536

537+
// rewriteMethodCall rewrites a method call t.M(...) into a function call T.M(t, ...).
538+
func rewriteMethodCall(n *ir.CallExpr) {
539+
if n.Op() != ir.OCALLMETH {
540+
return
541+
}
542+
withRecv := make([]ir.Node, len(n.Args)+1)
543+
dot := n.X.(*ir.SelectorExpr)
544+
withRecv[0] = dot.X
545+
copy(withRecv[1:], n.Args)
546+
n.Args = withRecv
547+
548+
dot = ir.NewSelectorExpr(dot.Pos(), ir.OXDOT, ir.TypeNode(dot.X.Type()), dot.Selection.Sym)
549+
550+
n.SetOp(ir.OCALLFUNC)
551+
n.X = typecheck.Expr(dot)
552+
}
553+
550554
// walkDivMod walks an ODIV or OMOD node.
551555
func walkDivMod(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
552556
n.X = walkExpr(n.X, init)

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,9 @@ func wrapCall(n *ir.CallExpr, init *ir.Nodes) ir.Node {
241241
init.Append(ir.TakeInit(n)...)
242242
}
243243

244+
// TODO(mdempsky): Do this right after type checking.
245+
rewriteMethodCall(n)
246+
244247
isBuiltinCall := n.Op() != ir.OCALLFUNC && n.Op() != ir.OCALLMETH && n.Op() != ir.OCALLINTER
245248

246249
// Turn f(a, b, []T{c, d, e}...) back into f(a, b, c, d, e).

test/fixedbugs/issue24491a.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,30 @@ 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+
runtime.GC()
57+
runtime.GC()
58+
59+
if *(*string)(unsafe.Pointer(p)) != "ok" {
60+
panic(s + ": p failed")
61+
}
62+
if *(*string)(unsafe.Pointer(q)) != "ok" {
63+
panic(s + ": q failed")
64+
}
65+
for _, r := range rest {
66+
if *(*string)(unsafe.Pointer(r)) != "ok" {
67+
panic(s + ": r[i] failed")
68+
}
69+
}
70+
71+
done <- true
72+
return 0
73+
}
74+
5175
func main() {
5276
test("normal", uintptr(setup()), uintptr(setup()), uintptr(setup()), uintptr(setup()))
5377
<-done
@@ -60,6 +84,12 @@ func main() {
6084
}()
6185
<-done
6286

87+
func() {
88+
s := &S{}
89+
defer s.test("method call", uintptr(setup()), uintptr(setup()))
90+
}()
91+
<-done
92+
6393
f()
6494
<-done
6595
}

test/fixedbugs/issue44415.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// compile
2+
3+
// Copyright 2021 The Go Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file.
6+
7+
// +build windows
8+
9+
package p
10+
11+
import (
12+
"syscall"
13+
"unsafe"
14+
)
15+
16+
var dllKernel = syscall.NewLazyDLL("Kernel32.dll")
17+
18+
func Call() {
19+
procLocalFree := dllKernel.NewProc("LocalFree")
20+
defer procLocalFree.Call(uintptr(unsafe.Pointer(nil)))
21+
}

0 commit comments

Comments
 (0)