runtime, plugin: error not throw on duplicate open

Along the way, track bad modules. Make sure they don't end up on
the active modules list, and aren't accidentally reprocessed as
new plugins.

Fixes #19004

Change-Id: I8a5e7bb11f572f7b657a97d521a7f84822a35c07
Reviewed-on: https://go-review.googlesource.com/61171
Run-TryBot: David Crawshaw <crawshaw@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
David Crawshaw 2017-09-02 12:05:35 -04:00
parent 4e2ef7f7f9
commit d8ae2156fe
6 changed files with 58 additions and 20 deletions

View file

@ -87,7 +87,7 @@ func open(name string) (*Plugin, error) {
if C.realpath(
(*C.char)(unsafe.Pointer(&cRelName[0])),
(*C.char)(unsafe.Pointer(&cPath[0]))) == nil {
return nil, errors.New("plugin.Open(" + name + "): realpath failed")
return nil, errors.New(`plugin.Open("` + name + `"): realpath failed`)
}
filepath := C.GoString((*C.char)(unsafe.Pointer(&cPath[0])))
@ -95,6 +95,9 @@ func open(name string) (*Plugin, error) {
pluginsMu.Lock()
if p := plugins[filepath]; p != nil {
pluginsMu.Unlock()
if p.err != "" {
return nil, errors.New(`plugin.Open("` + name + `"): ` + p.err + ` (previous failure)`)
}
<-p.loaded
return p, nil
}
@ -102,22 +105,25 @@ func open(name string) (*Plugin, error) {
h := C.pluginOpen((*C.char)(unsafe.Pointer(&cPath[0])), &cErr)
if h == 0 {
pluginsMu.Unlock()
return nil, errors.New("plugin.Open: " + C.GoString(cErr))
return nil, errors.New(`plugin.Open("` + name + `"): ` + C.GoString(cErr))
}
// TODO(crawshaw): look for plugin note, confirm it is a Go plugin
// and it was built with the correct toolchain.
if len(name) > 3 && name[len(name)-3:] == ".so" {
name = name[:len(name)-3]
}
pluginpath, syms, mismatchpkg := lastmoduleinit()
if mismatchpkg != "" {
pluginsMu.Unlock()
return nil, errors.New("plugin.Open: plugin was built with a different version of package " + mismatchpkg)
}
if plugins == nil {
plugins = make(map[string]*Plugin)
}
pluginpath, syms, errstr := lastmoduleinit()
if errstr != "" {
plugins[filepath] = &Plugin{
pluginpath: pluginpath,
err: errstr,
}
pluginsMu.Unlock()
return nil, errors.New(`plugin.Open("` + name + `"): ` + errstr)
}
// This function can be called from the init function of a plugin.
// Drop a placeholder in the map so subsequent opens can wait on it.
p := &Plugin{
@ -153,7 +159,7 @@ func open(name string) (*Plugin, error) {
p := C.pluginLookup(h, (*C.char)(unsafe.Pointer(&cname[0])), &cErr)
if p == nil {
return nil, errors.New("plugin.Open: could not find symbol " + symName + ": " + C.GoString(cErr))
return nil, errors.New(`plugin.Open("` + name + `"): could not find symbol ` + symName + `: ` + C.GoString(cErr))
}
valp := (*[2]unsafe.Pointer)(unsafe.Pointer(&sym))
if isFunc {
@ -184,4 +190,4 @@ var (
)
// lastmoduleinit is defined in package runtime
func lastmoduleinit() (pluginpath string, syms map[string]interface{}, mismatchpkg string)
func lastmoduleinit() (pluginpath string, syms map[string]interface{}, errstr string)