Skip to content

Commit 462e902

Browse files
committed
runtime: keep FuncForPC from crashing for PCs between functions
Reuse the strict mechanism from FileLine for FuncForPC, so we don't crash when asking the pcln table about bad pcs. Fixes #29735 Change-Id: Iaffb32498b8586ecf4eae03823e8aecef841aa68 Reviewed-on: https://go-review.googlesource.com/c/157799 Reviewed-by: Josh Bleecher Snyder <[email protected]> Run-TryBot: Josh Bleecher Snyder <[email protected]> TryBot-Result: Gobot Gobot <[email protected]>
1 parent e1d20ce commit 462e902

File tree

2 files changed

+50
-3
lines changed

2 files changed

+50
-3
lines changed

src/runtime/symtab.go

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,11 @@ func FuncForPC(pc uintptr) *Func {
474474
return nil
475475
}
476476
if inldata := funcdata(f, _FUNCDATA_InlTree); inldata != nil {
477-
if ix := pcdatavalue(f, _PCDATA_InlTreeIndex, pc, nil); ix >= 0 {
477+
// Note: strict=false so bad PCs (those between functions) don't crash the runtime.
478+
// We just report the preceeding function in that situation. See issue 29735.
479+
// TODO: Perhaps we should report no function at all in that case.
480+
// The runtime currently doesn't have function end info, alas.
481+
if ix := pcdatavalue1(f, _PCDATA_InlTreeIndex, pc, nil, false); ix >= 0 {
478482
inltree := (*[1 << 20]inlinedCall)(inldata)
479483
name := funcnameFromNameoff(f, inltree[ix].func_)
480484
file, line := funcline(f, pc)
@@ -756,12 +760,22 @@ func funcspdelta(f funcInfo, targetpc uintptr, cache *pcvalueCache) int32 {
756760
return x
757761
}
758762

763+
func pcdatastart(f funcInfo, table int32) int32 {
764+
return *(*int32)(add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(table)*4))
765+
}
766+
759767
func pcdatavalue(f funcInfo, table int32, targetpc uintptr, cache *pcvalueCache) int32 {
760768
if table < 0 || table >= f.npcdata {
761769
return -1
762770
}
763-
off := *(*int32)(add(unsafe.Pointer(&f.nfuncdata), unsafe.Sizeof(f.nfuncdata)+uintptr(table)*4))
764-
return pcvalue(f, off, targetpc, cache, true)
771+
return pcvalue(f, pcdatastart(f, table), targetpc, cache, true)
772+
}
773+
774+
func pcdatavalue1(f funcInfo, table int32, targetpc uintptr, cache *pcvalueCache, strict bool) int32 {
775+
if table < 0 || table >= f.npcdata {
776+
return -1
777+
}
778+
return pcvalue(f, pcdatastart(f, table), targetpc, cache, strict)
765779
}
766780

767781
func funcdata(f funcInfo, i uint8) unsafe.Pointer {

test/fixedbugs/issue29735.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
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 FuncForPC won't panic when given a pc which
8+
// lies between two functions.
9+
10+
package main
11+
12+
import (
13+
"runtime"
14+
)
15+
16+
func main() {
17+
var stack [1]uintptr
18+
runtime.Callers(1, stack[:])
19+
f() // inlined function, to give main some inlining info
20+
for i := uintptr(0); true; i++ {
21+
f := runtime.FuncForPC(stack[0] + i)
22+
if f.Name() != "main.main" && f.Name() != "main.f" {
23+
// Reached next function successfully.
24+
break
25+
}
26+
}
27+
}
28+
29+
func f() {
30+
sink = 0 // one instruction which can't be removed
31+
}
32+
33+
var sink int

0 commit comments

Comments
 (0)