From: Todd Neal Date: Tue, 25 Apr 2017 23:32:48 +0000 (-0400) Subject: plugin: resolve plugin import path issue X-Git-Tag: go1.9beta1~469 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=7a92395ddd8354e49d2a928c99027a1a321ea716;p=gostls13.git plugin: resolve plugin import path issue Resolve import paths to get plugin symbol prefixes. Fixes #19534 Change-Id: Ic25d83e72465ba8f6be0337218a1627b5dc702dc Reviewed-on: https://go-review.googlesource.com/40994 Run-TryBot: Todd Neal TryBot-Result: Gobot Gobot Reviewed-by: David Crawshaw --- diff --git a/misc/cgo/testplugin/src/issue19534/main.go b/misc/cgo/testplugin/src/issue19534/main.go new file mode 100644 index 0000000000..de263b6f0f --- /dev/null +++ b/misc/cgo/testplugin/src/issue19534/main.go @@ -0,0 +1,23 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "plugin" + +func main() { + p, err := plugin.Open("plugin.so") + if err != nil { + panic(err) + } + + sym, err := p.Lookup("Foo") + if err != nil { + panic(err) + } + f := sym.(func() int) + if f() != 42 { + panic("expected f() == 42") + } +} diff --git a/misc/cgo/testplugin/src/issue19534/plugin.go b/misc/cgo/testplugin/src/issue19534/plugin.go new file mode 100644 index 0000000000..582d33305c --- /dev/null +++ b/misc/cgo/testplugin/src/issue19534/plugin.go @@ -0,0 +1,9 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func Foo() int { + return 42 +} diff --git a/misc/cgo/testplugin/test.bash b/misc/cgo/testplugin/test.bash index ab7430acc3..69df5bd2bf 100755 --- a/misc/cgo/testplugin/test.bash +++ b/misc/cgo/testplugin/test.bash @@ -16,7 +16,7 @@ goarch=$(go env GOARCH) function cleanup() { rm -f plugin*.so unnamed*.so iface*.so - rm -rf host pkg sub iface issue18676 + rm -rf host pkg sub iface issue18676 issue19534 } trap cleanup EXIT @@ -44,3 +44,9 @@ LD_LIBRARY_PATH=$(pwd) ./iface GOPATH=$(pwd) go build -buildmode=plugin -o plugin.so src/issue18676/plugin.go GOPATH=$(pwd) go build -o issue18676 src/issue18676/main.go timeout 10s ./issue18676 + +# Test for issue 19534 - that we can load a plugin built in a path with non-alpha +# characters +GOPATH=$(pwd) go build -buildmode=plugin -ldflags='-pluginpath=issue.19534' -o plugin.so src/issue19534/plugin.go +GOPATH=$(pwd) go build -o issue19534 src/issue19534/main.go +./issue19534 diff --git a/src/plugin/plugin_dlopen.go b/src/plugin/plugin_dlopen.go index 72e219e337..3237598f06 100644 --- a/src/plugin/plugin_dlopen.go +++ b/src/plugin/plugin_dlopen.go @@ -39,6 +39,47 @@ import ( "unsafe" ) +// avoid a dependency on strings +func lastIndexByte(s string, c byte) int { + for i := len(s) - 1; i >= 0; i-- { + if s[i] == c { + return i + } + } + return -1 +} + +// pathToPrefix converts raw string to the prefix that will be used in the symbol +// table. If modifying, modify the version in internal/obj/sym.go as well. +func pathToPrefix(s string) string { + slash := lastIndexByte(s, '/') + // check for chars that need escaping + n := 0 + for r := 0; r < len(s); r++ { + if c := s[r]; c <= ' ' || (c == '.' && r > slash) || c == '%' || c == '"' || c >= 0x7F { + n++ + } + } + + // quick exit + if n == 0 { + return s + } + + // escape + const hex = "0123456789abcdef" + p := make([]byte, 0, len(s)+2*n) + for r := 0; r < len(s); r++ { + if c := s[r]; c <= ' ' || (c == '.' && r > slash) || c == '%' || c == '"' || c >= 0x7F { + p = append(p, '%', hex[c>>4], hex[c&0xF]) + } else { + p = append(p, c) + } + } + + return string(p) +} + func open(name string) (*Plugin, error) { cPath := (*C.char)(C.malloc(C.PATH_MAX + 1)) defer C.free(unsafe.Pointer(cPath)) @@ -103,7 +144,7 @@ func open(name string) (*Plugin, error) { delete(syms, symName) symName = symName[1:] } - cname := C.CString(pluginpath + "." + symName) + cname := C.CString(pathToPrefix(pluginpath) + "." + symName) p := C.pluginLookup(h, cname, &cErr) C.free(unsafe.Pointer(cname)) if p == nil {