]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/go/internal/work: allow @ character in some -Wl, linker flags on darwin
authorPedro Tôrres <t0rr3sp3dr0@gmail.com>
Fri, 27 Dec 2024 07:21:53 +0000 (07:21 +0000)
committerGopher Robot <gobot@golang.org>
Fri, 27 Dec 2024 20:34:09 +0000 (12:34 -0800)
The GNU linker interprets @file as "read command-line options from file".
Thus, we forbid values starting with @ on linker flags. However, this
causes a problem when targeting Darwin. @executable_path, @loader_path, and
@rpath are special values used in Mach-O to change the library search path
and can be used in conjunction with the -install_name and -rpath linker
flags. Since the GNU linker does not support Mach-O, targeting Darwin
implies not using the GNU linker. Therefore, we allow @ in the linker flags
if and only if cfg.Goos == "darwin".

Fixes #40559

Change-Id: I0896758f0835e444ea0d501ea3fd8423cff97a27
GitHub-Last-Rev: 2b81dcd12e7ae0bbb77deccc9973f84a3aa6d750
GitHub-Pull-Request: golang/go#70939
Reviewed-on: https://go-review.googlesource.com/c/go/+/638075
Auto-Submit: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>

src/cmd/go/internal/work/security.go
src/cmd/go/internal/work/security_test.go

index 50bfd0ab70538330ecaf7491f30bb497ff420673..33341a4f4dde0928990c6bdaf615d09126e55e00 100644 (file)
@@ -227,6 +227,21 @@ var validLinkerFlags = []*lazyregexp.Regexp{
        re(`\./.*\.(a|o|obj|dll|dylib|so|tbd)`),
 }
 
+var validLinkerFlagsOnDarwin = []*lazyregexp.Regexp{
+       // The GNU linker interprets `@file` as "read command-line options from
+       // file". Thus, we forbid values starting with `@` on linker flags.
+       // However, this causes a problem when targeting Darwin.
+       // `@executable_path`, `@loader_path`, and `@rpath` are special values
+       // used in Mach-O to change the library search path and can be used in
+       // conjunction with the `-install_name` and `-rpath` linker flags.
+       // Since the GNU linker does not support Mach-O, targeting Darwin
+       // implies not using the GNU linker. Therefore, we allow @ in the linker
+       // flags if and only if cfg.Goos == "darwin" || cfg.Goos == "ios".
+       re(`-Wl,-dylib_install_name,@rpath(/[^,]*)?`),
+       re(`-Wl,-install_name,@rpath(/[^,]*)?`),
+       re(`-Wl,-rpath,@(executable_path|loader_path)(/[^,]*)?`),
+}
+
 var validLinkerFlagsWithNextArg = []string{
        "-arch",
        "-F",
@@ -249,8 +264,13 @@ func checkCompilerFlags(name, source string, list []string) error {
 }
 
 func checkLinkerFlags(name, source string, list []string) error {
+       validLinkerFlagsForPlatform := validLinkerFlags
+       if cfg.Goos == "darwin" || cfg.Goos == "ios" {
+               validLinkerFlagsForPlatform = append(validLinkerFlags, validLinkerFlagsOnDarwin...)
+       }
+
        checkOverrides := true
-       return checkFlags(name, source, list, invalidLinkerFlags, validLinkerFlags, validLinkerFlagsWithNextArg, checkOverrides)
+       return checkFlags(name, source, list, invalidLinkerFlags, validLinkerFlagsForPlatform, validLinkerFlagsWithNextArg, checkOverrides)
 }
 
 // checkCompilerFlagsForInternalLink returns an error if 'list'
index 35af62176472b4e7af90fb4b7b33351eebf6b02f..52e54e25e4a2934c7aa76b1f6750acd6b85f1b09 100644 (file)
@@ -8,6 +8,8 @@ import (
        "os"
        "strings"
        "testing"
+
+       "cmd/go/internal/cfg"
 )
 
 var goodCompilerFlags = [][]string{
@@ -245,6 +247,8 @@ var badLinkerFlags = [][]string{
        {"-Wl,--hash-style=foo"},
        {"-x", "--c"},
        {"-x", "@obj"},
+       {"-Wl,-dylib_install_name,@foo"},
+       {"-Wl,-install_name,@foo"},
        {"-Wl,-rpath,@foo"},
        {"-Wl,-R,foo,bar"},
        {"-Wl,-R,@foo"},
@@ -261,6 +265,21 @@ var badLinkerFlags = [][]string{
        {"./-Wl,--push-state,-R.c"},
 }
 
+var goodLinkerFlagsOnDarwin = [][]string{
+       {"-Wl,-dylib_install_name,@rpath"},
+       {"-Wl,-dylib_install_name,@rpath/"},
+       {"-Wl,-dylib_install_name,@rpath/foo"},
+       {"-Wl,-install_name,@rpath"},
+       {"-Wl,-install_name,@rpath/"},
+       {"-Wl,-install_name,@rpath/foo"},
+       {"-Wl,-rpath,@executable_path"},
+       {"-Wl,-rpath,@executable_path/"},
+       {"-Wl,-rpath,@executable_path/foo"},
+       {"-Wl,-rpath,@loader_path"},
+       {"-Wl,-rpath,@loader_path/"},
+       {"-Wl,-rpath,@loader_path/foo"},
+}
+
 func TestCheckLinkerFlags(t *testing.T) {
        for _, f := range goodLinkerFlags {
                if err := checkLinkerFlags("test", "test", f); err != nil {
@@ -272,6 +291,31 @@ func TestCheckLinkerFlags(t *testing.T) {
                        t.Errorf("missing error for %q", f)
                }
        }
+
+       goos := cfg.Goos
+
+       cfg.Goos = "darwin"
+       for _, f := range goodLinkerFlagsOnDarwin {
+               if err := checkLinkerFlags("test", "test", f); err != nil {
+                       t.Errorf("unexpected error for %q: %v", f, err)
+               }
+       }
+
+       cfg.Goos = "ios"
+       for _, f := range goodLinkerFlagsOnDarwin {
+               if err := checkLinkerFlags("test", "test", f); err != nil {
+                       t.Errorf("unexpected error for %q: %v", f, err)
+               }
+       }
+
+       cfg.Goos = "linux"
+       for _, f := range goodLinkerFlagsOnDarwin {
+               if err := checkLinkerFlags("test", "test", f); err == nil {
+                       t.Errorf("missing error for %q", f)
+               }
+       }
+
+       cfg.Goos = goos
 }
 
 func TestCheckFlagAllowDisallow(t *testing.T) {