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 in go/defer
Currently, the statement:
go g(uintptr(f()))
gets rewritten into:
tmp := f()
newproc(8, g, uintptr(tmp))
runtime.KeepAlive(tmp)
which doesn't guarantee that tmp is still alive by time the g call is
scheduled to run.
This CL fixes the issue, by wrapping g call in a closure:
go func(p unsafe.Pointer) {
g(uintptr(p))
}(f())
then this will be rewritten into:
tmp := f()
go func(p unsafe.Pointer) {
g(uintptr(p))
runtime.KeepAlive(p)
}(tmp)
runtime.KeepAlive(tmp) // superfluous, but harmless
So the unsafe.Pointer p will be kept alive at the time g call runs.
Updates #24491
Change-Id: Ic10821251cbb1b0073daec92b82a866c6ebaf567
Reviewed-on: https://go-review.googlesource.com/c/go/+/253457
Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
1e6ad65b43
commit
bdb480fd62
4 changed files with 117 additions and 24 deletions
|
|
@ -141,19 +141,20 @@ const (
|
|||
nodeInitorder, _ // tracks state during init1; two bits
|
||||
_, _ // second nodeInitorder bit
|
||||
_, nodeHasBreak
|
||||
_, nodeNoInline // used internally by inliner to indicate that a function call should not be inlined; set for OCALLFUNC and OCALLMETH only
|
||||
_, nodeImplicit // implicit OADDR or ODEREF; ++/-- statement represented as OASOP; or ANDNOT lowered to OAND
|
||||
_, nodeIsDDD // is the argument variadic
|
||||
_, nodeDiag // already printed error about this
|
||||
_, nodeColas // OAS resulting from :=
|
||||
_, nodeNonNil // guaranteed to be non-nil
|
||||
_, nodeTransient // storage can be reused immediately after this statement
|
||||
_, nodeBounded // bounds check unnecessary
|
||||
_, nodeHasCall // expression contains a function call
|
||||
_, nodeLikely // if statement condition likely
|
||||
_, nodeHasVal // node.E contains a Val
|
||||
_, nodeHasOpt // node.E contains an Opt
|
||||
_, nodeEmbedded // ODCLFIELD embedded type
|
||||
_, nodeNoInline // used internally by inliner to indicate that a function call should not be inlined; set for OCALLFUNC and OCALLMETH only
|
||||
_, nodeImplicit // implicit OADDR or ODEREF; ++/-- statement represented as OASOP; or ANDNOT lowered to OAND
|
||||
_, nodeIsDDD // is the argument variadic
|
||||
_, nodeDiag // already printed error about this
|
||||
_, nodeColas // OAS resulting from :=
|
||||
_, nodeNonNil // guaranteed to be non-nil
|
||||
_, nodeTransient // storage can be reused immediately after this statement
|
||||
_, nodeBounded // bounds check unnecessary
|
||||
_, nodeHasCall // expression contains a function call
|
||||
_, nodeLikely // if statement condition likely
|
||||
_, nodeHasVal // node.E contains a Val
|
||||
_, nodeHasOpt // node.E contains an Opt
|
||||
_, nodeEmbedded // ODCLFIELD embedded type
|
||||
_, nodeNeedsWrapper // OCALLxxx node that needs to be wrapped
|
||||
)
|
||||
|
||||
func (n *Node) Class() Class { return Class(n.flags.get3(nodeClass)) }
|
||||
|
|
@ -286,6 +287,20 @@ func (n *Node) SetIota(x int64) {
|
|||
n.Xoffset = x
|
||||
}
|
||||
|
||||
func (n *Node) NeedsWrapper() bool {
|
||||
return n.flags&nodeNeedsWrapper != 0
|
||||
}
|
||||
|
||||
// SetNeedsWrapper indicates that OCALLxxx node needs to be wrapped by a closure.
|
||||
func (n *Node) SetNeedsWrapper(b bool) {
|
||||
switch n.Op {
|
||||
case OCALLFUNC, OCALLMETH, OCALLINTER:
|
||||
default:
|
||||
Fatalf("Node.SetNeedsWrapper %v", n.Op)
|
||||
}
|
||||
n.flags.set(nodeNeedsWrapper, b)
|
||||
}
|
||||
|
||||
// mayBeShared reports whether n may occur in multiple places in the AST.
|
||||
// Extra care must be taken when mutating such a node.
|
||||
func (n *Node) mayBeShared() bool {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue