Skip to content

Commit 027855e

Browse files
committed
os/exec: add GODEBUG setting to opt out of ErrDot changes
The changes are likely to break users, and we need to make it easy to unbreak without code changes. For #43724. Fixes #53962. Change-Id: I105c5d6c801d354467e0cefd268189c18846858e Reviewed-on: https://go-review.googlesource.com/c/go/+/419794 Reviewed-by: Bryan Mills <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Run-TryBot: Russ Cox <[email protected]>
1 parent 462b78f commit 027855e

File tree

6 files changed

+71
-40
lines changed

6 files changed

+71
-40
lines changed

src/go/build/deps_test.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,11 @@ var depsRules = `
177177
178178
os/signal, STR
179179
< path/filepath
180-
< io/ioutil, os/exec;
180+
< io/ioutil;
181+
182+
os < internal/godebug;
183+
184+
path/filepath, internal/godebug < os/exec;
181185
182186
io/ioutil, os/exec, os/signal
183187
< OS;
@@ -187,8 +191,6 @@ var depsRules = `
187191
OS
188192
< golang.org/x/sys/cpu;
189193
190-
os < internal/godebug;
191-
192194
# FMT is OS (which includes string routines) plus reflect and fmt.
193195
# It does not include package log, which should be avoided in core packages.
194196
strconv, unicode

src/os/exec/dot_test.go

