Skip to content

Commit ff5bff8

Browse files
randall77andybons
authored andcommitted
[release-branch.go1.10] runtime: identify special functions by flag instead of address
When there are plugins, there may not be a unique copy of runtime functions like goexit, mcall, etc. So identifying them by entry address is problematic. Instead, keep track of each special function using a field in the symbol table. That way, multiple copies of the same runtime function will be treated identically. Fixes #24351 Fixes #23133 Change-Id: Iea3232df8a6af68509769d9ca618f530cc0f84fd Reviewed-on: https://go-review.googlesource.com/100739 Run-TryBot: Keith Randall <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> Reviewed-on: https://go-review.googlesource.com/102793 Run-TryBot: Andrew Bonventre <[email protected]> Reviewed-by: Keith Randall <[email protected]>
1 parent 76b63aa commit ff5bff8

File tree

11 files changed

+181
-84
lines changed

11 files changed

+181
-84
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2018 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package main
6+
7+
import "plugin"
8+
9+
func main() {
10+
p, err := plugin.Open("issue24351.so")
11+
if err != nil {
12+
panic(err)
13+
}
14+
f, err := p.Lookup("B")
15+
if err != nil {
16+
panic(err)
17+
}
18+
c := make(chan bool)
19+
f.(func(chan bool))(c)
20+
<-c
21+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright 2018 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package main
6+
7+
import "fmt"
8+
9+
func B(c chan bool) {
10+
go func() {
11+
fmt.Println(1.5)
12+
c <- true
13+
}()
14+
}

misc/cgo/testplugin/test.bash

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,8 @@ GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -o issue22175 src/issue22175/main.
8585
GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -o issue.22295.so issue22295.pkg
8686
GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -o issue22295 src/issue22295.pkg/main.go
8787
./issue22295
88+
89+
# Test for issue 24351
90+
GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -o issue24351.so src/issue24351/plugin.go
91+
GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -o issue24351 src/issue24351/main.go
92+
./issue24351

src/cmd/internal/objabi/funcid.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright 2018 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package objabi
6+
7+
// A FuncID identifies particular functions that need to be treated
8+
// specially by the runtime.
9+
// Note that in some situations involving plugins, there may be multiple
10+
// copies of a particular special runtime function.
11+
// Note: this list must match the list in runtime/symtab.go.
12+
type FuncID uint32
13+
14+
const (
15+
FuncID_normal FuncID = iota // not a special function
16+
FuncID_goexit
17+
FuncID_jmpdefer
18+
FuncID_mcall
19+
FuncID_morestack
20+
FuncID_mstart
21+
FuncID_rt0_go
22+
FuncID_asmcgocall
23+
FuncID_sigpanic
24+
FuncID_runfinq
25+
FuncID_bgsweep
26+
FuncID_forcegchelper
27+
FuncID_timerproc
28+
FuncID_gcBgMarkWorker
29+
FuncID_systemstack_switch
30+
FuncID_systemstack
31+
FuncID_cgocallback_gofunc
32+
FuncID_gogo
33+
FuncID_externalthreadhandler
34+
)

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

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -312,12 +312,47 @@ func (ctxt *Link) pclntab() {
312312
}
313313
off = int32(ftab.SetUint32(ctxt.Arch, int64(off), args))
314314

315-
// frame int32
316-
// This has been removed (it was never set quite correctly anyway).
317-
// Nothing should use it.
318-
// Leave an obviously incorrect value.
319-
// TODO: Remove entirely.
320-
off = int32(ftab.SetUint32(ctxt.Arch, int64(off), 0x1234567))
315+
// funcID uint32
316+
funcID := objabi.FuncID_normal
317+
switch s.Name {
318+
case "runtime.goexit":
319+
funcID = objabi.FuncID_goexit
320+
case "runtime.jmpdefer":
321+
funcID = objabi.FuncID_jmpdefer
322+
case "runtime.mcall":
323+
funcID = objabi.FuncID_mcall
324+
case "runtime.morestack":
325+
funcID = objabi.FuncID_morestack
326+
case "runtime.mstart":
327+
funcID = objabi.FuncID_mstart
328+
case "runtime.rt0_go":
329+
funcID = objabi.FuncID_rt0_go
330+
case "runtime.asmcgocall":
331+
funcID = objabi.FuncID_asmcgocall
332+
case "runtime.sigpanic":
333+
funcID = objabi.FuncID_sigpanic
334+
case "runtime.runfinq":
335+
funcID = objabi.FuncID_runfinq
336+
case "runtime.bgsweep":
337+
funcID = objabi.FuncID_bgsweep
338+
case "runtime.forcegchelper":
339+
funcID = objabi.FuncID_forcegchelper
340+
case "runtime.timerproc":
341+
funcID = objabi.FuncID_timerproc
342+
case "runtime.gcBgMarkWorker":
343+
funcID = objabi.FuncID_gcBgMarkWorker
344+
case "runtime.systemstack_switch":
345+
funcID = objabi.FuncID_systemstack_switch
346+
case "runtime.systemstack":
347+
funcID = objabi.FuncID_systemstack
348+
case "runtime.cgocallback_gofunc":
349+
funcID = objabi.FuncID_cgocallback_gofunc
350+
case "runtime.gogo":
351+
funcID = objabi.FuncID_gogo
352+
case "runtime.externalthreadhandler":
353+
funcID = objabi.FuncID_externalthreadhandler
354+
}
355+
off = int32(ftab.SetUint32(ctxt.Arch, int64(off), uint32(funcID)))
321356

322357
if pcln != &pclntabZpcln {
323358
renumberfiles(ctxt, pcln.File, &pcln.Pcfile)

src/runtime/os_windows.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -304,8 +304,6 @@ func osinit() {
304304

305305
disableWER()
306306

307-
externalthreadhandlerp = funcPC(externalthreadhandler)
308-
309307
initExceptionHandler()
310308

311309
stdcall2(_SetConsoleCtrlHandler, funcPC(ctrlhandler), 1)

src/runtime/proc.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,11 @@ func releaseSudog(s *sudog) {
393393

394394
// funcPC returns the entry PC of the function f.
395395
// It assumes that f is a func value. Otherwise the behavior is undefined.
396+
// CAREFUL: In programs with plugins, funcPC can return different values
397+
// for the same function (because there are actually multiple copies of
398+
// the same function in the address space). To be safe, don't use the
399+
// results of this function in any == expression. It is only safe to
400+
// use the result as an address at which to start executing code.
396401
//go:nosplit
397402
func funcPC(f interface{}) uintptr {
398403
return **(**uintptr)(add(unsafe.Pointer(&f), sys.PtrSize))
@@ -3798,8 +3803,8 @@ func setsSP(pc uintptr) bool {
37983803
// so assume the worst and stop traceback
37993804
return true
38003805
}
3801-
switch f.entry {
3802-
case gogoPC, systemstackPC, mcallPC, morestackPC:
3806+
switch f.funcID {
3807+
case funcID_gogo, funcID_systemstack, funcID_mcall, funcID_morestack:
38033808
return true
38043809
}
38053810
return false

src/runtime/runtime2.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -635,8 +635,8 @@ type _func struct {
635635
entry uintptr // start pc
636636
nameoff int32 // function name
637637

638-
args int32 // in/out args size
639-
_ int32 // previously legacy frame size; kept for layout compatibility
638+
args int32 // in/out args size
639+
funcID funcID // set for certain special runtime functions
640640

641641
pcsp int32
642642
pcfile int32

src/runtime/stack.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -619,7 +619,7 @@ func adjustframe(frame *stkframe, arg unsafe.Pointer) bool {
619619
if stackDebug >= 2 {
620620
print(" adjusting ", funcname(f), " frame=[", hex(frame.sp), ",", hex(frame.fp), "] pc=", hex(frame.pc), " continpc=", hex(frame.continpc), "\n")
621621
}
622-
if f.entry == systemstack_switchPC {
622+
if f.funcID == funcID_systemstack_switch {
623623
// A special routine at the bottom of stack of a goroutine that does an systemstack call.
624624
// We will allow it to be copied even though we don't
625625
// have full GC info for it (because it is written in asm).
@@ -1110,7 +1110,8 @@ func shrinkstack(gp *g) {
11101110
if debug.gcshrinkstackoff > 0 {
11111111
return
11121112
}
1113-
if gp.startpc == gcBgMarkWorkerPC {
1113+
f := findfunc(gp.startpc)
1114+
if f.valid() && f.funcID == funcID_gcBgMarkWorker {
11141115
// We're not allowed to shrink the gcBgMarkWorker
11151116
// stack (see gcBgMarkWorker for explanation).
11161117
return

src/runtime/symtab.go

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ again:
133133
}
134134
se.pcExpander.init(ncallers[0], se.wasPanic)
135135
ncallers = ncallers[1:]
136-
se.wasPanic = se.pcExpander.funcInfo.valid() && se.pcExpander.funcInfo.entry == sigpanicPC
136+
se.wasPanic = se.pcExpander.funcInfo.valid() && se.pcExpander.funcInfo.funcID == funcID_sigpanic
137137
if se.skip > 0 {
138138
for ; se.skip > 0; se.skip-- {
139139
se.pcExpander.next()
@@ -349,6 +349,35 @@ const (
349349
_ArgsSizeUnknown = -0x80000000
350350
)
351351

352+
// A FuncID identifies particular functions that need to be treated
353+
// specially by the runtime.
354+
// Note that in some situations involving plugins, there may be multiple
355+
// copies of a particular special runtime function.
356+
// Note: this list must match the list in cmd/internal/objabi/funcid.go.
357+
type funcID uint32
358+
359+
const (
360+
funcID_normal funcID = iota // not a special function
361+
funcID_goexit
362+
funcID_jmpdefer
363+
funcID_mcall
364+
funcID_morestack
365+
funcID_mstart
366+
funcID_rt0_go
367+
funcID_asmcgocall
368+
funcID_sigpanic
369+
funcID_runfinq
370+
funcID_bgsweep
371+
funcID_forcegchelper
372+
funcID_timerproc
373+
funcID_gcBgMarkWorker
374+
funcID_systemstack_switch
375+
funcID_systemstack
376+
funcID_cgocallback_gofunc
377+
funcID_gogo
378+
funcID_externalthreadhandler
379+
)
380+
352381
// moduledata records information about the layout of the executable
353382
// image. It is written by the linker. Any changes here must be
354383
// matched changes to the code in cmd/internal/ld/symtab.go:symtab.
@@ -648,7 +677,6 @@ func findfunc(pc uintptr) funcInfo {
648677
idx = uint32(len(datap.ftab) - 1)
649678
}
650679
if pc < datap.ftab[idx].entry {
651-
652680
// With multiple text sections, the idx might reference a function address that
653681
// is higher than the pc being searched, so search backward until the matching address is found.
654682

@@ -659,7 +687,6 @@ func findfunc(pc uintptr) funcInfo {
659687
throw("findfunc: bad findfunctab entry idx")
660688
}
661689
} else {
662-
663690
// linear search to find func with pc >= entry.
664691
for datap.ftab[idx+1].entry <= pc {
665692
idx++

0 commit comments

Comments
 (0)