aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/cgo/internal/testplugin/testdata
diff options
context:
space:
mode:
authorAustin Clements <austin@google.com>2023-05-04 12:13:27 -0400
committerAustin Clements <austin@google.com>2023-05-12 11:59:56 +0000
commitbf6c55a8b313752667b51194485fa206110d71f9 (patch)
tree8dd81bdb6e48bc77d7923ba985a91b6b7daa341e /src/cmd/cgo/internal/testplugin/testdata
parenta25688d406f2a4296d39b22a2b10aea7178eddc6 (diff)
downloadgo-bf6c55a8b313752667b51194485fa206110d71f9.tar.xz
misc/cgo: move easy tests to cmd/cgo/internal
This moves most misc/cgo tests to cmd/cgo/internal. This is mostly a trivial rename and updating dist/test.go for the new paths, plus excluding these packages from regular dist test registration. A few tests were sensitive to what path they ran in, so we update those. This will let these tests access facilities in internal/testenv. For #37486. Change-Id: I3ed417c7c22d9b667f2767c0cb1f59118fcd4af6 Reviewed-on: https://go-review.googlesource.com/c/go/+/492720 Run-TryBot: Austin Clements <austin@google.com> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org> Reviewed-by: Bryan Mills <bcmills@google.com> TryBot-Result: Gopher Robot <gobot@golang.org>
Diffstat (limited to 'src/cmd/cgo/internal/testplugin/testdata')
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/checkdwarf/main.go106
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/common/common.go11
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/forkexec/main.go30
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/host/host.go176
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/iface/main.go47
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/iface_a/a.go17
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/iface_b/b.go17
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/iface_i/i.go17
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/issue18584/main.go23
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/issue18584/plugin.go19
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/issue18676/dynamodbstreamsevt/definition.go13
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/issue18676/main.go32
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/issue18676/plugin.go11
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/issue19418/main.go29
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/issue19418/plugin.go7
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/issue19529/plugin.go15
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/issue19534/main.go23
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/issue19534/plugin.go9
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/issue22175/main.go28
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/issue22175/plugin1.go21
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/issue22175/plugin2.go9
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/issue22295.pkg/main.go28
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/issue22295.pkg/plugin.go16
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/issue24351/main.go21
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/issue24351/plugin.go14
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/issue25756/main.go52
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/issue25756/plugin/c-life.c56
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/issue25756/plugin/life.go40
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/issue25756/plugin/life.h7
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/issue44956/base/base.go7
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/issue44956/main.go47
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/issue44956/plugin1.go9
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/issue44956/plugin2.go11
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/issue52937/main.go9
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/issue53989/main.go32
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/issue53989/p/p.go52
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/issue53989/plugin.go13
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/method/main.go26
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/method/plugin.go13
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/method2/main.go32
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/method2/p/p.go9
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/method2/plugin.go11
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/method3/main.go32
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/method3/p/p.go17
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/method3/plugin.go11
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/plugin1/plugin1.go57
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/plugin2/plugin2.go44
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/sub/plugin1/plugin1.go23
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/unnamed1/main.go25
-rw-r--r--src/cmd/cgo/internal/testplugin/testdata/unnamed2/main.go23
50 files changed, 1397 insertions, 0 deletions
diff --git a/src/cmd/cgo/internal/testplugin/testdata/checkdwarf/main.go b/src/cmd/cgo/internal/testplugin/testdata/checkdwarf/main.go
new file mode 100644
index 0000000000..7886c834e7
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/checkdwarf/main.go
@@ -0,0 +1,106 @@
+// Copyright 2018 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.
+
+// Usage:
+//
+// checkdwarf <exe> <suffix>
+//
+// Opens <exe>, which must be an executable or a library and checks that
+// there is an entry in .debug_info whose name ends in <suffix>
+
+package main
+
+import (
+ "debug/dwarf"
+ "debug/elf"
+ "debug/macho"
+ "debug/pe"
+ "fmt"
+ "os"
+ "strings"
+)
+
+func usage() {
+ fmt.Fprintf(os.Stderr, "checkdwarf executable-or-library DIE-suffix\n")
+}
+
+type dwarfer interface {
+ DWARF() (*dwarf.Data, error)
+}
+
+func openElf(path string) dwarfer {
+ exe, err := elf.Open(path)
+ if err != nil {
+ return nil
+ }
+ return exe
+}
+
+func openMacho(path string) dwarfer {
+ exe, err := macho.Open(path)
+ if err != nil {
+ return nil
+ }
+ return exe
+}
+
+func openPE(path string) dwarfer {
+ exe, err := pe.Open(path)
+ if err != nil {
+ return nil
+ }
+ return exe
+}
+
+func main() {
+ if len(os.Args) != 3 {
+ usage()
+ }
+
+ exePath := os.Args[1]
+ dieSuffix := os.Args[2]
+
+ var exe dwarfer
+
+ for _, openfn := range []func(string) dwarfer{openMacho, openPE, openElf} {
+ exe = openfn(exePath)
+ if exe != nil {
+ break
+ }
+ }
+
+ if exe == nil {
+ fmt.Fprintf(os.Stderr, "could not open %s\n", exePath)
+ os.Exit(1)
+ }
+
+ data, err := exe.DWARF()
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "%s: error opening DWARF: %v\n", exePath, err)
+ os.Exit(1)
+ }
+
+ rdr := data.Reader()
+ for {
+ e, err := rdr.Next()
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "%s: error reading DWARF: %v\n", exePath, err)
+ os.Exit(1)
+ }
+ if e == nil {
+ break
+ }
+ name, hasname := e.Val(dwarf.AttrName).(string)
+ if !hasname {
+ continue
+ }
+ if strings.HasSuffix(name, dieSuffix) {
+ // found
+ os.Exit(0)
+ }
+ }
+
+ fmt.Fprintf(os.Stderr, "%s: no entry with a name ending in %q was found\n", exePath, dieSuffix)
+ os.Exit(1)
+}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/common/common.go b/src/cmd/cgo/internal/testplugin/testdata/common/common.go
new file mode 100644
index 0000000000..b064e6bccf
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/common/common.go
@@ -0,0 +1,11 @@
+// Copyright 2016 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 common
+
+var X int
+
+func init() {
+ X = 3
+}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/forkexec/main.go b/src/cmd/cgo/internal/testplugin/testdata/forkexec/main.go
new file mode 100644
index 0000000000..3169ff5f04
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/forkexec/main.go
@@ -0,0 +1,30 @@
+// Copyright 2021 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 (
+ "os"
+ "os/exec"
+ _ "plugin"
+ "sync"
+)
+
+func main() {
+ if os.Args[1] != "1" {
+ return
+ }
+
+ var wg sync.WaitGroup
+ for i := 0; i < 8; i++ {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ // does not matter what we exec, just exec itself
+ cmd := exec.Command("./forkexec.exe", "0")
+ cmd.Run()
+ }()
+ }
+ wg.Wait()
+}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/host/host.go b/src/cmd/cgo/internal/testplugin/testdata/host/host.go
new file mode 100644
index 0000000000..a3799328cd
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/host/host.go
@@ -0,0 +1,176 @@
+// Copyright 2016 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 (
+ "fmt"
+ "log"
+ "path/filepath"
+ "plugin"
+ "strings"
+
+ "testplugin/common"
+)
+
+func init() {
+ common.X *= 5
+}
+
+// testUnnamed tests that two plugins built with .go files passed on
+// the command line do not have overlapping symbols. That is,
+// unnamed1.so/FuncInt and unnamed2.so/FuncInt should be distinct functions.
+func testUnnamed() {
+ p, err := plugin.Open("unnamed1.so")
+ if err != nil {
+ log.Fatalf(`plugin.Open("unnamed1.so"): %v`, err)
+ }
+ fn, err := p.Lookup("FuncInt")
+ if err != nil {
+ log.Fatalf(`unnamed1.so: Lookup("FuncInt") failed: %v`, err)
+ }
+ if got, want := fn.(func() int)(), 1; got != want {
+ log.Fatalf("unnamed1.so: FuncInt()=%d, want %d", got, want)
+ }
+
+ p, err = plugin.Open("unnamed2.so")
+ if err != nil {
+ log.Fatalf(`plugin.Open("unnamed2.so"): %v`, err)
+ }
+ fn, err = p.Lookup("FuncInt")
+ if err != nil {
+ log.Fatalf(`unnamed2.so: Lookup("FuncInt") failed: %v`, err)
+ }
+ if got, want := fn.(func() int)(), 2; got != want {
+ log.Fatalf("unnamed2.so: FuncInt()=%d, want %d", got, want)
+ }
+}
+
+func main() {
+ if got, want := common.X, 3*5; got != want {
+ log.Fatalf("before plugin load common.X=%d, want %d", got, want)
+ }
+
+ p, err := plugin.Open("plugin1.so")
+ if err != nil {
+ log.Fatalf("plugin.Open failed: %v", err)
+ }
+
+ const wantX = 3 * 5 * 7
+ if got := common.X; got != wantX {
+ log.Fatalf("after plugin load common.X=%d, want %d", got, wantX)
+ }
+
+ seven, err := p.Lookup("Seven")
+ if err != nil {
+ log.Fatalf(`Lookup("Seven") failed: %v`, err)
+ }
+ if got, want := *seven.(*int), 7; got != want {
+ log.Fatalf("plugin1.Seven=%d, want %d", got, want)
+ }
+
+ readFunc, err := p.Lookup("ReadCommonX")
+ if err != nil {
+ log.Fatalf(`plugin1.Lookup("ReadCommonX") failed: %v`, err)
+ }
+ if got := readFunc.(func() int)(); got != wantX {
+ log.Fatalf("plugin1.ReadCommonX()=%d, want %d", got, wantX)
+ }
+
+ // sub/plugin1.so is a different plugin with the same name as
+ // the already loaded plugin. It also depends on common. Test
+ // that we can load the different plugin, it is actually
+ // different, and that it sees the same common package.
+ subpPath, err := filepath.Abs("sub/plugin1.so")
+ if err != nil {
+ log.Fatalf("filepath.Abs(%q) failed: %v", subpPath, err)
+ }
+ subp, err := plugin.Open(subpPath)
+ if err != nil {
+ log.Fatalf("plugin.Open(%q) failed: %v", subpPath, err)
+ }
+
+ funcVar, err := subp.Lookup("FuncVar")
+ if err != nil {
+ log.Fatalf(`sub/plugin1.Lookup("FuncVar") failed: %v`, err)
+ }
+ called := false
+ *funcVar.(*func()) = func() {
+ called = true
+ }
+
+ readFunc, err = subp.Lookup("ReadCommonX")
+ if err != nil {
+ log.Fatalf(`sub/plugin1.Lookup("ReadCommonX") failed: %v`, err)
+ }
+ if got := readFunc.(func() int)(); got != wantX {
+ log.Fatalf("sub/plugin1.ReadCommonX()=%d, want %d", got, wantX)
+ }
+ if !called {
+ log.Fatal("calling ReadCommonX did not call FuncVar")
+ }
+
+ subf, err := subp.Lookup("F")
+ if err != nil {
+ log.Fatalf(`sub/plugin1.Lookup("F") failed: %v`, err)
+ }
+ if gotf := subf.(func() int)(); gotf != 17 {
+ log.Fatalf(`sub/plugin1.F()=%d, want 17`, gotf)
+ }
+ f, err := p.Lookup("F")
+ if err != nil {
+ log.Fatalf(`plugin1.Lookup("F") failed: %v`, err)
+ }
+ if gotf := f.(func() int)(); gotf != 3 {
+ log.Fatalf(`plugin1.F()=%d, want 17`, gotf)
+ }
+
+ p2, err := plugin.Open("plugin2.so")
+ if err != nil {
+ log.Fatalf("plugin.Open failed: %v", err)
+ }
+ // Check that plugin2's init function was called, and
+ // that it modifies the same global variable as the host.
+ if got, want := common.X, 2; got != want {
+ log.Fatalf("after loading plugin2, common.X=%d, want %d", got, want)
+ }
+
+ _, err = plugin.Open("plugin2-dup.so")
+ if err == nil {
+ log.Fatal(`plugin.Open("plugin2-dup.so"): duplicate open should have failed`)
+ }
+ if s := err.Error(); !strings.Contains(s, "already loaded") {
+ log.Fatal(`plugin.Open("plugin2.so"): error does not mention "already loaded"`)
+ }
+
+ _, err = plugin.Open("plugin-mismatch.so")
+ if err == nil {
+ log.Fatal(`plugin.Open("plugin-mismatch.so"): should have failed`)
+ }
+ if s := err.Error(); !strings.Contains(s, "different version") {
+ log.Fatalf(`plugin.Open("plugin-mismatch.so"): error does not mention "different version": %v`, s)
+ }
+
+ _, err = plugin.Open("plugin2-dup.so")
+ if err == nil {
+ log.Fatal(`plugin.Open("plugin2-dup.so"): duplicate open after bad plugin should have failed`)
+ }
+ _, err = plugin.Open("plugin2.so")
+ if err != nil {
+ log.Fatalf(`plugin.Open("plugin2.so"): second open with same name failed: %v`, err)
+ }
+
+ // Test that unexported types with the same names in
+ // different plugins do not interfere with each other.
+ //
+ // See Issue #21386.
+ UnexportedNameReuse, _ := p.Lookup("UnexportedNameReuse")
+ UnexportedNameReuse.(func())()
+ UnexportedNameReuse, _ = p2.Lookup("UnexportedNameReuse")
+ UnexportedNameReuse.(func())()
+
+ testUnnamed()
+
+ fmt.Println("PASS")
+}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/iface/main.go b/src/cmd/cgo/internal/testplugin/testdata/iface/main.go
new file mode 100644
index 0000000000..c04f28880f
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/iface/main.go
@@ -0,0 +1,47 @@
+// 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 (
+ "log"
+ "plugin"
+
+ "testplugin/iface_i"
+)
+
+func main() {
+ a, err := plugin.Open("iface_a.so")
+ if err != nil {
+ log.Fatalf(`plugin.Open("iface_a.so"): %v`, err)
+ }
+ b, err := plugin.Open("iface_b.so")
+ if err != nil {
+ log.Fatalf(`plugin.Open("iface_b.so"): %v`, err)
+ }
+
+ af, err := a.Lookup("F")
+ if err != nil {
+ log.Fatalf(`a.Lookup("F") failed: %v`, err)
+ }
+ bf, err := b.Lookup("F")
+ if err != nil {
+ log.Fatalf(`b.Lookup("F") failed: %v`, err)
+ }
+ if af.(func() interface{})() != bf.(func() interface{})() {
+ panic("empty interfaces not equal")
+ }
+
+ ag, err := a.Lookup("G")
+ if err != nil {
+ log.Fatalf(`a.Lookup("G") failed: %v`, err)
+ }
+ bg, err := b.Lookup("G")
+ if err != nil {
+ log.Fatalf(`b.Lookup("G") failed: %v`, err)
+ }
+ if ag.(func() iface_i.I)() != bg.(func() iface_i.I)() {
+ panic("nonempty interfaces not equal")
+ }
+}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/iface_a/a.go b/src/cmd/cgo/internal/testplugin/testdata/iface_a/a.go
new file mode 100644
index 0000000000..357f7e827e
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/iface_a/a.go
@@ -0,0 +1,17 @@
+// 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 "testplugin/iface_i"
+
+//go:noinline
+func F() interface{} {
+ return (*iface_i.T)(nil)
+}
+
+//go:noinline
+func G() iface_i.I {
+ return (*iface_i.T)(nil)
+}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/iface_b/b.go b/src/cmd/cgo/internal/testplugin/testdata/iface_b/b.go
new file mode 100644
index 0000000000..357f7e827e
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/iface_b/b.go
@@ -0,0 +1,17 @@
+// 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 "testplugin/iface_i"
+
+//go:noinline
+func F() interface{} {
+ return (*iface_i.T)(nil)
+}
+
+//go:noinline
+func G() iface_i.I {
+ return (*iface_i.T)(nil)
+}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/iface_i/i.go b/src/cmd/cgo/internal/testplugin/testdata/iface_i/i.go
new file mode 100644
index 0000000000..31c80387c7
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/iface_i/i.go
@@ -0,0 +1,17 @@
+// 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 iface_i
+
+type I interface {
+ M()
+}
+
+type T struct {
+}
+
+func (t *T) M() {
+}
+
+// *T implements I
diff --git a/src/cmd/cgo/internal/testplugin/testdata/issue18584/main.go b/src/cmd/cgo/internal/testplugin/testdata/issue18584/main.go
new file mode 100644
index 0000000000..c280fd4620
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/issue18584/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("G")
+ if err != nil {
+ panic(err)
+ }
+ g := sym.(func() bool)
+ if !g() {
+ panic("expected types to match, Issue #18584")
+ }
+}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/issue18584/plugin.go b/src/cmd/cgo/internal/testplugin/testdata/issue18584/plugin.go
new file mode 100644
index 0000000000..be0868d375
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/issue18584/plugin.go
@@ -0,0 +1,19 @@
+// 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 "reflect"
+
+type C struct {
+}
+
+func F(c *C) *C {
+ return nil
+}
+
+func G() bool {
+ var c *C
+ return reflect.TypeOf(F).Out(0) == reflect.TypeOf(c)
+}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/issue18676/dynamodbstreamsevt/definition.go b/src/cmd/cgo/internal/testplugin/testdata/issue18676/dynamodbstreamsevt/definition.go
new file mode 100644
index 0000000000..70fd054d08
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/issue18676/dynamodbstreamsevt/definition.go
@@ -0,0 +1,13 @@
+// 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 dynamodbstreamsevt
+
+import "encoding/json"
+
+var foo json.RawMessage
+
+type Event struct{}
+
+func (e *Event) Dummy() {}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/issue18676/main.go b/src/cmd/cgo/internal/testplugin/testdata/issue18676/main.go
new file mode 100644
index 0000000000..471f3d969c
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/issue18676/main.go
@@ -0,0 +1,32 @@
+// 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.
+
+// The bug happened like this:
+// 1. The main binary adds an itab for *json.UnsupportedValueError / error
+// (concrete type / interface type). This itab goes in hash bucket 0x111.
+// 2. The plugin adds that same itab again. That makes a cycle in the itab
+// chain rooted at hash bucket 0x111.
+// 3. The main binary then asks for the itab for *dynamodbstreamsevt.Event /
+// json.Unmarshaler. This itab happens to also live in bucket 0x111.
+// The lookup code goes into an infinite loop searching for this itab.
+//
+// The code is carefully crafted so that the two itabs are both from the
+// same bucket, and so that the second itab doesn't exist in
+// the itab hashmap yet (so the entire linked list must be searched).
+package main
+
+import (
+ "encoding/json"
+ "plugin"
+ "testplugin/issue18676/dynamodbstreamsevt"
+)
+
+func main() {
+ plugin.Open("plugin.so")
+
+ var x interface{} = (*dynamodbstreamsevt.Event)(nil)
+ if _, ok := x.(json.Unmarshaler); !ok {
+ println("something")
+ }
+}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/issue18676/plugin.go b/src/cmd/cgo/internal/testplugin/testdata/issue18676/plugin.go
new file mode 100644
index 0000000000..e7fc74f777
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/issue18676/plugin.go
@@ -0,0 +1,11 @@
+// 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 "C"
+
+import "testplugin/issue18676/dynamodbstreamsevt"
+
+func F(evt *dynamodbstreamsevt.Event) {}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/issue19418/main.go b/src/cmd/cgo/internal/testplugin/testdata/issue19418/main.go
new file mode 100644
index 0000000000..2ec9f9aaaa
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/issue19418/main.go
@@ -0,0 +1,29 @@
+// 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 (
+ "fmt"
+ "os"
+ "plugin"
+)
+
+func main() {
+ p, err := plugin.Open("plugin.so")
+ if err != nil {
+ panic(err)
+ }
+
+ val, err := p.Lookup("Val")
+ if err != nil {
+ panic(err)
+ }
+ got := *val.(*string)
+ const want = "linkstr"
+ if got != want {
+ fmt.Fprintf(os.Stderr, "issue19418 value is %q, want %q\n", got, want)
+ os.Exit(2)
+ }
+}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/issue19418/plugin.go b/src/cmd/cgo/internal/testplugin/testdata/issue19418/plugin.go
new file mode 100644
index 0000000000..fe93b16143
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/issue19418/plugin.go
@@ -0,0 +1,7 @@
+// 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
+
+var Val = "val-unset"
diff --git a/src/cmd/cgo/internal/testplugin/testdata/issue19529/plugin.go b/src/cmd/cgo/internal/testplugin/testdata/issue19529/plugin.go
new file mode 100644
index 0000000000..ad2df6cc7c
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/issue19529/plugin.go
@@ -0,0 +1,15 @@
+package main
+
+import (
+ "reflect"
+)
+
+type Foo struct {
+ Bar string `json:"Bar@baz,omitempty"`
+}
+
+func F() {
+ println(reflect.TypeOf(Foo{}).Field(0).Tag)
+}
+
+func main() {}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/issue19534/main.go b/src/cmd/cgo/internal/testplugin/testdata/issue19534/main.go
new file mode 100644
index 0000000000..de263b6f0f
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/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/src/cmd/cgo/internal/testplugin/testdata/issue19534/plugin.go b/src/cmd/cgo/internal/testplugin/testdata/issue19534/plugin.go
new file mode 100644
index 0000000000..582d33305c
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/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/src/cmd/cgo/internal/testplugin/testdata/issue22175/main.go b/src/cmd/cgo/internal/testplugin/testdata/issue22175/main.go
new file mode 100644
index 0000000000..9be9bab9dc
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/issue22175/main.go
@@ -0,0 +1,28 @@
+// 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 (
+ "fmt"
+ "os"
+ "plugin"
+)
+
+func main() {
+ p2, err := plugin.Open("issue22175_plugin1.so")
+ if err != nil {
+ panic(err)
+ }
+ f, err := p2.Lookup("F")
+ if err != nil {
+ panic(err)
+ }
+ got := f.(func() int)()
+ const want = 971
+ if got != want {
+ fmt.Fprintf(os.Stderr, "issue22175: F()=%d, want %d", got, want)
+ os.Exit(1)
+ }
+}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/issue22175/plugin1.go b/src/cmd/cgo/internal/testplugin/testdata/issue22175/plugin1.go
new file mode 100644
index 0000000000..5ae6cb631e
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/issue22175/plugin1.go
@@ -0,0 +1,21 @@
+// 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 F() int {
+ p2, err := plugin.Open("issue22175_plugin2.so")
+ if err != nil {
+ panic(err)
+ }
+ g, err := p2.Lookup("G")
+ if err != nil {
+ panic(err)
+ }
+ return g.(func() int)()
+}
+
+func main() {}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/issue22175/plugin2.go b/src/cmd/cgo/internal/testplugin/testdata/issue22175/plugin2.go
new file mode 100644
index 0000000000..f387a192e6
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/issue22175/plugin2.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 G() int { return 971 }
+
+func main() {}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/issue22295.pkg/main.go b/src/cmd/cgo/internal/testplugin/testdata/issue22295.pkg/main.go
new file mode 100644
index 0000000000..44b2a2140e
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/issue22295.pkg/main.go
@@ -0,0 +1,28 @@
+// 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.
+
+//go:build ignore
+
+package main
+
+import (
+ "log"
+ "plugin"
+)
+
+func main() {
+ p, err := plugin.Open("issue.22295.so")
+ if err != nil {
+ log.Fatal(err)
+ }
+ f, err := p.Lookup("F")
+ if err != nil {
+ log.Fatal(err)
+ }
+ const want = 2503
+ got := f.(func() int)()
+ if got != want {
+ log.Fatalf("got %d, want %d", got, want)
+ }
+}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/issue22295.pkg/plugin.go b/src/cmd/cgo/internal/testplugin/testdata/issue22295.pkg/plugin.go
new file mode 100644
index 0000000000..46b08a405b
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/issue22295.pkg/plugin.go
@@ -0,0 +1,16 @@
+// 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
+
+var f *int
+
+func init() {
+ f = new(int)
+ *f = 2503
+}
+
+func F() int { return *f }
+
+func main() {}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/issue24351/main.go b/src/cmd/cgo/internal/testplugin/testdata/issue24351/main.go
new file mode 100644
index 0000000000..4107adff7b
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/issue24351/main.go
@@ -0,0 +1,21 @@
+// Copyright 2018 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("issue24351.so")
+ if err != nil {
+ panic(err)
+ }
+ f, err := p.Lookup("B")
+ if err != nil {
+ panic(err)
+ }
+ c := make(chan bool)
+ f.(func(chan bool))(c)
+ <-c
+}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/issue24351/plugin.go b/src/cmd/cgo/internal/testplugin/testdata/issue24351/plugin.go
new file mode 100644
index 0000000000..db17e0a609
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/issue24351/plugin.go
@@ -0,0 +1,14 @@
+// Copyright 2018 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 "fmt"
+
+func B(c chan bool) {
+ go func() {
+ fmt.Println(1.5)
+ c <- true
+ }()
+}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/issue25756/main.go b/src/cmd/cgo/internal/testplugin/testdata/issue25756/main.go
new file mode 100644
index 0000000000..817daf42f6
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/issue25756/main.go
@@ -0,0 +1,52 @@
+// Copyright 2018 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.
+
+// Run the game of life in C using Go for parallelization.
+
+package main
+
+import (
+ "flag"
+ "fmt"
+ "plugin"
+)
+
+const MAXDIM = 100
+
+var dim = flag.Int("dim", 16, "board dimensions")
+var gen = flag.Int("gen", 10, "generations")
+
+func main() {
+ flag.Parse()
+
+ var a [MAXDIM * MAXDIM]int32
+ for i := 2; i < *dim; i += 8 {
+ for j := 2; j < *dim-3; j += 8 {
+ for y := 0; y < 3; y++ {
+ a[i**dim+j+y] = 1
+ }
+ }
+ }
+
+ p, err := plugin.Open("life.so")
+ if err != nil {
+ panic(err)
+ }
+ f, err := p.Lookup("Run")
+ if err != nil {
+ panic(err)
+ }
+ f.(func(int, int, int, []int32))(*gen, *dim, *dim, a[:])
+
+ for i := 0; i < *dim; i++ {
+ for j := 0; j < *dim; j++ {
+ if a[i**dim+j] == 0 {
+ fmt.Print(" ")
+ } else {
+ fmt.Print("X")
+ }
+ }
+ fmt.Print("\n")
+ }
+}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/issue25756/plugin/c-life.c b/src/cmd/cgo/internal/testplugin/testdata/issue25756/plugin/c-life.c
new file mode 100644
index 0000000000..f853163e2f
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/issue25756/plugin/c-life.c
@@ -0,0 +1,56 @@
+// Copyright 2010 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.
+
+#include <assert.h>
+#include "life.h"
+#include "_cgo_export.h"
+
+const int MYCONST = 0;
+
+// Do the actual manipulation of the life board in C. This could be
+// done easily in Go, we are just using C for demonstration
+// purposes.
+void
+Step(int x, int y, int *a, int *n)
+{
+ struct GoStart_return r;
+
+ // Use Go to start 4 goroutines each of which handles 1/4 of the
+ // board.
+ r = GoStart(0, x, y, 0, x / 2, 0, y / 2, a, n);
+ assert(r.r0 == 0 && r.r1 == 100); // test multiple returns
+ r = GoStart(1, x, y, x / 2, x, 0, y / 2, a, n);
+ assert(r.r0 == 1 && r.r1 == 101); // test multiple returns
+ GoStart(2, x, y, 0, x / 2, y / 2, y, a, n);
+ GoStart(3, x, y, x / 2, x, y / 2, y, a, n);
+ GoWait(0);
+ GoWait(1);
+ GoWait(2);
+ GoWait(3);
+}
+
+// The actual computation. This is called in parallel.
+void
+DoStep(int xdim, int ydim, int xstart, int xend, int ystart, int yend, int *a, int *n)
+{
+ int x, y, c, i, j;
+
+ for(x = xstart; x < xend; x++) {
+ for(y = ystart; y < yend; y++) {
+ c = 0;
+ for(i = -1; i <= 1; i++) {
+ for(j = -1; j <= 1; j++) {
+ if(x+i >= 0 && x+i < xdim &&
+ y+j >= 0 && y+j < ydim &&
+ (i != 0 || j != 0))
+ c += a[(x+i)*xdim + (y+j)] != 0;
+ }
+ }
+ if(c == 3 || (c == 2 && a[x*xdim + y] != 0))
+ n[x*xdim + y] = 1;
+ else
+ n[x*xdim + y] = 0;
+ }
+ }
+}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/issue25756/plugin/life.go b/src/cmd/cgo/internal/testplugin/testdata/issue25756/plugin/life.go
new file mode 100644
index 0000000000..468bc6fab6
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/issue25756/plugin/life.go
@@ -0,0 +1,40 @@
+// Copyright 2010 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
+
+// #include "life.h"
+import "C"
+
+import "unsafe"
+
+func Run(gen, x, y int, a []int32) {
+ n := make([]int32, x*y)
+ for i := 0; i < gen; i++ {
+ C.Step(C.int(x), C.int(y), (*C.int)(unsafe.Pointer(&a[0])), (*C.int)(unsafe.Pointer(&n[0])))
+ copy(a, n)
+ }
+}
+
+// Keep the channels visible from Go.
+var chans [4]chan bool
+
+// Double return value is just for testing.
+//
+//export GoStart
+func GoStart(i, xdim, ydim, xstart, xend, ystart, yend C.int, a *C.int, n *C.int) (int, int) {
+ c := make(chan bool, int(C.MYCONST))
+ go func() {
+ C.DoStep(xdim, ydim, xstart, xend, ystart, yend, a, n)
+ c <- true
+ }()
+ chans[i] = c
+ return int(i), int(i + 100)
+}
+
+//export GoWait
+func GoWait(i C.int) {
+ <-chans[i]
+ chans[i] = nil
+}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/issue25756/plugin/life.h b/src/cmd/cgo/internal/testplugin/testdata/issue25756/plugin/life.h
new file mode 100644
index 0000000000..11d2b97226
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/issue25756/plugin/life.h
@@ -0,0 +1,7 @@
+// Copyright 2010 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.
+
+extern void Step(int, int, int *, int *);
+extern void DoStep(int, int, int, int, int, int, int *, int *);
+extern const int MYCONST;
diff --git a/src/cmd/cgo/internal/testplugin/testdata/issue44956/base/base.go b/src/cmd/cgo/internal/testplugin/testdata/issue44956/base/base.go
new file mode 100644
index 0000000000..609aa0dff4
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/issue44956/base/base.go
@@ -0,0 +1,7 @@
+// Copyright 2021 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 base
+
+var X = &map[int]int{123: 456}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/issue44956/main.go b/src/cmd/cgo/internal/testplugin/testdata/issue44956/main.go
new file mode 100644
index 0000000000..287a60585e
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/issue44956/main.go
@@ -0,0 +1,47 @@
+// Copyright 2021 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.
+
+// Issue 44956: writable static temp is not exported correctly.
+// In the test below, package base is
+//
+// X = &map{...}
+//
+// which compiles to
+//
+// X = &stmp // static
+// stmp = makemap(...) // in init function
+//
+// plugin1 and plugin2 both import base. plugin1 doesn't use
+// base.X, so that symbol is deadcoded in plugin1.
+//
+// plugin1 is loaded first. base.init runs at that point, which
+// initialize base.stmp.
+//
+// plugin2 is then loaded. base.init already ran, so it doesn't run
+// again. When base.stmp is not exported, plugin2's base.X points to
+// its own private base.stmp, which is not initialized, fail.
+
+package main
+
+import "plugin"
+
+func main() {
+ _, err := plugin.Open("issue44956p1.so")
+ if err != nil {
+ panic("FAIL")
+ }
+
+ p2, err := plugin.Open("issue44956p2.so")
+ if err != nil {
+ panic("FAIL")
+ }
+ f, err := p2.Lookup("F")
+ if err != nil {
+ panic("FAIL")
+ }
+ x := f.(func() *map[int]int)()
+ if x == nil || (*x)[123] != 456 {
+ panic("FAIL")
+ }
+}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/issue44956/plugin1.go b/src/cmd/cgo/internal/testplugin/testdata/issue44956/plugin1.go
new file mode 100644
index 0000000000..499fa31abf
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/issue44956/plugin1.go
@@ -0,0 +1,9 @@
+// Copyright 2021 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 _ "testplugin/issue44956/base"
+
+func main() {}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/issue44956/plugin2.go b/src/cmd/cgo/internal/testplugin/testdata/issue44956/plugin2.go
new file mode 100644
index 0000000000..a73542ca71
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/issue44956/plugin2.go
@@ -0,0 +1,11 @@
+// Copyright 2021 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 "testplugin/issue44956/base"
+
+func F() *map[int]int { return base.X }
+
+func main() {}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/issue52937/main.go b/src/cmd/cgo/internal/testplugin/testdata/issue52937/main.go
new file mode 100644
index 0000000000..66f09effea
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/issue52937/main.go
@@ -0,0 +1,9 @@
+// Copyright 2022 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 main() {}
+func F[T any]() {}
+func G[T any](T) {}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/issue53989/main.go b/src/cmd/cgo/internal/testplugin/testdata/issue53989/main.go
new file mode 100644
index 0000000000..6907dfd858
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/issue53989/main.go
@@ -0,0 +1,32 @@
+// Copyright 2022 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.
+
+// Issue 53989: the use of jump table caused a function
+// from the plugin jumps in the middle of the function
+// to the function with the same name in the main
+// executable. As these two functions may be compiled
+// differently as plugin needs to be PIC, this causes
+// crash.
+
+package main
+
+import (
+ "plugin"
+
+ "testplugin/issue53989/p"
+)
+
+func main() {
+ p.Square(7) // call the function in main executable
+
+ p, err := plugin.Open("issue53989.so")
+ if err != nil {
+ panic(err)
+ }
+ f, err := p.Lookup("Square")
+ if err != nil {
+ panic(err)
+ }
+ f.(func(int))(7) // call the plugin one
+}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/issue53989/p/p.go b/src/cmd/cgo/internal/testplugin/testdata/issue53989/p/p.go
new file mode 100644
index 0000000000..02567c1cee
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/issue53989/p/p.go
@@ -0,0 +1,52 @@
+// Copyright 2022 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 p
+
+import (
+ "fmt"
+ "runtime"
+)
+
+var y int
+
+//go:noinline
+func Square(x int) {
+ var pc0, pc1 [1]uintptr
+ runtime.Callers(1, pc0[:]) // get PC at entry
+
+ // a switch using jump table
+ switch x {
+ case 1:
+ y = 1
+ case 2:
+ y = 4
+ case 3:
+ y = 9
+ case 4:
+ y = 16
+ case 5:
+ y = 25
+ case 6:
+ y = 36
+ case 7:
+ y = 49
+ case 8:
+ y = 64
+ default:
+ panic("too large")
+ }
+
+ // check PC is in the same function
+ runtime.Callers(1, pc1[:])
+ if pc1[0] < pc0[0] || pc1[0] > pc0[0]+1000000 {
+ fmt.Printf("jump across DSO boundary. pc0=%x, pc1=%x\n", pc0[0], pc1[0])
+ panic("FAIL")
+ }
+
+ if y != x*x {
+ fmt.Printf("x=%d y=%d!=%d\n", x, y, x*x)
+ panic("FAIL")
+ }
+}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/issue53989/plugin.go b/src/cmd/cgo/internal/testplugin/testdata/issue53989/plugin.go
new file mode 100644
index 0000000000..a753ee4419
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/issue53989/plugin.go
@@ -0,0 +1,13 @@
+// Copyright 2022 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 "testplugin/issue53989/p"
+
+func Square(x int) { // export Square for plugin
+ p.Square(x)
+}
+
+func main() {}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/method/main.go b/src/cmd/cgo/internal/testplugin/testdata/method/main.go
new file mode 100644
index 0000000000..5e9189b450
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/method/main.go
@@ -0,0 +1,26 @@
+// Copyright 2020 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.
+
+// Issue 42579: methods of symbols exported from plugin must be live.
+
+package main
+
+import (
+ "plugin"
+ "reflect"
+)
+
+func main() {
+ p, err := plugin.Open("plugin.so")
+ if err != nil {
+ panic(err)
+ }
+
+ x, err := p.Lookup("X")
+ if err != nil {
+ panic(err)
+ }
+
+ reflect.ValueOf(x).Elem().MethodByName("M").Call(nil)
+}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/method/plugin.go b/src/cmd/cgo/internal/testplugin/testdata/method/plugin.go
new file mode 100644
index 0000000000..240edd3bc4
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/method/plugin.go
@@ -0,0 +1,13 @@
+// Copyright 2020 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 main() {}
+
+type T int
+
+func (T) M() { println("M") }
+
+var X T
diff --git a/src/cmd/cgo/internal/testplugin/testdata/method2/main.go b/src/cmd/cgo/internal/testplugin/testdata/method2/main.go
new file mode 100644
index 0000000000..89afbda3d4
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/method2/main.go
@@ -0,0 +1,32 @@
+// Copyright 2021 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.
+
+// A type can be passed to a plugin and converted to interface
+// there. So its methods need to be live.
+
+package main
+
+import (
+ "plugin"
+
+ "testplugin/method2/p"
+)
+
+var t p.T
+
+type I interface{ M() }
+
+func main() {
+ pl, err := plugin.Open("method2.so")
+ if err != nil {
+ panic(err)
+ }
+
+ f, err := pl.Lookup("F")
+ if err != nil {
+ panic(err)
+ }
+
+ f.(func(p.T) interface{})(t).(I).M()
+}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/method2/p/p.go b/src/cmd/cgo/internal/testplugin/testdata/method2/p/p.go
new file mode 100644
index 0000000000..acb526acec
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/method2/p/p.go
@@ -0,0 +1,9 @@
+// Copyright 2021 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 p
+
+type T int
+
+func (T) M() { println("M") }
diff --git a/src/cmd/cgo/internal/testplugin/testdata/method2/plugin.go b/src/cmd/cgo/internal/testplugin/testdata/method2/plugin.go
new file mode 100644
index 0000000000..6198e7648e
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/method2/plugin.go
@@ -0,0 +1,11 @@
+// Copyright 2021 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 "testplugin/method2/p"
+
+func main() {}
+
+func F(t p.T) interface{} { return t }
diff --git a/src/cmd/cgo/internal/testplugin/testdata/method3/main.go b/src/cmd/cgo/internal/testplugin/testdata/method3/main.go
new file mode 100644
index 0000000000..a3a51711cd
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/method3/main.go
@@ -0,0 +1,32 @@
+// Copyright 2022 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.
+
+// An unexported method can be reachable from the plugin via interface
+// when a package is shared. So it need to be live.
+
+package main
+
+import (
+ "plugin"
+
+ "testplugin/method3/p"
+)
+
+var i p.I
+
+func main() {
+ pl, err := plugin.Open("method3.so")
+ if err != nil {
+ panic(err)
+ }
+
+ f, err := pl.Lookup("F")
+ if err != nil {
+ panic(err)
+ }
+
+ f.(func())()
+
+ i = p.T(123)
+}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/method3/p/p.go b/src/cmd/cgo/internal/testplugin/testdata/method3/p/p.go
new file mode 100644
index 0000000000..f72f7c715c
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/method3/p/p.go
@@ -0,0 +1,17 @@
+// Copyright 2022 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 p
+
+type T int
+
+func (T) m() { println("m") }
+
+type I interface{ m() }
+
+func F() {
+ i.m()
+}
+
+var i I = T(123)
diff --git a/src/cmd/cgo/internal/testplugin/testdata/method3/plugin.go b/src/cmd/cgo/internal/testplugin/testdata/method3/plugin.go
new file mode 100644
index 0000000000..bd25b31857
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/method3/plugin.go
@@ -0,0 +1,11 @@
+// Copyright 2022 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 "testplugin/method3/p"
+
+func main() {}
+
+func F() { p.F() }
diff --git a/src/cmd/cgo/internal/testplugin/testdata/plugin1/plugin1.go b/src/cmd/cgo/internal/testplugin/testdata/plugin1/plugin1.go
new file mode 100644
index 0000000000..d29d674ade
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/plugin1/plugin1.go
@@ -0,0 +1,57 @@
+// Copyright 2016 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
+
+// // No C code required.
+import "C"
+
+import (
+ "reflect"
+
+ "testplugin/common"
+)
+
+func F() int {
+ _ = make([]byte, 1<<21) // trigger stack unwind, Issue #18190.
+ return 3
+}
+
+func ReadCommonX() int {
+ return common.X
+}
+
+var Seven int
+
+func call(fn func()) {
+ fn()
+}
+
+func g() {
+ common.X *= Seven
+}
+
+func init() {
+ Seven = 7
+ call(g)
+}
+
+type sameNameReusedInPlugins struct {
+ X string
+}
+
+type sameNameHolder struct {
+ F *sameNameReusedInPlugins
+}
+
+func UnexportedNameReuse() {
+ h := sameNameHolder{}
+ v := reflect.ValueOf(&h).Elem().Field(0)
+ newval := reflect.New(v.Type().Elem())
+ v.Set(newval)
+}
+
+func main() {
+ panic("plugin1.main called")
+}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/plugin2/plugin2.go b/src/cmd/cgo/internal/testplugin/testdata/plugin2/plugin2.go
new file mode 100644
index 0000000000..31ed642ca5
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/plugin2/plugin2.go
@@ -0,0 +1,44 @@
+// Copyright 2016 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
+
+//#include <errno.h>
+//#include <string.h>
+import "C"
+
+// #include
+// void cfunc() {} // uses cgo_topofstack
+
+import (
+ "reflect"
+ "strings"
+
+ "testplugin/common"
+)
+
+func init() {
+ _ = strings.NewReplacer() // trigger stack unwind, Issue #18190.
+ C.strerror(C.EIO) // uses cgo_topofstack
+ common.X = 2
+}
+
+type sameNameReusedInPlugins struct {
+ X string
+}
+
+type sameNameHolder struct {
+ F *sameNameReusedInPlugins
+}
+
+func UnexportedNameReuse() {
+ h := sameNameHolder{}
+ v := reflect.ValueOf(&h).Elem().Field(0)
+ newval := reflect.New(v.Type().Elem())
+ v.Set(newval)
+}
+
+func main() {
+ panic("plugin1.main called")
+}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/sub/plugin1/plugin1.go b/src/cmd/cgo/internal/testplugin/testdata/sub/plugin1/plugin1.go
new file mode 100644
index 0000000000..5f891b09a3
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/sub/plugin1/plugin1.go
@@ -0,0 +1,23 @@
+// Copyright 2016 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
+
+// // No C code required.
+import "C"
+
+import "testplugin/common"
+
+func F() int { return 17 }
+
+var FuncVar = func() {}
+
+func ReadCommonX() int {
+ FuncVar()
+ return common.X
+}
+
+func main() {
+ panic("plugin1.main called")
+}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/unnamed1/main.go b/src/cmd/cgo/internal/testplugin/testdata/unnamed1/main.go
new file mode 100644
index 0000000000..1620dc48ce
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/unnamed1/main.go
@@ -0,0 +1,25 @@
+// Copyright 2016 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.
+
+//go:build ignore
+
+package main
+
+// // No C code required.
+import "C"
+
+func FuncInt() int { return 1 }
+
+// Add a recursive type to check that type equality across plugins doesn't
+// crash. See https://golang.org/issues/19258
+func FuncRecursive() X { return X{} }
+
+type Y struct {
+ X *X
+}
+type X struct {
+ Y Y
+}
+
+func main() {}
diff --git a/src/cmd/cgo/internal/testplugin/testdata/unnamed2/main.go b/src/cmd/cgo/internal/testplugin/testdata/unnamed2/main.go
new file mode 100644
index 0000000000..027ef6475c
--- /dev/null
+++ b/src/cmd/cgo/internal/testplugin/testdata/unnamed2/main.go
@@ -0,0 +1,23 @@
+// Copyright 2016 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.
+
+//go:build ignore
+
+package main
+
+// // No C code required.
+import "C"
+
+func FuncInt() int { return 2 }
+
+func FuncRecursive() X { return X{} }
+
+type Y struct {
+ X *X
+}
+type X struct {
+ Y Y
+}
+
+func main() {}