Lines changed: 52 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -56,40 +56,58 @@ func TestLookPath(t *testing.T) {
5656

5757
// Add "." to PATH so that exec.LookPath looks in the current directory on all systems.
5858
// And try to trick it with "../testdir" too.
59-
for _, dir := range []string{".", "../testdir"} {
60-
t.Run(pathVar+"="+dir, func(t *testing.T) {
61-
t.Setenv(pathVar, dir+string(filepath.ListSeparator)+origPath)
62-
good := dir + "/execabs-test"
63-
if found, err := LookPath(good); err != nil || !strings.HasPrefix(found, good) {
64-
t.Fatalf(`LookPath(%#q) = %#q, %v, want "%s...", nil`, good, found, err, good)
65-
}
66-
if runtime.GOOS == "windows" {
67-
good = dir + `\execabs-test`
68-
if found, err := LookPath(good); err != nil || !strings.HasPrefix(found, good) {
69-
t.Fatalf(`LookPath(%#q) = %#q, %v, want "%s...", nil`, good, found, err, good)
70-
}
71-
}
72-
73-
if _, err := LookPath("execabs-test"); err == nil {
74-
t.Fatalf("LookPath didn't fail when finding a non-relative path")
75-
} else if !errors.Is(err, ErrDot) {
76-
t.Fatalf("LookPath returned unexpected error: want Is ErrDot, got %q", err)
77-
}
78-
79-
cmd := Command("execabs-test")
80-
if cmd.Err == nil {
81-
t.Fatalf("Command didn't fail when finding a non-relative path")
82-
} else if !errors.Is(cmd.Err, ErrDot) {
83-
t.Fatalf("Command returned unexpected error: want Is ErrDot, got %q", cmd.Err)
84-
}
85-
cmd.Err = nil
86-
87-
// Clearing cmd.Err should let the execution proceed,
88-
// and it should fail because it's not a valid binary.
89-
if err := cmd.Run(); err == nil {
90-
t.Fatalf("Run did not fail: expected exec error")
91-
} else if errors.Is(err, ErrDot) {
92-
t.Fatalf("Run returned unexpected error ErrDot: want error like ENOEXEC: %q", err)
59+
for _, errdot := range []string{"1", "0"} {
60+
t.Run("GODEBUG=execerrdot="+errdot, func(t *testing.T) {
61+
t.Setenv("GODEBUG", "execerrdot="+errdot)
62+
for _, dir := range []string{".", "../testdir"} {
63+
t.Run(pathVar+"="+dir, func(t *testing.T) {
64+
t.Setenv(pathVar, dir+string(filepath.ListSeparator)+origPath)
65+
good := dir + "/execabs-test"
66+
if found, err := LookPath(good); err != nil || !strings.HasPrefix(found, good) {
67+
t.Fatalf(`LookPath(%#q) = %#q, %v, want "%s...", nil`, good, found, err, good)
68+
}
69+
if runtime.GOOS == "windows" {
70+
good = dir + `\execabs-test`
71+
if found, err := LookPath(good); err != nil || !strings.HasPrefix(found, good) {
72+
t.Fatalf(`LookPath(%#q) = %#q, %v, want "%s...", nil`, good, found, err, good)
73+
}
74+
}
75+
76+
_, err := LookPath("execabs-test")
77+
if errdot == "1" {
78+
if err == nil {
79+
t.Fatalf("LookPath didn't fail when finding a non-relative path")
80+
} else if !errors.Is(err, ErrDot) {
81+
t.Fatalf("LookPath returned unexpected error: want Is ErrDot, got %q", err)
82+
}
83+
} else {
84+
if err != nil {
85+
t.Fatalf("LookPath failed unexpectedly: %v", err)
86+
}
87+
}
88+
89+
cmd := Command("execabs-test")
90+
if errdot == "1" {
91+
if cmd.Err == nil {
92+
t.Fatalf("Command didn't fail when finding a non-relative path")
93+
} else if !errors.Is(cmd.Err, ErrDot) {
94+
t.Fatalf("Command returned unexpected error: want Is ErrDot, got %q", cmd.Err)
95+
}
96+
cmd.Err = nil
97+
} else {
98+
if cmd.Err != nil {
99+
t.Fatalf("Command failed unexpectedly: %v", err)
100+
}
101+
}
102+
103+
// Clearing cmd.Err should let the execution proceed,
104+
// and it should fail because it's not a valid binary.
105+
if err := cmd.Run(); err == nil {
106+
t.Fatalf("Run did not fail: expected exec error")
107+
} else if errors.Is(err, ErrDot) {
108+
t.Fatalf("Run returned unexpected error ErrDot: want error like ENOEXEC: %q", err)
109+
}
110+
})
93111
}
94112
})
95113
}

src/os/exec/exec.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@
8080
// log.Fatal(err)
8181
// }
8282
//
83+
// Setting the environment variable GODEBUG=execerrdot=0
84+
// disables generation of ErrDot entirely, temporarily restoring the pre-Go 1.19
85+
// behavior for programs that are unable to apply more targeted fixes.
86+
// A future version of Go may remove support for this variable.
87+
//
8388
// Before adding such overrides, make sure you understand the
8489
// security implications of doing so.
8590
// See https://go.dev/blog/path-security for more information.

src/os/exec/lp_plan9.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package exec
66

77
import (
88
"errors"
9+
"internal/godebug"
910
"io/fs"
1011
"os"
1112
"path/filepath"
@@ -53,7 +54,7 @@ func LookPath(file string) (string, error) {
5354
for _, dir := range filepath.SplitList(path) {
5455
path := filepath.Join(dir, file)
5556
if err := findExecutable(path); err == nil {
56-
if !filepath.IsAbs(path) {
57+
if !filepath.IsAbs(path) && godebug.Get("execerrdot") != "0" {
5758
return path, &Error{file, ErrDot}
5859
}
5960
return path, nil

src/os/exec/lp_unix.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ package exec
88

99
import (
1010
"errors"
11+
"internal/godebug"
1112
"io/fs"
1213
"os"
1314
"path/filepath"
@@ -56,7 +57,7 @@ func LookPath(file string) (string, error) {
5657
}
5758
path := filepath.Join(dir, file)
5859
if err := findExecutable(path); err == nil {
59-
if !filepath.IsAbs(path) {
60+
if !filepath.IsAbs(path) && godebug.Get("execerrdot") != "0" {
6061
return path, &Error{file, ErrDot}
6162
}
6263
return path, nil

src/os/exec/lp_windows.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package exec
66

77
import (
88
"errors"
9+
"internal/godebug"
910
"io/fs"
1011
"os"
1112
"path/filepath"
@@ -102,6 +103,9 @@ func LookPath(file string) (string, error) {
102103
)
103104
if _, found := syscall.Getenv("NoDefaultCurrentDirectoryInExePath"); !found {
104105
if f, err := findExecutable(filepath.Join(".", file), exts); err == nil {
106+
if godebug.Get("execerrdot") == "0" {
107+
return f, nil
108+
}
105109
dotf, dotErr = f, &Error{file, ErrDot}
106110
}
107111
}
@@ -124,7 +128,7 @@ func LookPath(file string) (string, error) {
124128
}
125129
}
126130

127-
if !filepath.IsAbs(f) {
131+
if !filepath.IsAbs(f) && godebug.Get("execerrdot") != "0" {
128132
return f, &Error{file, ErrDot}
129133
}
130134
return f, nil

0 commit comments

Comments
 (0)