Commit 96414ca3 authored by David Crawshaw's avatar David Crawshaw

cmd/link: do not export plugin C symbols

Explicitly filter any C-only cgo functions out of pclntable,
which allows them to be duplicated with the host binary.

Updates #18190.

Change-Id: I50d8706777a6133b3e95f696bc0bc586b84faa9e
Reviewed-on: https://go-review.googlesource.com/34199Reviewed-by: default avatarIan Lance Taylor <iant@golang.org>
parent 901005e8
......@@ -4,12 +4,21 @@
package main
// // No C code required.
//#include <errno.h>
//#include <string.h>
import "C"
import "common"
// #include
// void cfunc() {} // uses cgo_topofstack
import (
"common"
"strings"
)
func init() {
_ = strings.NewReplacer() // trigger stack unwind, Issue #18190.
C.strerror(C.EIO) // uses cgo_topofstack
common.X = 2
}
......
......@@ -695,7 +695,16 @@ func machoShouldExport(ctxt *Link, s *Symbol) bool {
if Buildmode == BuildmodePlugin && strings.HasPrefix(s.Extname, *flagPluginPath) {
return true
}
return s.Type != obj.STEXT
if strings.HasPrefix(s.Name, "type.") && !strings.HasPrefix(s.Name, "type..") {
// reduce runtime typemap pressure, but do not
// export alg functions (type..*), as these
// appear in pclntable.
return true
}
if strings.HasPrefix(s.Name, "go.link.pkghash") {
return true
}
return s.Type >= obj.SELFSECT // only writable sections
}
func machosymtab(ctxt *Link) {
......@@ -710,7 +719,13 @@ func machosymtab(ctxt *Link) {
// In normal buildmodes, only add _ to C symbols, as
// Go symbols have dot in the name.
if !strings.Contains(s.Extname, ".") || export {
//
// Do not export C symbols in plugins, as runtime C
// symbols like crosscall2 are in pclntab and end up
// pointing at the host binary, breaking unwinding.
// See Issue #18190.
cexport := !strings.Contains(s.Extname, ".") && (Buildmode != BuildmodePlugin || onlycsymbol(s))
if cexport || export {
Adduint8(ctxt, symstr, '_')
}
......
......@@ -154,10 +154,26 @@ func renumberfiles(ctxt *Link, files []*Symbol, d *Pcdata) {
*d = out
}
// onlycsymbol reports whether this is a cgo symbol provided by the
// runtime and only used from C code.
func onlycsymbol(s *Symbol) bool {
switch s.Name {
case "_cgo_topofstack", "_cgo_panic", "crosscall2":
return true
}
return false
}
func container(s *Symbol) int {
if s == nil {
return 0
}
if Buildmode == BuildmodePlugin && onlycsymbol(s) {
return 1
}
// We want to generate func table entries only for the "lowest level" symbols,
// not containers of subsymbols.
if s != nil && s.Type&obj.SCONTAINER != 0 {
if s.Type&obj.SCONTAINER != 0 {
return 1
}
return 0
......
......@@ -51,6 +51,9 @@ func plugin_lastmoduleinit() (path string, syms map[string]interface{}, mismatch
modulesinit()
typelinksinit()
pluginftabverify(md)
moduledataverify1(md)
lock(&ifaceLock)
for _, i := range md.itablinks {
additab(i, true, false)
......@@ -82,6 +85,35 @@ func plugin_lastmoduleinit() (path string, syms map[string]interface{}, mismatch
return md.pluginpath, syms, ""
}
func pluginftabverify(md *moduledata) {
badtable := false
for i := 0; i < len(md.ftab); i++ {
entry := md.ftab[i].entry
if md.minpc <= entry && entry <= md.maxpc {
continue
}
f := (*_func)(unsafe.Pointer(&md.pclntable[md.ftab[i].funcoff]))
name := funcname(f)
// A common bug is f.entry has a relocation to a duplicate
// function symbol, meaning if we search for its PC we get
// a valid entry with a name that is useful for debugging.
name2 := "none"
entry2 := uintptr(0)
f2 := findfunc(entry)
if f2 != nil {
name2 = funcname(f2)
entry2 = f2.entry
}
badtable = true
println("ftab entry outside pc range: ", hex(entry), "/", hex(entry2), ": ", name, "/", name2)
}
if badtable {
throw("runtime: plugin has bad symbol table")
}
}
// inRange reports whether v0 or v1 are in the range [r0, r1].
func inRange(r0, r1, v0, v1 uintptr) bool {
return (v0 >= r0 && v0 <= r1) || (v1 >= r0 && v1 <= r1)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment