Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

plugin: using same type in map across two plugins causes stackoverflow #19258

Closed
vimalk78 opened this issue Feb 23, 2017 · 3 comments
Closed
Milestone

Comments

@vimalk78
Copy link

vimalk78 commented Feb 23, 2017

Please answer these questions before submitting your issue. Thanks!

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

$ go version
go version go1.8 linux/amd64

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

$ go env
GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/vimal/gowork"
GORACE=""
GOROOT="/usr/local/go"
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build121316025=/tmp/go-build -gno-record-gcc-switches"
CXX="g++"
CGO_ENABLED="1"
PKG_CONFIG="pkg-config"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"

What did you do?

using the plugins feature. created the following two plugins using the command go build -buildmode=plugin

plugin1

package main

import "C"
import "log"

func init() {
    log.Printf("testplugin.main.init invoked\n")
}

type innerType struct {
    f1 int
    f2 string
}

type MyStruct struct {
    Name string
    Id   int
    mm   map[string]innerType
}

func InitPlugin() {
    m := MyStruct{Name: "x", Id: 0}
    log.Printf("testplugin.InitPlugin %v", m)
}

plugin2

package main

import "C"
import "log"

func init() {
    log.Printf("testplugin1.main.init invoked\n")
}

type innerType struct {
    f1 int
    f2 string
}

type MyStruct struct {
    Name string
    Id   int
    mm   map[string]innerType
}

func InitPlugin() {
    m := MyStruct{Name: "x", Id: 0}
    log.Printf("testplugin1.InitPlugin %v", m)
}

Both plugins have the same code, except the minor difference in print statements.

a main program loads the plugins using the api plugin.Open(pluginpath)

What did you expect to see?

Both plugins loaded succesfully.

What did you see instead?

a stackoverflow error. I have limited the stack using debug.SetMaxStack(100) so that i can see the beginning of the stack.

runtime: goroutine stack exceeds 100-byte limit
fatal error: stack overflow

runtime stack:
runtime.throw(0x537589, 0xe)
        /usr/local/go/src/runtime/panic.go:596 +0x95
runtime.newstack(0x0)
        /usr/local/go/src/runtime/stack.go:1089 +0x3f2
runtime.morestack()
        /usr/local/go/src/runtime/asm_amd64.s:398 +0x86

goroutine 1 [running]:
runtime.(*_type).string(0x7f29a2dca140, 0x0, 0x0)
        /usr/local/go/src/runtime/type.go:45 +0xad fp=0xc42004c320 sp=0xc42004c318
runtime.typesEqual(0x7f29a2dca140, 0x7f29a31de140, 0x0)
        /usr/local/go/src/runtime/type.go:543 +0x73 fp=0xc42004c448 sp=0xc42004c320
runtime.typesEqual(0x7f29a2dd4a60, 0x7f29a31e8a60, 0x7f29a31d2850)
        /usr/local/go/src/runtime/type.go:647 +0xc0a fp=0xc42004c570 sp=0xc42004c448
runtime.typesEqual(0x7f29a2dc0a60, 0x7f29a31d4a60, 0x0)
        /usr/local/go/src/runtime/type.go:627 +0x9c5 fp=0xc42004c698 sp=0xc42004c570
runtime.typesEqual(0x7f29a2dd4a60, 0x7f29a31e8a60, 0x7f29a31d2850)
        /usr/local/go/src/runtime/type.go:647 +0xc0a fp=0xc42004c7c0 sp=0xc42004c698
runtime.typesEqual(0x7f29a2dc0a60, 0x7f29a31d4a60, 0x0)
        /usr/local/go/src/runtime/type.go:627 +0x9c5 fp=0xc42004c8e8 sp=0xc42004c7c0
runtime.typesEqual(0x7f29a2dd4a60, 0x7f29a31e8a60, 0x7f29a31d2850)
        /usr/local/go/src/runtime/type.go:647 +0xc0a fp=0xc42004ca10 sp=0xc42004c8e8
runtime.typesEqual(0x7f29a2dc0a60, 0x7f29a31d4a60, 0x0)
        /usr/local/go/src/runtime/type.go:627 +0x9c5 fp=0xc42004cb38 sp=0xc42004ca10
runtime.typesEqual(0x7f29a2dd4a60, 0x7f29a31e8a60, 0x7f29a31d2850)
        /usr/local/go/src/runtime/type.go:647 +0xc0a fp=0xc42004cc60 sp=0xc42004cb38
runtime.typesEqual(0x7f29a2dc0a60, 0x7f29a31d4a60, 0x0)
        /usr/local/go/src/runtime/type.go:627 +0x9c5 fp=0xc42004cd88 sp=0xc42004cc60
runtime.typesEqual(0x7f29a2dd4a60, 0x7f29a31e8a60, 0x7f29a31d2850)
        /usr/local/go/src/runtime/type.go:647 +0xc0a fp=0xc42004ceb0 sp=0xc42004cd88
runtime.typesEqual(0x7f29a2dc0a60, 0x7f29a31d4a60, 0x0)
        /usr/local/go/src/runtime/type.go:627 +0x9c5 fp=0xc42004cfd8 sp=0xc42004ceb0
runtime.typesEqual(0x7f29a2dd4a60, 0x7f29a31e8a60, 0x7f29a31d2850)
        /usr/local/go/src/runtime/type.go:647 +0xc0a fp=0xc42004d100 sp=0xc42004cfd8
runtime.typesEqual(0x7f29a2dc0a60, 0x7f29a31d4a60, 0x0)
        /usr/local/go/src/runtime/type.go:627 +0x9c5 fp=0xc42004d228 sp=0xc42004d100
