golang/go

plugin: report the version of Go used to build a plugin when a mismatch occurs

mfreeman451 opened this issue · 3 comments

What version of Go are you using (go version)?

$ go version
go version go1.21.1 linux/amd64

Does this issue reproduce with the latest release?

Y

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GO111MODULE=''
GOARCH='amd64'
GOBIN=''
GOCACHE='/home/mfreeman/.cache/go-build'
GOENV='/home/mfreeman/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOOS='linux'
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/usr/local/go'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/usr/local/go/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.21.1'
GCCGO='gccgo'
GOAMD64='v1'
AR='ar'
CC='gcc'
CXX='g++'
CGO_ENABLED='1'
GOWORK=''
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build4277136579=/tmp/go-build -gno-record-gcc-switches'

What did you do?

go build -buildmode=plugin -o ./handler.so ./main.go

Then when I tried to use it with another program:

2023/09/29 02:11:29 main.go:26: plugin error: plugin.Open("/plugin/handler"): plugin was built with a different version of package google.golang.org/protobuf/internal/pragma

What did you expect to see?

It should tell me what the different version is so I can match it.

What did you see instead?

Nothing other than a not very useful message telling me that I have the wrong version, but not what the correct version should be.

You can run go version -m handler.so and go version -m <main_executable> to find out the versions and how they differ. Would that be helpful?

You can run go version -m handler.so and go version -m <main_executable> to find out the versions and how they differ. Would that be helpful?

I'm afraid that there are some cases where go version -m cannot help.

├── go.mod
├── go.sum
├── main.go
├── plugin
│   ├── go.mod
│   ├── go.sum
│   ├── myplugin.so
│   └── vendor
└── vendor
    ├── golang.org
    └── modules.txt

plugin/myplugin.go:

package main

import (
	"fmt"

	_ "golang.org/x/xerrors"
)

var ExportedVariable int = 42

func ExportedFunction() {
	fmt.Println("Hello from the plugin!")
}

main.go:

package main

import (
	"fmt"
	"plugin"

	_ "golang.org/x/xerrors"
)

func main() {
	p, err := plugin.Open("plugin/myplugin.so")
	if err != nil {
		fmt.Println("Error opening plugin:", err)
		return
	}

	exportedVar, err := p.Lookup("ExportedVariable")
	if err != nil {
		fmt.Println("Error looking up variable:", err)
		return
	}

	varValue, ok := exportedVar.(*int)
	if !ok {
		fmt.Println("Error getting variable value")
		return
	}

	fmt.Println("Exported variable:", *varValue)

	exportedFunc, err := p.Lookup("ExportedFunction")
	if err != nil {
		fmt.Println("Error looking up function:", err)
		return
	}

	exportedFunc.(func())()
}

Build the plugin:

$ cd plugin
$ go build -buildmode=plugin -mod=vendor -o myplugin.so myplugin.go

Build the main program:

$ cd ..
$ go build -mod=vendor -o main main.go
$ ./main
Error opening plugin: plugin.Open("plugin/myplugin"): plugin was built with a different version of package golang.org/x/xerrors/internal
$ go version -m plugin/myplugin.so
plugin/myplugin.so: devel go1.22-5873bd1d7e Mon Oct 16 03:29:27 2023 +0000
        path    command-line-arguments
        dep     golang.org/x/xerrors    v0.0.0-20231012003039-104605ab7028      h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
        build   -buildmode=plugin
        build   -compiler=gc
        build   CGO_ENABLED=1
        build   CGO_CFLAGS=
        build   CGO_CPPFLAGS=
        build   CGO_CXXFLAGS=
        build   CGO_LDFLAGS=
        build   GOARCH=arm64
        build   GOOS=darwin
        
$ go version -m main
main: devel go1.22-5873bd1d7e Mon Oct 16 03:29:27 2023 +0000
        path    command-line-arguments
        dep     golang.org/x/xerrors    v0.0.0-20231012003039-104605ab7028      h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
        build   -buildmode=exe
        build   -compiler=gc
        build   CGO_ENABLED=1
        build   CGO_CFLAGS=
        build   CGO_CPPFLAGS=
        build   CGO_CXXFLAGS=
        build   CGO_LDFLAGS=
        build   GOARCH=arm64
        build   GOOS=darwin

It should tell me what the different version is so I can match it.

The root cause might be something else: the full file path, the build flags, ... not the package version. Moreover, I'm not sure if we can tell what the different versions are. I tried to make a change here:

diff --git a/src/runtime/plugin.go b/src/runtime/plugin.go
index 40dfefde17..33022c60f2 100644
--- a/src/runtime/plugin.go
+++ b/src/runtime/plugin.go
@@ -51,7 +51,7 @@ func plugin_lastmoduleinit() (path string, syms map[string]any, initTasks []*ini
        for _, pkghash := range md.pkghashes {
                if pkghash.linktimehash != *pkghash.runtimehash {
                        md.bad = true
-                       return "", nil, nil, "plugin was built with a different version of package " + pkghash.modulename
+                       return "", nil, nil, "plugin was built with a different version of package " + pkghash.modulename + ": got " + *pkghash.runtimehash + ", want " + pkghash.linktimehash
                }
        }

but what I got is something like this:

Error opening plugin: plugin.Open("plugin/myplugin"): plugin was built with a different version of package golang.org/x/xerrors/internal: got %uV�┌, ┬▒┼├ NWIꘓ├