Skip to content

Commit d7c6da8

Browse files
cuonglmcherrymui
authored andcommitted
[release-branch.go1.20] cmd/compile: fix unsafe.{SliceData,StringData} escape analysis memory corruption
Updates #57823 Updates #57854 Change-Id: I54654d3ecb20b75afa9052c5c9db2072a86188d4 Reviewed-on: https://go-review.googlesource.com/c/go/+/461759 Reviewed-by: Cherry Mui <[email protected]> Auto-Submit: Cuong Manh Le <[email protected]> Reviewed-by: Keith Randall <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Run-TryBot: Cuong Manh Le <[email protected]> Reviewed-by: Keith Randall <[email protected]> Reviewed-by: Matthew Dempsky <[email protected]> Reviewed-on: https://go-review.googlesource.com/c/go/+/461760
1 parent 9eed826 commit d7c6da8

File tree

2 files changed

+81
-1
lines changed

2 files changed

+81
-1
lines changed

src/cmd/compile/internal/escape/call.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -180,10 +180,14 @@ func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir
180180
argument(e.discardHole(), &call.Args[i])
181181
}
182182

183-
case ir.OLEN, ir.OCAP, ir.OREAL, ir.OIMAG, ir.OCLOSE, ir.OUNSAFESTRINGDATA, ir.OUNSAFESLICEDATA:
183+
case ir.OLEN, ir.OCAP, ir.OREAL, ir.OIMAG, ir.OCLOSE:
184184
call := call.(*ir.UnaryExpr)
185185
argument(e.discardHole(), &call.X)
186186

187+
case ir.OUNSAFESTRINGDATA, ir.OUNSAFESLICEDATA:
188+
call := call.(*ir.UnaryExpr)
189+
argument(ks[0], &call.X)
190+
187191
case ir.OUNSAFEADD, ir.OUNSAFESLICE, ir.OUNSAFESTRING:
188192
call := call.(*ir.BinaryExpr)
189193
argument(ks[0], &call.X)

test/fixedbugs/issue57823.go

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// run
2+
3+
// Copyright 2023 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+
package main
8+
9+
import (
10+
"runtime"
11+
"unsafe"
12+
)
13+
14+
//go:noinline
15+
func g(x *byte) *byte { return x }
16+
17+
func main() {
18+
slice()
19+
str("AAAAAAAA", "BBBBBBBBB")
20+
}
21+
22+
func wait(done <-chan struct{}) bool {
23+
for i := 0; i < 10; i++ {
24+
runtime.GC()
25+
select {
26+
case <-done:
27+
return true
28+
default:
29+
}
30+
}
31+
return false
32+
}
33+
34+
func slice() {
35+
s := make([]byte, 100)
36+
s[0] = 1
37+
one := unsafe.SliceData(s)
38+
39+
done := make(chan struct{})
40+
runtime.SetFinalizer(one, func(*byte) { close(done) })
41+
42+
h := g(one)
43+
44+
if wait(done) {
45+
panic("GC'd early")
46+
}
47+
48+
if *h != 1 {
49+
panic("lost one")
50+
}
51+
52+
if !wait(done) {
53+
panic("never GC'd")
54+
}
55+
}
56+
57+
var strDone = make(chan struct{})
58+
59+
//go:noinline
60+
func str(x, y string) {
61+
s := x + y // put in temporary on stack
62+
p := unsafe.StringData(s)
63+
runtime.SetFinalizer(p, func(*byte) { close(strDone) })
64+
65+
if wait(strDone) {
66+
panic("GC'd early")
67+
}
68+
69+
if *p != 'A' {
70+
panic("lost p")
71+
}
72+
73+
if !wait(strDone) {
74+
panic("never GC'd")
75+
}
76+
}

0 commit comments

Comments
 (0)