Skip to content

Commit 37d5627

Browse files
committed
cmd/go: limit test input file change detection to local GOROOT/GOPATH tree
We've had a series of problems with tests unexpectedly (and innocently) looking at system files that appear to (but don't) change in meaningful ways, like /dev/null on OS X having a modification time set to the current time. Cut all these off by only applying file change detection to the local package root: the GOROOT or specific sub-GOPATH in which the package being tested is found. (This means that if you test reads /tmp/x and you change /tmp/x, the cached result will still be used. Don't do that, or else use -count=1.) Fixes #23390. Change-Id: I30b6dd194835deb645a040aea5e6e4f68af09edb Reviewed-on: https://go-review.googlesource.com/87015 Run-TryBot: Russ Cox <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent c203696 commit 37d5627

File tree

5 files changed

+82
-28
lines changed

5 files changed

+82
-28
lines changed

src/cmd/go/go_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5307,6 +5307,30 @@ func TestTestCacheInputs(t *testing.T) {
53075307
tg.run("test", "testcache", "-run=DirList")
53085308
tg.grepStdout(`\(cached\)`, "did not cache")
53095309

5310+
tg.tempFile("file.txt", "")
5311+
tg.must(ioutil.WriteFile(filepath.Join(tg.pwd(), "testdata/src/testcache/testcachetmp_test.go"), []byte(`package testcache
5312+
5313+
import (
5314+
"os"
5315+
"testing"
5316+
)
5317+
5318+
func TestExternalFile(t *testing.T) {
5319+
os.Open(`+fmt.Sprintf("%q", tg.path("file.txt"))+`)
5320+
_, err := os.Stat(`+fmt.Sprintf("%q", tg.path("file.txt"))+`)
5321+
if err != nil {
5322+
t.Fatal(err)
5323+
}
5324+
}
5325+
`), 0666))
5326+
defer os.Remove(filepath.Join(tg.pwd(), "testdata/src/testcache/testcachetmp_test.go"))
5327+
tg.run("test", "testcache", "-run=ExternalFile")
5328+
tg.run("test", "testcache", "-run=ExternalFile")
5329+
tg.grepStdout(`\(cached\)`, "did not cache")
5330+
tg.must(os.Remove(filepath.Join(tg.tempdir, "file.txt")))
5331+
tg.run("test", "testcache", "-run=ExternalFile")
5332+
tg.grepStdout(`\(cached\)`, "did not cache")
5333+
53105334
switch runtime.GOOS {
53115335
case "nacl", "plan9", "windows":
53125336
// no shell scripts

src/cmd/go/internal/load/path.go

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -56,25 +56,3 @@ func expandPath(p string) string {
5656
}
5757
return p
5858
}
59-
60-
// hasFilePathPrefix reports whether the filesystem path s begins with the
61-
// elements in prefix.
62-
func hasFilePathPrefix(s, prefix string) bool {
63-
sv := strings.ToUpper(filepath.VolumeName(s))
64-
pv := strings.ToUpper(filepath.VolumeName(prefix))
65-
s = s[len(sv):]
66-
prefix = prefix[len(pv):]
67-
switch {
68-
default:
69-
return false
70-
case sv != pv:
71-
return false
72-
case len(s) == len(prefix):
73-
return s == prefix
74-
case len(s) > len(prefix):
75-
if prefix != "" && prefix[len(prefix)-1] == filepath.Separator {
76-
return strings.HasPrefix(s, prefix)
77-
}
78-
return s[len(prefix)] == filepath.Separator && s[:len(prefix)] == prefix
79-
}
80-
}

src/cmd/go/internal/load/pkg.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -520,13 +520,13 @@ func VendoredImportPath(parent *Package, path string) (found string) {
520520

521521
dir := filepath.Clean(parent.Dir)
522522
root := filepath.Join(parent.Root, "src")
523-
if !hasFilePathPrefix(dir, root) || parent.ImportPath != "command-line-arguments" && filepath.Join(root, parent.ImportPath) != dir {
523+
if !str.HasFilePathPrefix(dir, root) || parent.ImportPath != "command-line-arguments" && filepath.Join(root, parent.ImportPath) != dir {
524524
// Look for symlinks before reporting error.
525525
dir = expandPath(dir)
526526
root = expandPath(root)
527527
}
528528

529-
if !hasFilePathPrefix(dir, root) || len(dir) <= len(root) || dir[len(root)] != filepath.Separator || parent.ImportPath != "command-line-arguments" && !parent.Internal.Local && filepath.Join(root, parent.ImportPath) != dir {
529+
if !str.HasFilePathPrefix(dir, root) || len(dir) <= len(root) || dir[len(root)] != filepath.Separator || parent.ImportPath != "command-line-arguments" && !parent.Internal.Local && filepath.Join(root, parent.ImportPath) != dir {
530530
base.Fatalf("unexpected directory layout:\n"+
531531
" import path: %s\n"+
532532
" root: %s\n"+
@@ -670,14 +670,14 @@ func disallowInternal(srcDir string, p *Package, stk *ImportStack) *Package {
670670
i-- // rewind over slash in ".../internal"
671671
}
672672
parent := p.Dir[:i+len(p.Dir)-len(p.ImportPath)]
673-
if hasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
673+
if str.HasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
674674
return p
675675
}
676676

677677
// Look for symlinks before reporting error.
678678
srcDir = expandPath(srcDir)
679679
parent = expandPath(parent)
680-
if hasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
680+
if str.HasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
681681
return p
682682
}
683683

@@ -770,14 +770,14 @@ func disallowVendorVisibility(srcDir string, p *Package, stk *ImportStack) *Pack
770770
return p
771771
}
772772
parent := p.Dir[:truncateTo]
773-
if hasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
773+
if str.HasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
774774
return p
775775
}
776776

777777
// Look for symlinks before reporting error.
778778
srcDir = expandPath(srcDir)
779779
parent = expandPath(parent)
780-
if hasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
780+
if str.HasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
781781
return p
782782
}
783783

src/cmd/go/internal/str/path.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2018 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package str
6+
7+
import (
8+
"path/filepath"
9+
"strings"
10+
)
11+
12+
// HasFilePathPrefix reports whether the filesystem path s begins with the
13+
// elements in prefix.
14+
func HasFilePathPrefix(s, prefix string) bool {
15+
sv := strings.ToUpper(filepath.VolumeName(s))
16+
pv := strings.ToUpper(filepath.VolumeName(prefix))
17+
s = s[len(sv):]
18+
prefix = prefix[len(pv):]
19+
switch {
20+
default:
21+
return false
22+
case sv != pv:
23+
return false
24+
case len(s) == len(prefix):
25+
return s == prefix
26+
case len(s) > len(prefix):
27+
if prefix != "" && prefix[len(prefix)-1] == filepath.Separator {
28+
return strings.HasPrefix(s, prefix)
29+
}
30+
return s[len(prefix)] == filepath.Separator && s[:len(prefix)] == prefix
31+
}
32+
}

src/cmd/go/internal/test/test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1637,11 +1637,19 @@ func computeTestInputsID(a *work.Action, testlog []byte) (cache.ActionID, error)
16371637
if !filepath.IsAbs(name) {
16381638
name = filepath.Join(pwd, name)
16391639
}
1640+
if !inDir(name, a.Package.Root) {
1641+
// Do not recheck files outside the GOPATH or GOROOT root.
1642+
break
1643+
}
16401644
fmt.Fprintf(h, "stat %s %x\n", name, hashStat(name))
16411645
case "open":
16421646
if !filepath.IsAbs(name) {
16431647
name = filepath.Join(pwd, name)
16441648
}
1649+
if !inDir(name, a.Package.Root) {
1650+
// Do not recheck files outside the GOPATH or GOROOT root.
1651+
break
1652+
}
16451653
fh, err := hashOpen(name)
16461654
if err != nil {
16471655
if cache.DebugTest {
@@ -1656,6 +1664,18 @@ func computeTestInputsID(a *work.Action, testlog []byte) (cache.ActionID, error)
16561664
return sum, nil
16571665
}
16581666

1667+
func inDir(path, dir string) bool {
1668+
if str.HasFilePathPrefix(path, dir) {
1669+
return true
1670+
}
1671+
xpath, err1 := filepath.EvalSymlinks(path)
1672+
xdir, err2 := filepath.EvalSymlinks(dir)
1673+
if err1 == nil && err2 == nil && str.HasFilePathPrefix(xpath, xdir) {
1674+
return true
1675+
}
1676+
return false
1677+
}
1678+
16591679
func hashGetenv(name string) cache.ActionID {
16601680
h := cache.NewHash("getenv")
16611681
v, ok := os.LookupEnv(name)

0 commit comments

Comments
 (0)