]> Cypherpunks repositories - gostls13.git/commitdiff
[release-branch.go1.16] cmd/link: handle types as converted to interface when dynlink
authorCherry Zhang <cherryyz@google.com>
Fri, 26 Feb 2021 01:01:53 +0000 (20:01 -0500)
committerDmitri Shuralyov <dmitshur@golang.org>
Mon, 1 Mar 2021 22:31:33 +0000 (22:31 +0000)
When using plugins, a type (whose value) may be pass to a plugin
and get converted to interface there, or vice versa. We need to
treat the type as potentially converted to interface, and retain
its methods.

Updates #44586.
Fixes #44638.

Change-Id: I80dd35e68baedaa852a317543ccd78d94628d13b
Reviewed-on: https://go-review.googlesource.com/c/go/+/296709
Trust: Cherry Zhang <cherryyz@google.com>
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
(cherry picked from commit a655208c9ecd2fee4de6deff35a863b1c28a091c)
Reviewed-on: https://go-review.googlesource.com/c/go/+/296910

misc/cgo/testplugin/plugin_test.go
misc/cgo/testplugin/testdata/method2/main.go [new file with mode: 0644]
misc/cgo/testplugin/testdata/method2/p/p.go [new file with mode: 0644]
misc/cgo/testplugin/testdata/method2/plugin.go [new file with mode: 0644]
src/cmd/link/internal/ld/deadcode.go

index 9055dbda0442a63a20a81e69745b870bd61282e3..2d991012c820c76ec410720dc342093687ae6369 100644 (file)
@@ -201,12 +201,11 @@ func TestMethod(t *testing.T) {
        // Exported symbol's method must be live.
        goCmd(t, "build", "-buildmode=plugin", "-o", "plugin.so", "./method/plugin.go")
        goCmd(t, "build", "-o", "method.exe", "./method/main.go")
+       run(t, "./method.exe")
+}
 
-       ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-       defer cancel()
-       cmd := exec.CommandContext(ctx, "./method.exe")
-       out, err := cmd.CombinedOutput()
-       if err != nil {
-               t.Fatalf("%s: %v\n%s", strings.Join(cmd.Args, " "), err, out)
-       }
+func TestMethod2(t *testing.T) {
+       goCmd(t, "build", "-buildmode=plugin", "-o", "method2.so", "./method2/plugin.go")
+       goCmd(t, "build", "-o", "method2.exe", "./method2/main.go")
+       run(t, "./method2.exe")
 }
diff --git a/misc/cgo/testplugin/testdata/method2/main.go b/misc/cgo/testplugin/testdata/method2/main.go
new file mode 100644 (file)
index 0000000..6a87e7b
--- /dev/null
@@ -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 (file)
index 0000000..acb526a
--- /dev/null
@@ -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 (file)
index 0000000..6198e76
--- /dev/null
@@ -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 }
index 245076a83a5c32c204c0a28d03e7059dfa2f9300..bfa8640ba99a04b492d6a63f29c2f8f5913dd0c5 100644 (file)
@@ -24,6 +24,7 @@ type deadcodePass struct {
        ifaceMethod     map[methodsig]bool // methods declared in reached interfaces
        markableMethods []methodref        // methods of reached types
        reflectSeen     bool               // whether we have seen a reflect method call
+       dynlink         bool
 
        methodsigstmp []methodsig // scratch buffer for decoding method signatures
 }
@@ -34,6 +35,7 @@ func (d *deadcodePass) init() {
        if objabi.Fieldtrack_enabled != 0 {
                d.ldr.Reachparent = make([]loader.Sym, d.ldr.NSym())
        }
+       d.dynlink = d.ctxt.DynlinkingGo()
 
        if d.ctxt.BuildMode == BuildModeShared {
                // Mark all symbols defined in this library as reachable when
@@ -111,6 +113,11 @@ func (d *deadcodePass) flood() {
                var usedInIface bool
 
                if isgotype {
+                       if d.dynlink {
+                               // When dynaamic linking, a type may be passed across DSO
+                               // boundary and get converted to interface at the other side.
+                               d.ldr.SetAttrUsedInIface(symIdx, true)
+                       }
                        usedInIface = d.ldr.AttrUsedInIface(symIdx)
                }