runtime.typesEqual(0x7f29a2dd4a60, 0x7f29a31e8a60, 0x7f29a31d2850)
        /usr/local/go/src/runtime/type.go:647 +0xc0a fp=0xc42004d350 sp=0xc42004d228
runtime.typesEqual(0x7f29a2dc0a60, 0x7f29a31d4a60, 0x0)
        /usr/local/go/src/runtime/type.go:627 +0x9c5 fp=0xc42004d478 sp=0xc42004d350
runtime.typesEqual(0x7f29a2dd4a60, 0x7f29a31e8a60, 0x7f29a31d2850)
        /usr/local/go/src/runtime/type.go:647 +0xc0a fp=0xc42004d5a0 sp=0xc42004d478
runtime.typesEqual(0x7f29a2dc0a60, 0x7f29a31d4a60, 0x0)
        /usr/local/go/src/runtime/type.go:627 +0x9c5 fp=0xc42004d6c8 sp=0xc42004d5a0
runtime.typesEqual(0x7f29a2dd4a60, 0x7f29a31e8a60, 0x7f29a31d2850)
        /usr/local/go/src/runtime/type.go:647 +0xc0a fp=0xc42004d7f0 sp=0xc42004d6c8
runtime.typesEqual(0x7f29a2dc0a60, 0x7f29a31d4a60, 0xc4800c6242)
        /usr/local/go/src/runtime/type.go:627 +0x9c5 fp=0xc42004d918 sp=0xc42004d7f0
runtime.typelinksinit()
        /usr/local/go/src/runtime/type.go:510 +0x432 fp=0xc42004db20 sp=0xc42004d918
plugin.lastmoduleinit(0xc39400, 0xc42000fb48, 0xc3ab60, 0x43, 0x7bbf60)
        /usr/local/go/src/runtime/plugin.go:52 +0x2f9 fp=0xc42004dc50 sp=0xc42004db20
plugin.open(0x7fffaaddfd48, 0x1d, 0x0, 0x0, 0x0)
        /usr/local/go/src/plugin/plugin_dlopen.go:72 +0x25d fp=0xc42004de90 sp=0xc42004dc50
plugin.Open(0x7fffaaddfd48, 0x1d, 0xc42004df28, 0x1, 0x1)
        /usr/local/go/src/plugin/plugin.go:30 +0x35 fp=0xc42004dec8 sp=0xc42004de90
main.loadPlugin(0x7fffaaddfd48, 0x1d, 0xc42000c200)
        /home/vimal/gowork/src/github.com/v70420/pluginfw/main.go:31 +0xd7 fp=0xc42004df48 sp=0xc42004dec8
main.main()
        /home/vimal/gowork/src/github.com/v70420/pluginfw/main.go:19 +0x75 fp=0xc42004df88 sp=0xc42004df48
runtime.main()
        /usr/local/go/src/runtime/proc.go:185 +0x20a fp=0xc42004dfe0 sp=0xc42004df88
runtime.goexit()
        /usr/local/go/src/runtime/asm_amd64.s:2197 +0x1 fp=0xc42004dfe8 sp=0xc42004dfe0

without limiting the stack size, the error is same, except

runtime: goroutine stack exceeds 1000000000-byte limit
fatal error: stack overflow

i narrowed down the issue to this

type MyStruct struct {
    Name string
    Id   int
    mm   map[string]innerType << using the type in map causes the error
}

If the type is not used in the map, the error is gone, and both plugins can be loaded successfully.

type MyStruct struct {
    Name string
    Id   int
    // mm   map[string]innerType << commenting this line does not cause the error
}

also, renaming the type innerType to some other name, say, innerType_xyz in one of the plugins also avoids the stackoverflow.

@vimalk78 vimalk78 changed the title plugin: using same type in map causes stackoverflow plugin: using same type in map across two plugins causes stackoverflow Feb 23, 2017
@ianlancetaylor ianlancetaylor added this to the Go1.9 milestone Feb 23, 2017
@tzneal
Copy link
Member

tzneal commented Apr 11, 2017

It's walking an infinite list of types caused by the overflow buckets in the map. Each bucket has a has a values field of type innerType, and a pointer to a bucket. Since everything else is identical, it recurses through the bucket pointer back to a bucket, and keeps going.

Any identical recursive type definition in two plugins causes it.

@gopherbot
Copy link

CL https://golang.org/cl/40292 mentions this issue.

@vimalk78
Copy link
Author

not sure, but does it make sense to check reverse way also?

	tp := _typePair{t, v}
	if _, ok := seen[tp]; ok {
		return true
	}
        reversetp := _typePair{v, t}
	if _, ok := seen[reversetp]; ok {
		return true
	}

        ...
        ...
        seen[tp] = struct{}{}
        seen[reversetp] = struct{}{}

lparth pushed a commit to lparth/go that referenced this issue Apr 13, 2017
Prevent a crash if the same type in two plugins had a recursive
definition, either by referring to a pointer to itself or a map existing
with the type as a value type (which creates a recursive definition
through the overflow bucket type).

Fixes golang#19258

Change-Id: Iac1cbda4c5b6e8edd5e6859a4d5da3bad539a9c6
Reviewed-on: https://go-review.googlesource.com/40292
Run-TryBot: Todd Neal <todd@tneal.org>
Reviewed-by: David Crawshaw <crawshaw@golang.org>
@golang golang locked and limited conversation to collaborators Apr 12, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants