diff options
Diffstat (limited to 'libgo/go/plugin/plugin_dlopen.go')
-rw-r--r-- | libgo/go/plugin/plugin_dlopen.go | 52 |
1 files changed, 48 insertions, 4 deletions
diff --git a/libgo/go/plugin/plugin_dlopen.go b/libgo/go/plugin/plugin_dlopen.go index c5b0a4721c5..3237598f06b 100644 --- a/libgo/go/plugin/plugin_dlopen.go +++ b/libgo/go/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)) @@ -82,7 +123,6 @@ func open(name string) (*Plugin, error) { p := &Plugin{ pluginpath: pluginpath, loaded: make(chan struct{}), - syms: syms, } plugins[filepath] = p pluginsMu.Unlock() @@ -97,14 +137,14 @@ func open(name string) (*Plugin, error) { } // Fill out the value of each plugin symbol. + updatedSyms := map[string]interface{}{} for symName, sym := range syms { isFunc := symName[0] == '.' if isFunc { 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 { @@ -116,8 +156,12 @@ func open(name string) (*Plugin, error) { } else { (*valp)[1] = p } - syms[symName] = sym + // we can't add to syms during iteration as we'll end up processing + // some symbols twice with the inability to tell if the symbol is a function + updatedSyms[symName] = sym } + p.syms = updatedSyms + close(p.loaded) return p, nil } |