mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
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 <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>
This commit is contained in:
parent
ee2a45e5fb
commit
1a3e968b1f
4 changed files with 72 additions and 14 deletions
|
|
@ -503,21 +503,8 @@ func walkCall1(n *ir.CallExpr, init *ir.Nodes) {
|
||||||
}
|
}
|
||||||
n.SetWalked(true)
|
n.SetWalked(true)
|
||||||
|
|
||||||
// If this is a method call t.M(...),
|
|
||||||
// rewrite into a function call T.M(t, ...).
|
|
||||||
// TODO(mdempsky): Do this right after type checking.
|
// TODO(mdempsky): Do this right after type checking.
|
||||||
if n.Op() == ir.OCALLMETH {
|
rewriteMethodCall(n)
|
||||||
withRecv := make([]ir.Node, len(n.Args)+1)
|
|
||||||
dot := n.X.(*ir.SelectorExpr)
|
|
||||||
withRecv[0] = dot.X
|
|
||||||
copy(withRecv[1:], n.Args)
|
|
||||||
n.Args = withRecv
|
|
||||||
|
|
||||||
dot = ir.NewSelectorExpr(dot.Pos(), ir.OXDOT, ir.TypeNode(dot.X.Type()), dot.Selection.Sym)
|
|
||||||
|
|
||||||
n.SetOp(ir.OCALLFUNC)
|
|
||||||
n.X = typecheck.Expr(dot)
|
|
||||||
}
|
|
||||||
|
|
||||||
args := n.Args
|
args := n.Args
|
||||||
params := n.X.Type().Params()
|
params := n.X.Type().Params()
|
||||||
|
|
@ -547,6 +534,23 @@ func walkCall1(n *ir.CallExpr, init *ir.Nodes) {
|
||||||
n.Args = args
|
n.Args = args
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// rewriteMethodCall rewrites a method call t.M(...) into a function call T.M(t, ...).
|
||||||
|
func rewriteMethodCall(n *ir.CallExpr) {
|
||||||
|
if n.Op() != ir.OCALLMETH {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
withRecv := make([]ir.Node, len(n.Args)+1)
|
||||||
|
dot := n.X.(*ir.SelectorExpr)
|
||||||
|
withRecv[0] = dot.X
|
||||||
|
copy(withRecv[1:], n.Args)
|
||||||
|
n.Args = withRecv
|
||||||
|
|
||||||
|
dot = ir.NewSelectorExpr(dot.Pos(), ir.OXDOT, ir.TypeNode(dot.X.Type()), dot.Selection.Sym)
|
||||||
|
|
||||||
|
n.SetOp(ir.OCALLFUNC)
|
||||||
|
n.X = typecheck.Expr(dot)
|
||||||
|
}
|
||||||
|
|
||||||
// walkDivMod walks an ODIV or OMOD node.
|
// walkDivMod walks an ODIV or OMOD node.
|
||||||
func walkDivMod(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
|
func walkDivMod(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
|
||||||
n.X = walkExpr(n.X, init)
|
n.X = walkExpr(n.X, init)
|
||||||
|
|
|
||||||
|
|
@ -241,6 +241,9 @@ func wrapCall(n *ir.CallExpr, init *ir.Nodes) ir.Node {
|
||||||
init.Append(ir.TakeInit(n)...)
|
init.Append(ir.TakeInit(n)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(mdempsky): Do this right after type checking.
|
||||||
|
rewriteMethodCall(n)
|
||||||
|
|
||||||
isBuiltinCall := n.Op() != ir.OCALLFUNC && n.Op() != ir.OCALLMETH && n.Op() != ir.OCALLINTER
|
isBuiltinCall := n.Op() != ir.OCALLFUNC && n.Op() != ir.OCALLMETH && n.Op() != ir.OCALLINTER
|
||||||
|
|
||||||
// Turn f(a, b, []T{c, d, e}...) back into f(a, b, c, d, e).
|
// Turn f(a, b, []T{c, d, e}...) back into f(a, b, c, d, e).
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,30 @@ func f() int {
|
||||||
return test("return", uintptr(setup()), uintptr(setup()), uintptr(setup()), uintptr(setup()))
|
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 {
|
||||||
|
runtime.GC()
|
||||||
|
runtime.GC()
|
||||||
|
|
||||||
|
if *(*string)(unsafe.Pointer(p)) != "ok" {
|
||||||
|
panic(s + ": p failed")
|
||||||
|
}
|
||||||
|
if *(*string)(unsafe.Pointer(q)) != "ok" {
|
||||||
|
panic(s + ": q failed")
|
||||||
|
}
|
||||||
|
for _, r := range rest {
|
||||||
|
if *(*string)(unsafe.Pointer(r)) != "ok" {
|
||||||
|
panic(s + ": r[i] failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
done <- true
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
test("normal", uintptr(setup()), uintptr(setup()), uintptr(setup()), uintptr(setup()))
|
test("normal", uintptr(setup()), uintptr(setup()), uintptr(setup()), uintptr(setup()))
|
||||||
<-done
|
<-done
|
||||||
|
|
@ -60,6 +84,12 @@ func main() {
|
||||||
}()
|
}()
|
||||||
<-done
|
<-done
|
||||||
|
|
||||||
|
func() {
|
||||||
|
s := &S{}
|
||||||
|
defer s.test("method call", uintptr(setup()), uintptr(setup()))
|
||||||
|
}()
|
||||||
|
<-done
|
||||||
|
|
||||||
f()
|
f()
|
||||||
<-done
|
<-done
|
||||||
}
|
}
|
||||||
|
|
|
||||||
21
test/fixedbugs/issue44415.go
Normal file
21
test/fixedbugs/issue44415.go
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
// compile
|
||||||
|
|
||||||
|
// Copyright 2021 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package p
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
var dllKernel = syscall.NewLazyDLL("Kernel32.dll")
|
||||||
|
|
||||||
|
func Call() {
|
||||||
|
procLocalFree := dllKernel.NewProc("LocalFree")
|
||||||
|
defer procLocalFree.Call(uintptr(unsafe.Pointer(nil)))
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue