go: plugin: convert iface to type failed with "types from different scopes"
What version of Go are you using (go version)?
$ go version go version devel go1.18-14e812bfc5 Fri Sep 17 00:31:49 2021 +0000 linux/amd64
Does this issue reproduce with the latest release?
yes
What operating system and processor architecture are you using (go env)?
go env Output
$ go env GO111MODULE="" GOARCH="amd64" GOBIN="" GOCACHE="/root/.cache/go-build" GOENV="/root/.config/go/env" GOEXE="" GOEXPERIMENT="" GOFLAGS="" GOHOSTARCH="amd64" GOHOSTOS="linux" GOINSECURE="" GOMODCACHE="/root/go/pkg/mod" GONOPROXY="" GONOSUMDB="" GOOS="linux" GOPATH="/root/go" GOPRIVATE="" GOPROXY="https://proxy.golang.org,direct" GOROOT="/mnt/d/00.Tool/00.golang/go-master" GOSUMDB="sum.golang.org" GOTMPDIR="" GOTOOLDIR="/mnt/d/00.Tool/00.golang/go-master/pkg/tool/linux_amd64" GOVCS="" GOVERSION="devel go1.18-14e812bfc5 Fri Sep 17 00:31:49 2021 +0000" GCCGO="gccgo" GOAMD64="v1" AR="ar" CC="gcc" CXX="g++" CGO_ENABLED="1" GOMOD="/mnt/d/01.Project/03.corego_performance/demo/go.mod" CGO_CFLAGS="-g -O2" CGO_CPPFLAGS="" CGO_CXXFLAGS="-g -O2" CGO_FFLAGS="-g -O2" CGO_LDFLAGS="-g -O2" PKG_CONFIG="pkg-config" GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build691445209=. -gno-record-gcc-switches"
What did you do?
pluginassert/go.mod:
module pluginassert
go 1.18
pluginassert/inter/iface.go:
package inter
type A interface {
Method1()
}
type B struct{}
func (b *B) Method1() {
println("Method1 in B")
}
pluginassert/main.go:
package main
import (
"log"
"plugin"
"pluginassert/inter"
)
func main() {
var a interface{}
a = &inter.B{}
switch x := a.(type) {
case inter.A:
x.Method1()
default:
log.Fatalln("assert x to A failed")
}
p, err := plugin.Open("./pluginassert.so")
if err != nil {
log.Fatalln(err)
}
sym, err := p.Lookup("TestFunc")
if err != nil {
log.Fatalln(err)
}
testFunc := sym.(func(inter.A))
switch x := a.(type) {
case inter.A:
testFunc(x)
default:
log.Fatalln("assert x to A failed")
}
}
pluginassert/plugin.go:
package main
import (
"pluginassert/inter"
)
func TestFunc(a inter.A) {
b := a.(*inter.B)
b.Method1()
}
~/pluginassert $ go build -buildmode=plugin ~/pluginassert $ go build ~/pluginassert $ ./pluginassert
What did you expect to see?
Method1 in B Method1 in B
What did you see instead?
Method1 in B
panic: interface conversion: inter.A is *inter.B, not *inter.B (types from different scopes)
goroutine 1 [running]:
pluginassert.TestFunc({0x7fe0643fdff8, 0x6406b8})
pluginassert/plugin.go:8 +0x67
main.main()
pluginassert/main.go:31 +0x204
There is no symbol go.itab.*pluginassert/inter.B,pluginassert/inter.A in main binary. So it will invoke persistentalloc in function getitab in first switch-case to allocate an itab.
But unfortunately, after plugin is loaded, the itab go.itab.*pluginassert/inter.B,pluginassert/inter.A was added to itabTable. When the TestFunc was invoked in second switch-case, x is a iface with itab which was allocated in first switch-case.
In plugin, the implement of a.(*inter.B) is to compare the address of a.tab and go.itab.*pluginassert/inter.B,pluginassert/inter.A. Certainly they are different. So we get this panic.
About this issue
- Original URL
- State: open
- Created 3 years ago
- Comments: 21 (14 by maintainers)
If we had our own dynamic linker…