diff options
Diffstat (limited to 'misc/cgo/testplugin/testdata')
50 files changed, 1395 insertions, 0 deletions
diff --git a/misc/cgo/testplugin/testdata/checkdwarf/main.go b/misc/cgo/testplugin/testdata/checkdwarf/main.go new file mode 100644 index 0000000..7886c83 --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/common/common.go b/misc/cgo/testplugin/testdata/common/common.go new file mode 100644 index 0000000..b064e6b --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/forkexec/main.go b/misc/cgo/testplugin/testdata/forkexec/main.go new file mode 100644 index 0000000..3169ff5 --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/host/host.go b/misc/cgo/testplugin/testdata/host/host.go new file mode 100644 index 0000000..a379932 --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/iface/main.go b/misc/cgo/testplugin/testdata/iface/main.go new file mode 100644 index 0000000..c04f288 --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/iface_a/a.go b/misc/cgo/testplugin/testdata/iface_a/a.go new file mode 100644 index 0000000..357f7e8 --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/iface_b/b.go b/misc/cgo/testplugin/testdata/iface_b/b.go new file mode 100644 index 0000000..357f7e8 --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/iface_i/i.go b/misc/cgo/testplugin/testdata/iface_i/i.go new file mode 100644 index 0000000..31c8038 --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/issue18584/main.go b/misc/cgo/testplugin/testdata/issue18584/main.go new file mode 100644 index 0000000..c280fd4 --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/issue18584/plugin.go b/misc/cgo/testplugin/testdata/issue18584/plugin.go new file mode 100644 index 0000000..be0868d --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/issue18676/dynamodbstreamsevt/definition.go b/misc/cgo/testplugin/testdata/issue18676/dynamodbstreamsevt/definition.go new file mode 100644 index 0000000..70fd054 --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/issue18676/main.go b/misc/cgo/testplugin/testdata/issue18676/main.go new file mode 100644 index 0000000..b1dadbe --- /dev/null +++ b/misc/cgo/testplugin/testdata/issue18676/main.go @@ -0,0 +1,31 @@ +// 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/misc/cgo/testplugin/testdata/issue18676/plugin.go b/misc/cgo/testplugin/testdata/issue18676/plugin.go new file mode 100644 index 0000000..e7fc74f --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/issue19418/main.go b/misc/cgo/testplugin/testdata/issue19418/main.go new file mode 100644 index 0000000..2ec9f9a --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/issue19418/plugin.go b/misc/cgo/testplugin/testdata/issue19418/plugin.go new file mode 100644 index 0000000..fe93b16 --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/issue19529/plugin.go b/misc/cgo/testplugin/testdata/issue19529/plugin.go new file mode 100644 index 0000000..ad2df6c --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/issue19534/main.go b/misc/cgo/testplugin/testdata/issue19534/main.go new file mode 100644 index 0000000..de263b6 --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/issue19534/plugin.go b/misc/cgo/testplugin/testdata/issue19534/plugin.go new file mode 100644 index 0000000..582d333 --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/issue22175/main.go b/misc/cgo/testplugin/testdata/issue22175/main.go new file mode 100644 index 0000000..9be9bab --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/issue22175/plugin1.go b/misc/cgo/testplugin/testdata/issue22175/plugin1.go new file mode 100644 index 0000000..5ae6cb6 --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/issue22175/plugin2.go b/misc/cgo/testplugin/testdata/issue22175/plugin2.go new file mode 100644 index 0000000..f387a19 --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/issue22295.pkg/main.go b/misc/cgo/testplugin/testdata/issue22295.pkg/main.go new file mode 100644 index 0000000..6cb186e --- /dev/null +++ b/misc/cgo/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. + +// +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/misc/cgo/testplugin/testdata/issue22295.pkg/plugin.go b/misc/cgo/testplugin/testdata/issue22295.pkg/plugin.go new file mode 100644 index 0000000..46b08a4 --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/issue24351/main.go b/misc/cgo/testplugin/testdata/issue24351/main.go new file mode 100644 index 0000000..4107adf --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/issue24351/plugin.go b/misc/cgo/testplugin/testdata/issue24351/plugin.go new file mode 100644 index 0000000..db17e0a --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/issue25756/main.go b/misc/cgo/testplugin/testdata/issue25756/main.go new file mode 100644 index 0000000..817daf4 --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/issue25756/plugin/c-life.c b/misc/cgo/testplugin/testdata/issue25756/plugin/c-life.c new file mode 100644 index 0000000..f853163 --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/issue25756/plugin/life.go b/misc/cgo/testplugin/testdata/issue25756/plugin/life.go new file mode 100644 index 0000000..675a192 --- /dev/null +++ b/misc/cgo/testplugin/testdata/issue25756/plugin/life.go @@ -0,0 +1,39 @@ +// 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 + +//export GoStart +// Double return value is just for testing. +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/misc/cgo/testplugin/testdata/issue25756/plugin/life.h b/misc/cgo/testplugin/testdata/issue25756/plugin/life.h new file mode 100644 index 0000000..11d2b97 --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/issue44956/base/base.go b/misc/cgo/testplugin/testdata/issue44956/base/base.go new file mode 100644 index 0000000..609aa0d --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/issue44956/main.go b/misc/cgo/testplugin/testdata/issue44956/main.go new file mode 100644 index 0000000..287a605 --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/issue44956/plugin1.go b/misc/cgo/testplugin/testdata/issue44956/plugin1.go new file mode 100644 index 0000000..499fa31 --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/issue44956/plugin2.go b/misc/cgo/testplugin/testdata/issue44956/plugin2.go new file mode 100644 index 0000000..a73542c --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/issue52937/main.go b/misc/cgo/testplugin/testdata/issue52937/main.go new file mode 100644 index 0000000..66f09ef --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/issue53989/main.go b/misc/cgo/testplugin/testdata/issue53989/main.go new file mode 100644 index 0000000..6907dfd --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/issue53989/p/p.go b/misc/cgo/testplugin/testdata/issue53989/p/p.go new file mode 100644 index 0000000..02567c1 --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/issue53989/plugin.go b/misc/cgo/testplugin/testdata/issue53989/plugin.go new file mode 100644 index 0000000..a753ee4 --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/method/main.go b/misc/cgo/testplugin/testdata/method/main.go new file mode 100644 index 0000000..5e9189b --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/method/plugin.go b/misc/cgo/testplugin/testdata/method/plugin.go new file mode 100644 index 0000000..240edd3 --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/method2/main.go b/misc/cgo/testplugin/testdata/method2/main.go new file mode 100644 index 0000000..89afbda --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/method2/p/p.go b/misc/cgo/testplugin/testdata/method2/p/p.go new file mode 100644 index 0000000..acb526a --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/method2/plugin.go b/misc/cgo/testplugin/testdata/method2/plugin.go new file mode 100644 index 0000000..6198e76 --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/method3/main.go b/misc/cgo/testplugin/testdata/method3/main.go new file mode 100644 index 0000000..a3a5171 --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/method3/p/p.go b/misc/cgo/testplugin/testdata/method3/p/p.go new file mode 100644 index 0000000..3846bc0 --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/method3/plugin.go b/misc/cgo/testplugin/testdata/method3/plugin.go new file mode 100644 index 0000000..bd25b31 --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/plugin1/plugin1.go b/misc/cgo/testplugin/testdata/plugin1/plugin1.go new file mode 100644 index 0000000..d29d674 --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/plugin2/plugin2.go b/misc/cgo/testplugin/testdata/plugin2/plugin2.go new file mode 100644 index 0000000..31ed642 --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/sub/plugin1/plugin1.go b/misc/cgo/testplugin/testdata/sub/plugin1/plugin1.go new file mode 100644 index 0000000..5f891b0 --- /dev/null +++ b/misc/cgo/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/misc/cgo/testplugin/testdata/unnamed1/main.go b/misc/cgo/testplugin/testdata/unnamed1/main.go new file mode 100644 index 0000000..dd1777b --- /dev/null +++ b/misc/cgo/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. + +// +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/misc/cgo/testplugin/testdata/unnamed2/main.go b/misc/cgo/testplugin/testdata/unnamed2/main.go new file mode 100644 index 0000000..757436f --- /dev/null +++ b/misc/cgo/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. + +// +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() {} |