]> Cypherpunks.ru repositories - gostls13.git/commitdiff
cmd/link: force eager binding when using plugins on darwin
authorCherry Mui <cherryyz@google.com>
Thu, 16 Dec 2021 19:33:13 +0000 (14:33 -0500)
committerCherry Mui <cherryyz@google.com>
Fri, 17 Dec 2021 16:05:31 +0000 (16:05 +0000)
When building/using plugins on darwin, we need to use flat
namespace so the same symbol from the main executable and the
plugin can be resolved to the same address. Apparently, when using
flat namespace the dynamic linker can hang at forkExec when
resolving a lazy binding. Work around it by forcing early bindings.

Fixes #38824.

Change-Id: I983aa0a0960b15bf3f7871382e8231ee244655f4
Reviewed-on: https://go-review.googlesource.com/c/go/+/372798
Trust: Cherry Mui <cherryyz@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Run-TryBot: Cherry Mui <cherryyz@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>

misc/cgo/testplugin/plugin_test.go
misc/cgo/testplugin/testdata/forkexec/main.go [new file with mode: 0644]
src/cmd/link/internal/ld/lib.go

index a6accc1dfbba9e76cd674735618b9a4f8f9793b9..10c5db2646b14824aa6c387569270c57eeb87678 100644 (file)
@@ -289,3 +289,31 @@ func TestIssue44956(t *testing.T) {
        goCmd(t, "build", "-o", "issue44956.exe", "./issue44956/main.go")
        run(t, "./issue44956.exe")
 }
+
+func TestForkExec(t *testing.T) {
+       // Issue 38824: importing the plugin package causes it hang in forkExec on darwin.
+
+       t.Parallel()
+       goCmd(t, "build", "-o", "forkexec.exe", "./forkexec/main.go")
+
+       var cmd *exec.Cmd
+       done := make(chan int, 1)
+
+       go func() {
+               for i := 0; i < 100; i++ {
+                       cmd = exec.Command("./forkexec.exe", "1")
+                       err := cmd.Run()
+                       if err != nil {
+                               t.Errorf("running command failed: %v", err)
+                               break
+                       }
+               }
+               done <- 1
+       }()
+       select {
+       case <-done:
+       case <-time.After(5 * time.Minute):
+               cmd.Process.Kill()
+               t.Fatalf("subprocess hang")
+       }
+}
diff --git a/misc/cgo/testplugin/testdata/forkexec/main.go b/misc/cgo/testplugin/testdata/forkexec/main.go
new file mode 100644 (file)
index 0000000..3169ff5
--- /dev/null
@@ -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()
+}
index 9e13db7b718783597d8a42644ef6e5c3fc8441a8..f1a37e955e93706e2324d1d476041616fd939c29 100644 (file)
@@ -1269,7 +1269,10 @@ func (ctxt *Link) hostlink() {
                if ctxt.DynlinkingGo() && buildcfg.GOOS != "ios" {
                        // -flat_namespace is deprecated on iOS.
                        // It is useful for supporting plugins. We don't support plugins on iOS.
-                       argv = append(argv, "-Wl,-flat_namespace")
+                       // -flat_namespace may cause the dynamic linker to hang at forkExec when
+                       // resolving a lazy binding. See issue 38824.
+                       // Force eager resolution to work around.
+                       argv = append(argv, "-Wl,-flat_namespace", "-Wl,-bind_at_load")
                }
                if !combineDwarf {
                        argv = append(argv, "-Wl,-S") // suppress STAB (symbolic debugging) symbols