Skip to content

Commit a6178d8

Browse files
randall77dmitshur
authored andcommitted
[release-branch.go1.12] cmd/link: fix deferreturn detector
The logic for detecting deferreturn calls is wrong. We used to look for a relocation whose symbol is runtime.deferreturn and has an offset of 0. But on some architectures, the relocation offset is not zero. These include arm (the offset is 0xebfffffe) and s390x (the offset is 6). This ends up setting the deferreturn offset at 0, so we end up using the entry point live map instead of the deferreturn live map in a frame which defers and then segfaults. Instead, use the IsDirectJump helper to find calls. Fixes #32484 Change-Id: Iecb530a7cf6eabd7233be7d0731ffa78873f3a54 Reviewed-on: https://go-review.googlesource.com/c/go/+/181258 Run-TryBot: Keith Randall <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Cherry Zhang <[email protected]> (cherry picked from commit 9eb4031) Reviewed-on: https://go-review.googlesource.com/c/go/+/181262 Reviewed-by: Emmanuel Odeke <[email protected]> Run-TryBot: Emmanuel Odeke <[email protected]>
1 parent 3887549 commit a6178d8

File tree

2 files changed

+72
-1
lines changed

2 files changed

+72
-1
lines changed

src/cmd/link/internal/ld/pcln.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ func (ctxt *Link) pclntab() {
325325
// set the resumption point to PC_B.
326326
lastWasmAddr = uint32(r.Add)
327327
}
328-
if r.Sym != nil && r.Sym.Name == "runtime.deferreturn" && r.Add == 0 {
328+
if r.Type.IsDirectJump() && r.Sym != nil && r.Sym.Name == "runtime.deferreturn" {
329329
if ctxt.Arch.Family == sys.Wasm {
330330
deferreturn = lastWasmAddr
331331
} else {

test/fixedbugs/issue32477.go

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// run
2+
3+
// Copyright 2019 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+
// Make sure we use the deferreturn live map instead of
8+
// the entry live map when handling a segv in a function
9+
// that defers.
10+
11+
package main
12+
13+
import "runtime"
14+
15+
var finalized bool
16+
var err string
17+
18+
type HeapObj [8]int64
19+
20+
const filler int64 = 0x123456789abcdef0
21+
22+
func (h *HeapObj) init() {
23+
for i := 0; i < len(*h); i++ {
24+
h[i] = filler
25+
}
26+
}
27+
func (h *HeapObj) check() {
28+
for i := 0; i < len(*h); i++ {
29+
if h[i] != filler {
30+
err = "filler overwritten"
31+
}
32+
}
33+
}
34+
35+
func gc(shouldFinalize bool) {
36+
runtime.GC()
37+
runtime.GC()
38+
runtime.GC()
39+
if shouldFinalize != finalized {
40+
err = "heap object finalized at the wrong time"
41+
}
42+
}
43+
44+
func main() {
45+
h := new(HeapObj)
46+
h.init()
47+
runtime.SetFinalizer(h, func(h *HeapObj) {
48+
finalized = true
49+
})
50+
51+
gc(false)
52+
g(h)
53+
if err != "" {
54+
panic(err)
55+
}
56+
}
57+
58+
func g(h *HeapObj) {
59+
gc(false)
60+
h.check()
61+
// h is now unused
62+
defer func() {
63+
// h should not be live here. Previously we used to
64+
// use the function entry point as the place to get
65+
// the live map when handling a segv.
66+
gc(true)
67+
recover()
68+
}()
69+
*(*int)(nil) = 0 // trigger a segv
70+
return
71+
}

0 commit comments

Comments
 (0)