From c96833e5badedb025761de6a74ed5f9c848059de Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Wed, 7 Jul 2021 14:58:36 +0000 Subject: [PATCH 01/11] doc: remove stale comment about arm64 port Fixes #47079. Change-Id: I8a671e3fdc13083e44e8d89064a5e7621e53bc4c Reviewed-on: https://go-review.googlesource.com/c/go/+/333075 Trust: Michael Knyszek Reviewed-by: Keith Randall Run-TryBot: Michael Knyszek TryBot-Result: Go Bot --- doc/asm.html | 4 ---- 1 file changed, 4 deletions(-) diff --git a/doc/asm.html b/doc/asm.html index 7173d9bd51..d578800086 100644 --- a/doc/asm.html +++ b/doc/asm.html @@ -827,10 +827,6 @@ The other codes are -> (arithmetic right shift),

ARM64

-

-The ARM64 port is in an experimental state. -

-

R18 is the "platform register", reserved on the Apple platform. To prevent accidental misuse, the register is named R18_PLATFORM. From f264879f74efc8b9a9bcf4e04df0f8f5affa11a9 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Fri, 2 Jul 2021 14:00:49 -0400 Subject: [PATCH 02/11] cmd/go/internal/modload: fix an apparent typo in the AutoRoot comment Updates #40276 Change-Id: Ic192d51f9f0306e5c206c550ef02f6d4495d0851 Reviewed-on: https://go-review.googlesource.com/c/go/+/332569 Trust: Bryan C. Mills Reviewed-by: Jay Conrod --- src/cmd/go/internal/modload/init.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/go/internal/modload/init.go b/src/cmd/go/internal/modload/init.go index cbc7289afa..09136b7de1 100644 --- a/src/cmd/go/internal/modload/init.go +++ b/src/cmd/go/internal/modload/init.go @@ -71,7 +71,7 @@ type Root int const ( // AutoRoot is the default for most commands. modload.Init will look for // a go.mod file in the current directory or any parent. If none is found, - // modules may be disabled (GO111MODULE=on) or commands may run in a + // modules may be disabled (GO111MODULE=auto) or commands may run in a // limited module mode. AutoRoot Root = iota From 00c00558e1513d4f110f0b778242c965e7f6505a Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Fri, 2 Jul 2021 11:27:37 -0400 Subject: [PATCH 03/11] cmd/go/internal/modload: remove unused functions Also unexport functions that are not used outside the modload package. Change-Id: I0de187cbb673cadafce95a27f5ccff934ae21104 Reviewed-on: https://go-review.googlesource.com/c/go/+/332570 Trust: Bryan C. Mills Reviewed-by: Jay Conrod --- src/cmd/go/internal/modload/load.go | 37 ---------------------------- src/cmd/go/internal/modload/query.go | 4 +-- 2 files changed, 2 insertions(+), 39 deletions(-) diff --git a/src/cmd/go/internal/modload/load.go b/src/cmd/go/internal/modload/load.go index a3a8021c04..771b142b73 100644 --- a/src/cmd/go/internal/modload/load.go +++ b/src/cmd/go/internal/modload/load.go @@ -675,20 +675,6 @@ func DirImportPath(ctx context.Context, dir string) string { return "." } -// TargetPackages returns the list of packages in the target (top-level) module -// matching pattern, which may be relative to the working directory, under all -// build tag settings. -func TargetPackages(ctx context.Context, pattern string) *search.Match { - // TargetPackages is relative to the main module, so ensure that the main - // module is a thing that can contain packages. - LoadModFile(ctx) // Sets Target. - ModRoot() // Emits an error if Target cannot contain packages. - - m := search.NewMatch(pattern) - matchPackages(ctx, m, imports.AnyTags(), omitStd, []module.Version{Target}) - return m -} - // ImportMap returns the actual package import path // for an import path found in source code. // If the given import path does not appear in the source code @@ -720,29 +706,6 @@ func PackageModule(path string) module.Version { return pkg.mod } -// PackageImports returns the imports for the package named by the import path. -// Test imports will be returned as well if tests were loaded for the package -// (i.e., if "all" was loaded or if LoadTests was set and the path was matched -// by a command line argument). PackageImports will return nil for -// unknown package paths. -func PackageImports(path string) (imports, testImports []string) { - pkg, ok := loaded.pkgCache.Get(path).(*loadPkg) - if !ok { - return nil, nil - } - imports = make([]string, len(pkg.imports)) - for i, p := range pkg.imports { - imports[i] = p.path - } - if pkg.test != nil { - testImports = make([]string, len(pkg.test.imports)) - for i, p := range pkg.test.imports { - testImports[i] = p.path - } - } - return imports, testImports -} - // Lookup returns the source directory, import path, and any loading error for // the package at path as imported from the package in parentDir. // Lookup requires that one of the Load functions in this package has already diff --git a/src/cmd/go/internal/modload/query.go b/src/cmd/go/internal/modload/query.go index 6f6c6e8c98..dda9004a9f 100644 --- a/src/cmd/go/internal/modload/query.go +++ b/src/cmd/go/internal/modload/query.go @@ -920,8 +920,8 @@ func (e *PackageNotInModuleError) ImportPath() string { return "" } -// ModuleHasRootPackage returns whether module m contains a package m.Path. -func ModuleHasRootPackage(ctx context.Context, m module.Version) (bool, error) { +// moduleHasRootPackage returns whether module m contains a package m.Path. +func moduleHasRootPackage(ctx context.Context, m module.Version) (bool, error) { needSum := false root, isLocal, err := fetch(ctx, m, needSum) if err != nil { From 186a3bb4b0939837c855a4f0689d4a4401aff608 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Fri, 25 Jun 2021 12:49:51 -0400 Subject: [PATCH 04/11] cmd/go/internal/modfetch/codehost: skip hg tests if no hg binary is present Change-Id: I5cf57bf1153eb662bcab71e3d2c04848212559a6 Reviewed-on: https://go-review.googlesource.com/c/go/+/330989 Trust: Bryan C. Mills Run-TryBot: Bryan C. Mills TryBot-Result: Go Bot Reviewed-by: Jay Conrod --- .../go/internal/modfetch/codehost/git_test.go | 49 +++++++++---------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/src/cmd/go/internal/modfetch/codehost/git_test.go b/src/cmd/go/internal/modfetch/codehost/git_test.go index 89a73baad9..a684fa1a9b 100644 --- a/src/cmd/go/internal/modfetch/codehost/git_test.go +++ b/src/cmd/go/internal/modfetch/codehost/git_test.go @@ -8,7 +8,6 @@ import ( "archive/zip" "bytes" "flag" - "fmt" "internal/testenv" "io" "io/fs" @@ -47,12 +46,6 @@ var altRepos = []string{ var localGitRepo string func testMain(m *testing.M) int { - if _, err := exec.LookPath("git"); err != nil { - fmt.Fprintln(os.Stderr, "skipping because git binary not found") - fmt.Println("PASS") - return 0 - } - dir, err := os.MkdirTemp("", "gitrepo-test-") if err != nil { log.Fatal(err) @@ -60,23 +53,25 @@ func testMain(m *testing.M) int { defer os.RemoveAll(dir) if testenv.HasExternalNetwork() && testenv.HasExec() { - // Clone gitrepo1 into a local directory. - // If we use a file:// URL to access the local directory, - // then git starts up all the usual protocol machinery, - // which will let us test remote git archive invocations. - localGitRepo = filepath.Join(dir, "gitrepo2") - if _, err := Run("", "git", "clone", "--mirror", gitrepo1, localGitRepo); err != nil { - log.Fatal(err) - } - if _, err := Run(localGitRepo, "git", "config", "daemon.uploadarch", "true"); err != nil { - log.Fatal(err) + if _, err := exec.LookPath("git"); err == nil { + // Clone gitrepo1 into a local directory. + // If we use a file:// URL to access the local directory, + // then git starts up all the usual protocol machinery, + // which will let us test remote git archive invocations. + localGitRepo = filepath.Join(dir, "gitrepo2") + if _, err := Run("", "git", "clone", "--mirror", gitrepo1, localGitRepo); err != nil { + log.Fatal(err) + } + if _, err := Run(localGitRepo, "git", "config", "daemon.uploadarch", "true"); err != nil { + log.Fatal(err) + } } } return m.Run() } -func testRepo(remote string) (Repo, error) { +func testRepo(t *testing.T, remote string) (Repo, error) { if remote == "localGitRepo" { // Convert absolute path to file URL. LocalGitRepo will not accept // Windows absolute paths because they look like a host:path remote. @@ -87,15 +82,17 @@ func testRepo(remote string) (Repo, error) { } else { url = "file:///" + filepath.ToSlash(localGitRepo) } + testenv.MustHaveExecPath(t, "git") return LocalGitRepo(url) } - kind := "git" + vcs := "git" for _, k := range []string{"hg"} { if strings.Contains(remote, "/"+k+"/") { - kind = k + vcs = k } } - return NewRepo(kind, remote) + testenv.MustHaveExecPath(t, vcs) + return NewRepo(vcs, remote) } var tagsTests = []struct { @@ -116,7 +113,7 @@ func TestTags(t *testing.T) { for _, tt := range tagsTests { f := func(t *testing.T) { - r, err := testRepo(tt.repo) + r, err := testRepo(t, tt.repo) if err != nil { t.Fatal(err) } @@ -168,7 +165,7 @@ func TestLatest(t *testing.T) { for _, tt := range latestTests { f := func(t *testing.T) { - r, err := testRepo(tt.repo) + r, err := testRepo(t, tt.repo) if err != nil { t.Fatal(err) } @@ -221,7 +218,7 @@ func TestReadFile(t *testing.T) { for _, tt := range readFileTests { f := func(t *testing.T) { - r, err := testRepo(tt.repo) + r, err := testRepo(t, tt.repo) if err != nil { t.Fatal(err) } @@ -412,7 +409,7 @@ func TestReadZip(t *testing.T) { for _, tt := range readZipTests { f := func(t *testing.T) { - r, err := testRepo(tt.repo) + r, err := testRepo(t, tt.repo) if err != nil { t.Fatal(err) } @@ -581,7 +578,7 @@ func TestStat(t *testing.T) { for _, tt := range statTests { f := func(t *testing.T) { - r, err := testRepo(tt.repo) + r, err := testRepo(t, tt.repo) if err != nil { t.Fatal(err) } From 991fd381d52e7cec37ab54732613d3e465916206 Mon Sep 17 00:00:00 2001 From: Jay Conrod Date: Tue, 6 Jul 2021 10:38:18 -0700 Subject: [PATCH 05/11] cmd/go: don't lock .mod and .sum files for read in overlay On Plan 9, locking a file requires a chmod call. In general, the go command should not modify files in the overlay, even metadata. With this change, we won't lock these files for reading. The go command already reported errors when attempting to write these files if they were in the overlay, but this change moves those checks to the point of access for clearer error messages. cmd/go/internal/lockedfile no longer imports cmd/go/internal/fsys. Fixes #44700 Change-Id: Ib544459dd6cf56ca0f7a27b3285f045f08040d7e Reviewed-on: https://go-review.googlesource.com/c/go/+/333012 Trust: Jay Conrod Run-TryBot: Jay Conrod TryBot-Result: Go Bot Reviewed-by: Bryan C. Mills --- .../internal/lockedfile/lockedfile_filelock.go | 3 +-- .../go/internal/lockedfile/lockedfile_plan9.go | 6 ++---- src/cmd/go/internal/modfetch/fetch.go | 17 ++++++++++++++++- src/cmd/go/internal/modload/init.go | 18 +++++++++++++++++- src/cmd/go/internal/modload/modfile.go | 14 ++++++++++++-- src/cmd/go/testdata/script/mod_overlay.txt | 10 +++++----- 6 files changed, 53 insertions(+), 15 deletions(-) diff --git a/src/cmd/go/internal/lockedfile/lockedfile_filelock.go b/src/cmd/go/internal/lockedfile/lockedfile_filelock.go index 729df5c681..e4923f6876 100644 --- a/src/cmd/go/internal/lockedfile/lockedfile_filelock.go +++ b/src/cmd/go/internal/lockedfile/lockedfile_filelock.go @@ -11,7 +11,6 @@ import ( "io/fs" "os" - "cmd/go/internal/fsys" "cmd/go/internal/lockedfile/internal/filelock" ) @@ -21,7 +20,7 @@ func openFile(name string, flag int, perm fs.FileMode) (*os.File, error) { // calls for Linux and Windows anyway, so it's simpler to use that approach // consistently. - f, err := fsys.OpenFile(name, flag&^os.O_TRUNC, perm) + f, err := os.OpenFile(name, flag&^os.O_TRUNC, perm) if err != nil { return nil, err } diff --git a/src/cmd/go/internal/lockedfile/lockedfile_plan9.go b/src/cmd/go/internal/lockedfile/lockedfile_plan9.go index 3d4b97d78e..979118b10a 100644 --- a/src/cmd/go/internal/lockedfile/lockedfile_plan9.go +++ b/src/cmd/go/internal/lockedfile/lockedfile_plan9.go @@ -13,8 +13,6 @@ import ( "os" "strings" "time" - - "cmd/go/internal/fsys" ) // Opening an exclusive-use file returns an error. @@ -59,7 +57,7 @@ func openFile(name string, flag int, perm fs.FileMode) (*os.File, error) { // If the file was unpacked or created by some other program, it might not // have the ModeExclusive bit set. Set it before we call OpenFile, so that we // can be confident that a successful OpenFile implies exclusive use. - if fi, err := fsys.Stat(name); err == nil { + if fi, err := os.Stat(name); err == nil { if fi.Mode()&fs.ModeExclusive == 0 { if err := os.Chmod(name, fi.Mode()|fs.ModeExclusive); err != nil { return nil, err @@ -72,7 +70,7 @@ func openFile(name string, flag int, perm fs.FileMode) (*os.File, error) { nextSleep := 1 * time.Millisecond const maxSleep = 500 * time.Millisecond for { - f, err := fsys.OpenFile(name, flag, perm|fs.ModeExclusive) + f, err := os.OpenFile(name, flag, perm|fs.ModeExclusive) if err == nil { return f, nil } diff --git a/src/cmd/go/internal/modfetch/fetch.go b/src/cmd/go/internal/modfetch/fetch.go index e40593abae..d3d30d970b 100644 --- a/src/cmd/go/internal/modfetch/fetch.go +++ b/src/cmd/go/internal/modfetch/fetch.go @@ -22,6 +22,7 @@ import ( "cmd/go/internal/base" "cmd/go/internal/cfg" + "cmd/go/internal/fsys" "cmd/go/internal/lockedfile" "cmd/go/internal/par" "cmd/go/internal/robustio" @@ -416,7 +417,18 @@ func initGoSum() (bool, error) { goSum.m = make(map[module.Version][]string) goSum.status = make(map[modSum]modSumStatus) - data, err := lockedfile.Read(GoSumFile) + var ( + data []byte + err error + ) + if actualSumFile, ok := fsys.OverlayPath(GoSumFile); ok { + // Don't lock go.sum if it's part of the overlay. + // On Plan 9, locking requires chmod, and we don't want to modify any file + // in the overlay. See #44700. + data, err = os.ReadFile(actualSumFile) + } else { + data, err = lockedfile.Read(GoSumFile) + } if err != nil && !os.IsNotExist(err) { return false, err } @@ -716,6 +728,9 @@ Outer: if cfg.BuildMod == "readonly" { base.Fatalf("go: updates to go.sum needed, disabled by -mod=readonly") } + if _, ok := fsys.OverlayPath(GoSumFile); ok { + base.Fatalf("go: updates to go.sum needed, but go.sum is part of the overlay specified with -overlay") + } // Make a best-effort attempt to acquire the side lock, only to exclude // previous versions of the 'go' command from making simultaneous edits. diff --git a/src/cmd/go/internal/modload/init.go b/src/cmd/go/internal/modload/init.go index 09136b7de1..a8cbd9fe16 100644 --- a/src/cmd/go/internal/modload/init.go +++ b/src/cmd/go/internal/modload/init.go @@ -412,7 +412,16 @@ func loadModFile(ctx context.Context) (rs *Requirements, needCommit bool) { } gomod := ModFilePath() - data, err := lockedfile.Read(gomod) + var data []byte + var err error + if gomodActual, ok := fsys.OverlayPath(gomod); ok { + // Don't lock go.mod if it's part of the overlay. + // On Plan 9, locking requires chmod, and we don't want to modify any file + // in the overlay. See #44700. + data, err = os.ReadFile(gomodActual) + } else { + data, err = lockedfile.Read(gomodActual) + } if err != nil { base.Fatalf("go: %v", err) } @@ -1026,6 +1035,13 @@ func commitRequirements(ctx context.Context, goVersion string, rs *Requirements) } return } + gomod := ModFilePath() + if _, ok := fsys.OverlayPath(gomod); ok { + if dirty { + base.Fatalf("go: updates to go.mod needed, but go.mod is part of the overlay specified with -overlay") + } + return + } new, err := modFile.Format() if err != nil { diff --git a/src/cmd/go/internal/modload/modfile.go b/src/cmd/go/internal/modload/modfile.go index 1145ac4ba5..d280945ea6 100644 --- a/src/cmd/go/internal/modload/modfile.go +++ b/src/cmd/go/internal/modload/modfile.go @@ -8,6 +8,7 @@ import ( "context" "errors" "fmt" + "os" "path/filepath" "strings" "sync" @@ -15,6 +16,7 @@ import ( "cmd/go/internal/base" "cmd/go/internal/cfg" + "cmd/go/internal/fsys" "cmd/go/internal/lockedfile" "cmd/go/internal/modfetch" "cmd/go/internal/par" @@ -601,8 +603,16 @@ func rawGoModSummary(m module.Version) (*modFileSummary, error) { dir = filepath.Join(ModRoot(), dir) } gomod := filepath.Join(dir, "go.mod") - - data, err := lockedfile.Read(gomod) + var data []byte + var err error + if gomodActual, ok := fsys.OverlayPath(gomod); ok { + // Don't lock go.mod if it's part of the overlay. + // On Plan 9, locking requires chmod, and we don't want to modify any file + // in the overlay. See #44700. + data, err = os.ReadFile(gomodActual) + } else { + data, err = lockedfile.Read(gomodActual) + } if err != nil { return cached{nil, module.VersionError(m, fmt.Errorf("reading %s: %v", base.ShortPath(gomod), err))} } diff --git a/src/cmd/go/testdata/script/mod_overlay.txt b/src/cmd/go/testdata/script/mod_overlay.txt index 92e79c725a..86ab04bd3c 100644 --- a/src/cmd/go/testdata/script/mod_overlay.txt +++ b/src/cmd/go/testdata/script/mod_overlay.txt @@ -21,7 +21,7 @@ go list -deps -overlay overlay.json . cd $WORK/gopath/src/get-doesnt-add-dep cp $WORK/overlay/get_doesnt_add_dep_go_mod $WORK/want_go_mod ! go get -d -overlay overlay.json . -stderr 'overlaid files can''t be opened for write' +stderr '^go: updates to go.mod needed, but go.mod is part of the overlay specified with -overlay$' cmp $WORK/overlay/get_doesnt_add_dep_go_mod $WORK/want_go_mod # Content of overlaid go.sum is used. @@ -41,10 +41,10 @@ go mod verify -overlay overlay.json # attempting to update the file cp incomplete-sum-file $WORK/overlay/overlay-sum-used-correct-sums ! go get -d -overlay overlay.json . -stderr 'overlaid files can''t be opened for write' +stderr '^go: updates to go.sum needed, but go.sum is part of the overlay specified with -overlay$' cmp incomplete-sum-file $WORK/overlay/overlay-sum-used-correct-sums ! go mod tidy -overlay overlay.json -stderr 'overlaid files can''t be opened for write' +stderr '^go: updates to go.sum needed, but go.sum is part of the overlay specified with -overlay$' cmp incomplete-sum-file $WORK/overlay/overlay-sum-used-correct-sums # -overlay works with -modfile. @@ -56,7 +56,7 @@ go list -modfile=alternate.mod -overlay overlay.json . stdout 'found.the/module' # Even with -modfile, overlaid files can't be opened for write. ! go get -modfile=alternate.mod -overlay overlay.json -d rsc.io/quote -stderr 'overlaid files can''t be opened for write' +stderr '^go: updates to go.mod needed, but go.mod is part of the overlay specified with -overlay$' # Carving out a module by adding an overlaid go.mod file cd $WORK/gopath/src/carve @@ -78,7 +78,7 @@ go list -overlay overlay.json all stdout ^carve2/nomod$ # Editing go.mod file fails because overlay is read only ! go get -overlay overlay.json -d rsc.io/quote -stderr 'overlaid files can''t be opened for write' +stderr '^go: updates to go.mod needed, but go.mod is part of the overlay specified with -overlay$' ! grep rsc.io/quote $WORK/overlay/carve2-nomod-go.mod # Editing go.mod file succeeds because we use -modfile to redirect to same file go get -overlay overlay.json -modfile $WORK/overlay/carve2-nomod-go.mod -d rsc.io/quote From 11f5df2d6703b3fbd61a256e4e32ba67d835e7ad Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Wed, 7 Jul 2021 12:11:37 -0700 Subject: [PATCH 06/11] cmd/compile: extract pkgqual from symfmt The logic in symfmt for deciding how to package-qualify an identifier is easily refactored into a separate function, loosely similar to go/types.Qualifier's API. Passes toolstash -cmp. Updates #47087. Change-Id: Ib3e7cc35a6577dc28df8eca79ba3457c48168e86 Reviewed-on: https://go-review.googlesource.com/c/go/+/333161 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/types/fmt.go | 43 +++++++++++++-------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/src/cmd/compile/internal/types/fmt.go b/src/cmd/compile/internal/types/fmt.go index b538ea8054..0ce423dae7 100644 --- a/src/cmd/compile/internal/types/fmt.go +++ b/src/cmd/compile/internal/types/fmt.go @@ -137,47 +137,44 @@ func sconv2(b *bytes.Buffer, s *Sym, verb rune, mode fmtMode) { } func symfmt(b *bytes.Buffer, s *Sym, verb rune, mode fmtMode) { + if q := pkgqual(s.Pkg, verb, mode); q != "" { + b.WriteString(q) + b.WriteByte('.') + } + b.WriteString(s.Name) +} + +// pkgqual returns the qualifier that should be used for printing +// symbols from the given package in the given mode. +// If it returns the empty string, no qualification is needed. +func pkgqual(pkg *Pkg, verb rune, mode fmtMode) string { if verb != 'S' { switch mode { case fmtGo: // This is for the user - if s.Pkg == BuiltinPkg || s.Pkg == LocalPkg { - b.WriteString(s.Name) - return + if pkg == BuiltinPkg || pkg == LocalPkg { + return "" } // If the name was used by multiple packages, display the full path, - if s.Pkg.Name != "" && NumImport[s.Pkg.Name] > 1 { - fmt.Fprintf(b, "%q.%s", s.Pkg.Path, s.Name) - return + if pkg.Name != "" && NumImport[pkg.Name] > 1 { + return strconv.Quote(pkg.Path) } - b.WriteString(s.Pkg.Name) - b.WriteByte('.') - b.WriteString(s.Name) - return + return pkg.Name case fmtDebug: - b.WriteString(s.Pkg.Name) - b.WriteByte('.') - b.WriteString(s.Name) - return + return pkg.Name case fmtTypeIDName: // dcommontype, typehash - b.WriteString(s.Pkg.Name) - b.WriteByte('.') - b.WriteString(s.Name) - return + return pkg.Name case fmtTypeID: // (methodsym), typesym, weaksym - b.WriteString(s.Pkg.Prefix) - b.WriteByte('.') - b.WriteString(s.Name) - return + return pkg.Prefix } } - b.WriteString(s.Name) + return "" } // Type From b003a8b1ae26fa684ec35eb7543efa1ded1bcae7 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Wed, 7 Jul 2021 12:33:40 -0700 Subject: [PATCH 07/11] cmd/compile: optimize types.sconv Now that symfmt is simpler, we can simply manually inline it into sconv. Importantly, this allows us to avoid allocating a buffer + writing a string + re-interning it when we don't need to qualify the identifier. Passes toolstash -cmp. Updates #47087. Change-Id: I47b57aef22301ba242556a645346f478f0c1a7d1 Reviewed-on: https://go-review.googlesource.com/c/go/+/333162 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/types/fmt.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/types/fmt.go b/src/cmd/compile/internal/types/fmt.go index 0ce423dae7..7b284aa661 100644 --- a/src/cmd/compile/internal/types/fmt.go +++ b/src/cmd/compile/internal/types/fmt.go @@ -112,11 +112,19 @@ func sconv(s *Sym, verb rune, mode fmtMode) string { if s.Name == "_" { return "_" } + + q := pkgqual(s.Pkg, verb, mode) + if q == "" { + return s.Name + } + buf := fmtBufferPool.Get().(*bytes.Buffer) buf.Reset() defer fmtBufferPool.Put(buf) - symfmt(buf, s, verb, mode) + buf.WriteString(q) + buf.WriteByte('.') + buf.WriteString(s.Name) return InternString(buf.Bytes()) } From 5c59e11f5e1fe2e6d5b684f9a348022c07807126 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Wed, 7 Jul 2021 13:18:42 -0700 Subject: [PATCH 08/11] cmd/compile: remove special-casing of blank in types.sconv{,2} I'm not sure why blank was special-cased here before, but it's wrong. Blank is a non-exported identifier, and writing it out without package-qualification can result in linker symbol collisions. Fixes #47087. Change-Id: Ie600037c8e54e3d4fdaeec21e2ca212badbd830b Reviewed-on: https://go-review.googlesource.com/c/go/+/333163 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/types/fmt.go | 8 -------- test/fixedbugs/issue47087.dir/a.go | 9 +++++++++ test/fixedbugs/issue47087.dir/b.go | 9 +++++++++ test/fixedbugs/issue47087.dir/main.go | 19 +++++++++++++++++++ test/fixedbugs/issue47087.go | 7 +++++++ 5 files changed, 44 insertions(+), 8 deletions(-) create mode 100644 test/fixedbugs/issue47087.dir/a.go create mode 100644 test/fixedbugs/issue47087.dir/b.go create mode 100644 test/fixedbugs/issue47087.dir/main.go create mode 100644 test/fixedbugs/issue47087.go diff --git a/src/cmd/compile/internal/types/fmt.go b/src/cmd/compile/internal/types/fmt.go index 7b284aa661..8b988952a7 100644 --- a/src/cmd/compile/internal/types/fmt.go +++ b/src/cmd/compile/internal/types/fmt.go @@ -109,10 +109,6 @@ func sconv(s *Sym, verb rune, mode fmtMode) string { return "" } - if s.Name == "_" { - return "_" - } - q := pkgqual(s.Pkg, verb, mode) if q == "" { return s.Name @@ -136,10 +132,6 @@ func sconv2(b *bytes.Buffer, s *Sym, verb rune, mode fmtMode) { b.WriteString("") return } - if s.Name == "_" { - b.WriteString("_") - return - } symfmt(b, s, verb, mode) } diff --git a/test/fixedbugs/issue47087.dir/a.go b/test/fixedbugs/issue47087.dir/a.go new file mode 100644 index 0000000000..6093092ace --- /dev/null +++ b/test/fixedbugs/issue47087.dir/a.go @@ -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 a + +func F() interface{} { return struct{ _ []int }{} } + +var X = F() diff --git a/test/fixedbugs/issue47087.dir/b.go b/test/fixedbugs/issue47087.dir/b.go new file mode 100644 index 0000000000..8f96d25a12 --- /dev/null +++ b/test/fixedbugs/issue47087.dir/b.go @@ -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 b + +func F() interface{} { return struct{ _ []int }{} } + +var X = F() diff --git a/test/fixedbugs/issue47087.dir/main.go b/test/fixedbugs/issue47087.dir/main.go new file mode 100644 index 0000000000..ccd0891a61 --- /dev/null +++ b/test/fixedbugs/issue47087.dir/main.go @@ -0,0 +1,19 @@ +// 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 ( + "a" + "b" +) + +func main() { + if a.F() == b.F() { + panic("FAIL") + } + if a.X == b.X { + panic("FAIL") + } +} diff --git a/test/fixedbugs/issue47087.go b/test/fixedbugs/issue47087.go new file mode 100644 index 0000000000..40df49f83b --- /dev/null +++ b/test/fixedbugs/issue47087.go @@ -0,0 +1,7 @@ +// rundir + +// 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 ignored From 2ca44fe2213b53ccaf6f555c11858c6e36490624 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Mon, 5 Jul 2021 10:35:53 +0200 Subject: [PATCH 09/11] doc/go1.17: linkify time.UnixMilli and time.UnixMicro Change-Id: I8503c4649fc42670f13d981f98af480467d6a3e8 Reviewed-on: https://go-review.googlesource.com/c/go/+/332829 Trust: Tobias Klauser Reviewed-by: Dmitri Shuralyov --- doc/go1.17.html | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/doc/go1.17.html b/doc/go1.17.html index 66b4f48b61..4fa30158bb 100644 --- a/doc/go1.17.html +++ b/doc/go1.17.html @@ -1132,10 +1132,13 @@ func Foo() bool {

The new Time.UnixMilli and - Time.UnixMicro methods return the number of milliseconds and - microseconds elapsed since January 1, 1970 UTC respectively.
- The new UnixMilli and UnixMicro functions return local Time corresponding to given - Unix time. + Time.UnixMicro + methods return the number of milliseconds and microseconds elapsed since + January 1, 1970 UTC respectively. +
+ The new UnixMilli and + UnixMicro functions + return the local Time corresponding to the given Unix time.

From ce76298ee7b2cc237b015f798abbfe891a6f5463 Mon Sep 17 00:00:00 2001 From: makdon Date: Mon, 17 May 2021 16:27:11 +0000 Subject: [PATCH 10/11] Update oudated comment Update comment cause gc/select.go has been moved to walk/select.go and gc/reflect.go has been moved to reflectdata/reflect.go Change-Id: I6894527e1e9dbca50ace92a51bf942f9495ce88c GitHub-Last-Rev: 6d6a4471440403218b68ba32d4038ca41eae2901 GitHub-Pull-Request: golang/go#45976 Reviewed-on: https://go-review.googlesource.com/c/go/+/317191 Reviewed-by: Keith Randall Trust: Michael Pratt --- src/cmd/compile/internal/reflectdata/reflect.go | 2 +- src/cmd/link/internal/ld/decodesym.go | 4 ++-- src/internal/reflectlite/type.go | 4 ++-- src/reflect/type.go | 10 +++++----- src/runtime/runtime2.go | 4 ++-- src/runtime/select.go | 2 +- src/runtime/type.go | 6 +++--- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go index e07294be0f..eb9a8a6c9b 100644 --- a/src/cmd/compile/internal/reflectdata/reflect.go +++ b/src/cmd/compile/internal/reflectdata/reflect.go @@ -669,7 +669,7 @@ var kinds = []int{ // tflag is documented in reflect/type.go. // // tflag values must be kept in sync with copies in: -// cmd/compile/internal/gc/reflect.go +// cmd/compile/internal/reflectdata/reflect.go // cmd/link/internal/ld/decodesym.go // reflect/type.go // runtime/type.go diff --git a/src/cmd/link/internal/ld/decodesym.go b/src/cmd/link/internal/ld/decodesym.go index c41d97706e..629bdcf4ca 100644 --- a/src/cmd/link/internal/ld/decodesym.go +++ b/src/cmd/link/internal/ld/decodesym.go @@ -16,12 +16,12 @@ import ( // Decoding the type.* symbols. This has to be in sync with // ../../runtime/type.go, or more specifically, with what -// cmd/compile/internal/gc/reflect.go stuffs in these. +// cmd/compile/internal/reflectdata/reflect.go stuffs in these. // tflag is documented in reflect/type.go. // // tflag values must be kept in sync with copies in: -// cmd/compile/internal/gc/reflect.go +// cmd/compile/internal/reflectdata/reflect.go // cmd/link/internal/ld/decodesym.go // reflect/type.go // runtime/type.go diff --git a/src/internal/reflectlite/type.go b/src/internal/reflectlite/type.go index f529f7c5fc..b1899b0191 100644 --- a/src/internal/reflectlite/type.go +++ b/src/internal/reflectlite/type.go @@ -68,7 +68,7 @@ type Type interface { } /* - * These data structures are known to the compiler (../../cmd/internal/gc/reflect.go). + * These data structures are known to the compiler (../../cmd/internal/reflectdata/reflect.go). * A few are known to ../runtime/type.go to convey to debuggers. * They are also known to ../runtime/type.go. */ @@ -111,7 +111,7 @@ const ( // available in the memory directly following the rtype value. // // tflag values must be kept in sync with copies in: -// cmd/compile/internal/gc/reflect.go +// cmd/compile/internal/reflectdata/reflect.go // cmd/link/internal/ld/decodesym.go // runtime/type.go type tflag uint8 diff --git a/src/reflect/type.go b/src/reflect/type.go index df863ae106..f672a7a5d5 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -228,7 +228,7 @@ type Type interface { // See https://golang.org/issue/4876 for more details. /* - * These data structures are known to the compiler (../../cmd/internal/gc/reflect.go). + * These data structures are known to the compiler (../../cmd/internal/reflectdata/reflect.go). * A few are known to ../runtime/type.go to convey to debuggers. * They are also known to ../runtime/type.go. */ @@ -271,7 +271,7 @@ const ( // available in the memory directly following the rtype value. // // tflag values must be kept in sync with copies in: -// cmd/compile/internal/gc/reflect.go +// cmd/compile/internal/reflectdata/reflect.go // cmd/link/internal/ld/decodesym.go // runtime/type.go type tflag uint8 @@ -1910,7 +1910,7 @@ func MapOf(key, elem Type) Type { // Make a map type. // Note: flag values must match those used in the TMAP case - // in ../cmd/compile/internal/gc/reflect.go:writeType. + // in ../cmd/compile/internal/reflectdata/reflect.go:writeType. var imap interface{} = (map[unsafe.Pointer]unsafe.Pointer)(nil) mt := **(**mapType)(unsafe.Pointer(&imap)) mt.str = resolveReflectName(newName(s, "", false)) @@ -2841,7 +2841,7 @@ func runtimeStructField(field StructField) (structField, string) { // typeptrdata returns the length in bytes of the prefix of t // containing pointer data. Anything after this offset is scalar data. -// keep in sync with ../cmd/compile/internal/gc/reflect.go +// keep in sync with ../cmd/compile/internal/reflectdata/reflect.go func typeptrdata(t *rtype) uintptr { switch t.Kind() { case Struct: @@ -2865,7 +2865,7 @@ func typeptrdata(t *rtype) uintptr { } } -// See cmd/compile/internal/gc/reflect.go for derivation of constant. +// See cmd/compile/internal/reflectdata/reflect.go for derivation of constant. const maxPtrmaskBytes = 2048 // ArrayOf returns the array type with the given length and element type. diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go index 0e0eb0b728..2a66826f34 100644 --- a/src/runtime/runtime2.go +++ b/src/runtime/runtime2.go @@ -895,7 +895,7 @@ type funcinl struct { // layout of Itab known to compilers // allocated in non-garbage-collected memory // Needs to be in sync with -// ../cmd/compile/internal/gc/reflect.go:/^func.WriteTabs. +// ../cmd/compile/internal/reflectdata/reflect.go:/^func.WriteTabs. type itab struct { inter *interfacetype _type *_type @@ -940,7 +940,7 @@ func extendRandom(r []byte, n int) { // A _defer holds an entry on the list of deferred calls. // If you add a field here, add code to clear it in freedefer and deferProcStack -// This struct must match the code in cmd/compile/internal/gc/reflect.go:deferstruct +// This struct must match the code in cmd/compile/internal/reflectdata/reflect.go:deferstruct // and cmd/compile/internal/gc/ssa.go:(*state).call. // Some defers will be allocated on the stack and some on the heap. // All defers are logically part of the stack, so write barriers to diff --git a/src/runtime/select.go b/src/runtime/select.go index e72761bfa9..06edb69f42 100644 --- a/src/runtime/select.go +++ b/src/runtime/select.go @@ -15,7 +15,7 @@ const debugSelect = false // Select case descriptor. // Known to compiler. -// Changes here must also be made in src/cmd/internal/gc/select.go's scasetype. +// Changes here must also be made in src/cmd/compile/internal/walk/select.go's scasetype. type scase struct { c *hchan // chan elem unsafe.Pointer // data element diff --git a/src/runtime/type.go b/src/runtime/type.go index 335fc57f4b..4039273695 100644 --- a/src/runtime/type.go +++ b/src/runtime/type.go @@ -11,7 +11,7 @@ import "unsafe" // tflag is documented in reflect/type.go. // // tflag values must be kept in sync with copies in: -// cmd/compile/internal/gc/reflect.go +// cmd/compile/internal/reflectdata/reflect.go // cmd/link/internal/ld/decodesym.go // reflect/type.go // internal/reflectlite/type.go @@ -25,7 +25,7 @@ const ( ) // Needs to be in sync with ../cmd/link/internal/ld/decodesym.go:/^func.commonsize, -// ../cmd/compile/internal/gc/reflect.go:/^func.dcommontype and +// ../cmd/compile/internal/reflectdata/reflect.go:/^func.dcommontype and // ../reflect/type.go:/^type.rtype. // ../internal/reflectlite/type.go:/^type.rtype. type _type struct { @@ -383,7 +383,7 @@ type maptype struct { } // Note: flag values must match those used in the TMAP case -// in ../cmd/compile/internal/gc/reflect.go:writeType. +// in ../cmd/compile/internal/reflectdata/reflect.go:writeType. func (mt *maptype) indirectkey() bool { // store ptr to key instead of key itself return mt.flags&1 != 0 } From 296ddf2a936a30866303a64d49bc0e3e034730a8 Mon Sep 17 00:00:00 2001 From: Roland Shoemaker Date: Fri, 2 Jul 2021 10:25:49 -0700 Subject: [PATCH 11/11] net: filter bad names from Lookup functions instead of hard failing Instead of hard failing on a single bad record, filter the bad records and return anything valid. This only applies to the methods which can return multiple records, LookupMX, LookupNS, LookupSRV, and LookupAddr. When bad results are filtered out, also return an error, indicating that this filtering has happened. Updates #46241 Fixes #46979 Change-Id: I6493e0002beaf89f5a9795333a93605abd30d171 Reviewed-on: https://go-review.googlesource.com/c/go/+/332549 Trust: Roland Shoemaker Reviewed-by: Filippo Valsorda --- src/net/dnsclient_unix_test.go | 222 +++++++++++++++++++++++++-------- src/net/lookup.go | 74 ++++++++--- 2 files changed, 229 insertions(+), 67 deletions(-) diff --git a/src/net/dnsclient_unix_test.go b/src/net/dnsclient_unix_test.go index 59cdd2bf3e..350ad5def7 100644 --- a/src/net/dnsclient_unix_test.go +++ b/src/net/dnsclient_unix_test.go @@ -1846,6 +1846,17 @@ func TestCVE202133195(t *testing.T) { Target: dnsmessage.MustNewName(".golang.org."), }, }, + dnsmessage.Resource{ + Header: dnsmessage.ResourceHeader{ + Name: n, + Type: dnsmessage.TypeSRV, + Class: dnsmessage.ClassINET, + Length: 4, + }, + Body: &dnsmessage.SRVResource{ + Target: dnsmessage.MustNewName("good.golang.org."), + }, + }, ) case dnsmessage.TypeMX: r.Answers = append(r.Answers, @@ -1860,6 +1871,17 @@ func TestCVE202133195(t *testing.T) { MX: dnsmessage.MustNewName(".golang.org."), }, }, + dnsmessage.Resource{ + Header: dnsmessage.ResourceHeader{ + Name: dnsmessage.MustNewName("good.golang.org."), + Type: dnsmessage.TypeMX, + Class: dnsmessage.ClassINET, + Length: 4, + }, + Body: &dnsmessage.MXResource{ + MX: dnsmessage.MustNewName("good.golang.org."), + }, + }, ) case dnsmessage.TypeNS: r.Answers = append(r.Answers, @@ -1874,6 +1896,17 @@ func TestCVE202133195(t *testing.T) { NS: dnsmessage.MustNewName(".golang.org."), }, }, + dnsmessage.Resource{ + Header: dnsmessage.ResourceHeader{ + Name: dnsmessage.MustNewName("good.golang.org."), + Type: dnsmessage.TypeNS, + Class: dnsmessage.ClassINET, + Length: 4, + }, + Body: &dnsmessage.NSResource{ + NS: dnsmessage.MustNewName("good.golang.org."), + }, + }, ) case dnsmessage.TypePTR: r.Answers = append(r.Answers, @@ -1888,6 +1921,17 @@ func TestCVE202133195(t *testing.T) { PTR: dnsmessage.MustNewName(".golang.org."), }, }, + dnsmessage.Resource{ + Header: dnsmessage.ResourceHeader{ + Name: dnsmessage.MustNewName("good.golang.org."), + Type: dnsmessage.TypePTR, + Class: dnsmessage.ClassINET, + Length: 4, + }, + Body: &dnsmessage.PTRResource{ + PTR: dnsmessage.MustNewName("good.golang.org."), + }, + }, ) } return r, nil @@ -1903,59 +1947,139 @@ func TestCVE202133195(t *testing.T) { defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath) testHookHostsPath = "testdata/hosts" - _, err := r.LookupCNAME(context.Background(), "golang.org") - if expected := "lookup golang.org: CNAME target is invalid"; err == nil || err.Error() != expected { - t.Errorf("Resolver.LookupCNAME returned unexpected error, got %q, want %q", err, expected) - } - _, err = LookupCNAME("golang.org") - if expected := "lookup golang.org: CNAME target is invalid"; err == nil || err.Error() != expected { - t.Errorf("LookupCNAME returned unexpected error, got %q, want %q", err, expected) + tests := []struct { + name string + f func(*testing.T) + }{ + { + name: "CNAME", + f: func(t *testing.T) { + expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "golang.org"} + _, err := r.LookupCNAME(context.Background(), "golang.org") + if err.Error() != expectedErr.Error() { + t.Fatalf("unexpected error: %s", err) + } + _, err = LookupCNAME("golang.org") + if err.Error() != expectedErr.Error() { + t.Fatalf("unexpected error: %s", err) + } + }, + }, + { + name: "SRV (bad record)", + f: func(t *testing.T) { + expected := []*SRV{ + { + Target: "good.golang.org.", + }, + } + expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "golang.org"} + _, records, err := r.LookupSRV(context.Background(), "target", "tcp", "golang.org") + if err.Error() != expectedErr.Error() { + t.Fatalf("unexpected error: %s", err) + } + if !reflect.DeepEqual(records, expected) { + t.Error("Unexpected record set") + } + _, records, err = LookupSRV("target", "tcp", "golang.org") + if err.Error() != expectedErr.Error() { + t.Errorf("unexpected error: %s", err) + } + if !reflect.DeepEqual(records, expected) { + t.Error("Unexpected record set") + } + }, + }, + { + name: "SRV (bad header)", + f: func(t *testing.T) { + _, _, err := r.LookupSRV(context.Background(), "hdr", "tcp", "golang.org.") + if expected := "lookup golang.org.: SRV header name is invalid"; err == nil || err.Error() != expected { + t.Errorf("Resolver.LookupSRV returned unexpected error, got %q, want %q", err, expected) + } + _, _, err = LookupSRV("hdr", "tcp", "golang.org.") + if expected := "lookup golang.org.: SRV header name is invalid"; err == nil || err.Error() != expected { + t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err, expected) + } + }, + }, + { + name: "MX", + f: func(t *testing.T) { + expected := []*MX{ + { + Host: "good.golang.org.", + }, + } + expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "golang.org"} + records, err := r.LookupMX(context.Background(), "golang.org") + if err.Error() != expectedErr.Error() { + t.Fatalf("unexpected error: %s", err) + } + if !reflect.DeepEqual(records, expected) { + t.Error("Unexpected record set") + } + records, err = LookupMX("golang.org") + if err.Error() != expectedErr.Error() { + t.Fatalf("unexpected error: %s", err) + } + if !reflect.DeepEqual(records, expected) { + t.Error("Unexpected record set") + } + }, + }, + { + name: "NS", + f: func(t *testing.T) { + expected := []*NS{ + { + Host: "good.golang.org.", + }, + } + expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "golang.org"} + records, err := r.LookupNS(context.Background(), "golang.org") + if err.Error() != expectedErr.Error() { + t.Fatalf("unexpected error: %s", err) + } + if !reflect.DeepEqual(records, expected) { + t.Error("Unexpected record set") + } + records, err = LookupNS("golang.org") + if err.Error() != expectedErr.Error() { + t.Fatalf("unexpected error: %s", err) + } + if !reflect.DeepEqual(records, expected) { + t.Error("Unexpected record set") + } + }, + }, + { + name: "Addr", + f: func(t *testing.T) { + expected := []string{"good.golang.org."} + expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "192.0.2.42"} + records, err := r.LookupAddr(context.Background(), "192.0.2.42") + if err.Error() != expectedErr.Error() { + t.Fatalf("unexpected error: %s", err) + } + if !reflect.DeepEqual(records, expected) { + t.Error("Unexpected record set") + } + records, err = LookupAddr("192.0.2.42") + if err.Error() != expectedErr.Error() { + t.Fatalf("unexpected error: %s", err) + } + if !reflect.DeepEqual(records, expected) { + t.Error("Unexpected record set") + } + }, + }, } - _, _, err = r.LookupSRV(context.Background(), "target", "tcp", "golang.org") - if expected := "lookup golang.org: SRV target is invalid"; err == nil || err.Error() != expected { - t.Errorf("Resolver.LookupSRV returned unexpected error, got %q, want %q", err, expected) - } - _, _, err = LookupSRV("target", "tcp", "golang.org") - if expected := "lookup golang.org: SRV target is invalid"; err == nil || err.Error() != expected { - t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err, expected) + for _, tc := range tests { + t.Run(tc.name, tc.f) } - _, _, err = r.LookupSRV(context.Background(), "hdr", "tcp", "golang.org.") - if expected := "lookup golang.org.: SRV header name is invalid"; err == nil || err.Error() != expected { - t.Errorf("Resolver.LookupSRV returned unexpected error, got %q, want %q", err, expected) - } - _, _, err = LookupSRV("hdr", "tcp", "golang.org.") - if expected := "lookup golang.org.: SRV header name is invalid"; err == nil || err.Error() != expected { - t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err, expected) - } - - _, err = r.LookupMX(context.Background(), "golang.org") - if expected := "lookup golang.org: MX target is invalid"; err == nil || err.Error() != expected { - t.Errorf("Resolver.LookupMX returned unexpected error, got %q, want %q", err, expected) - } - _, err = LookupMX("golang.org") - if expected := "lookup golang.org: MX target is invalid"; err == nil || err.Error() != expected { - t.Errorf("LookupMX returned unexpected error, got %q, want %q", err, expected) - } - - _, err = r.LookupNS(context.Background(), "golang.org") - if expected := "lookup golang.org: NS target is invalid"; err == nil || err.Error() != expected { - t.Errorf("Resolver.LookupNS returned unexpected error, got %q, want %q", err, expected) - } - _, err = LookupNS("golang.org") - if expected := "lookup golang.org: NS target is invalid"; err == nil || err.Error() != expected { - t.Errorf("LookupNS returned unexpected error, got %q, want %q", err, expected) - } - - _, err = r.LookupAddr(context.Background(), "192.0.2.42") - if expected := "lookup 192.0.2.42: PTR target is invalid"; err == nil || err.Error() != expected { - t.Errorf("Resolver.LookupAddr returned unexpected error, got %q, want %q", err, expected) - } - _, err = LookupAddr("192.0.2.42") - if expected := "lookup 192.0.2.42: PTR target is invalid"; err == nil || err.Error() != expected { - t.Errorf("LookupAddr returned unexpected error, got %q, want %q", err, expected) - } } func TestNullMX(t *testing.T) { diff --git a/src/net/lookup.go b/src/net/lookup.go index b5af3a0f86..d350ef7fc0 100644 --- a/src/net/lookup.go +++ b/src/net/lookup.go @@ -424,7 +424,7 @@ func (r *Resolver) LookupCNAME(ctx context.Context, host string) (string, error) return "", err } if !isDomainName(cname) { - return "", &DNSError{Err: "CNAME target is invalid", Name: host} + return "", &DNSError{Err: errMalformedDNSRecordsDetail, Name: host} } return cname, nil } @@ -440,7 +440,9 @@ func (r *Resolver) LookupCNAME(ctx context.Context, host string) (string, error) // and proto are empty strings, LookupSRV looks up name directly. // // The returned service names are validated to be properly -// formatted presentation-format domain names. +// formatted presentation-format domain names. If the response contains +// invalid names, those records are filtered out and an error +// will be returned alongside the the remaining results, if any. func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) { return DefaultResolver.LookupSRV(context.Background(), service, proto, name) } @@ -456,7 +458,9 @@ func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err err // and proto are empty strings, LookupSRV looks up name directly. // // The returned service names are validated to be properly -// formatted presentation-format domain names. +// formatted presentation-format domain names. If the response contains +// invalid names, those records are filtered out and an error +// will be returned alongside the the remaining results, if any. func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) { cname, addrs, err := r.lookupSRV(ctx, service, proto, name) if err != nil { @@ -465,21 +469,28 @@ func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) ( if cname != "" && !isDomainName(cname) { return "", nil, &DNSError{Err: "SRV header name is invalid", Name: name} } + filteredAddrs := make([]*SRV, 0, len(addrs)) for _, addr := range addrs { if addr == nil { continue } if !isDomainName(addr.Target) { - return "", nil, &DNSError{Err: "SRV target is invalid", Name: name} + continue } + filteredAddrs = append(filteredAddrs, addr) } - return cname, addrs, nil + if len(addrs) != len(filteredAddrs) { + return cname, filteredAddrs, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name} + } + return cname, filteredAddrs, nil } // LookupMX returns the DNS MX records for the given domain name sorted by preference. // // The returned mail server names are validated to be properly -// formatted presentation-format domain names. +// formatted presentation-format domain names. If the response contains +// invalid names, those records are filtered out and an error +// will be returned alongside the the remaining results, if any. // // LookupMX uses context.Background internally; to specify the context, use // Resolver.LookupMX. @@ -490,12 +501,15 @@ func LookupMX(name string) ([]*MX, error) { // LookupMX returns the DNS MX records for the given domain name sorted by preference. // // The returned mail server names are validated to be properly -// formatted presentation-format domain names. +// formatted presentation-format domain names. If the response contains +// invalid names, those records are filtered out and an error +// will be returned alongside the the remaining results, if any. func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) { records, err := r.lookupMX(ctx, name) if err != nil { return nil, err } + filteredMX := make([]*MX, 0, len(records)) for _, mx := range records { if mx == nil { continue @@ -503,16 +517,22 @@ func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) { // Bypass the hostname validity check for targets which contain only a dot, // as this is used to represent a 'Null' MX record. if mx.Host != "." && !isDomainName(mx.Host) { - return nil, &DNSError{Err: "MX target is invalid", Name: name} + continue } + filteredMX = append(filteredMX, mx) } - return records, nil + if len(records) != len(filteredMX) { + return filteredMX, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name} + } + return filteredMX, nil } // LookupNS returns the DNS NS records for the given domain name. // // The returned name server names are validated to be properly -// formatted presentation-format domain names. +// formatted presentation-format domain names. If the response contains +// invalid names, those records are filtered out and an error +// will be returned alongside the the remaining results, if any. // // LookupNS uses context.Background internally; to specify the context, use // Resolver.LookupNS. @@ -523,21 +543,28 @@ func LookupNS(name string) ([]*NS, error) { // LookupNS returns the DNS NS records for the given domain name. // // The returned name server names are validated to be properly -// formatted presentation-format domain names. +// formatted presentation-format domain names. If the response contains +// invalid names, those records are filtered out and an error +// will be returned alongside the the remaining results, if any. func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) { records, err := r.lookupNS(ctx, name) if err != nil { return nil, err } + filteredNS := make([]*NS, 0, len(records)) for _, ns := range records { if ns == nil { continue } if !isDomainName(ns.Host) { - return nil, &DNSError{Err: "NS target is invalid", Name: name} + continue } + filteredNS = append(filteredNS, ns) } - return records, nil + if len(records) != len(filteredNS) { + return filteredNS, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name} + } + return filteredNS, nil } // LookupTXT returns the DNS TXT records for the given domain name. @@ -557,7 +584,8 @@ func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, error) // of names mapping to that address. // // The returned names are validated to be properly formatted presentation-format -// domain names. +// domain names. If the response contains invalid names, those records are filtered +// out and an error will be returned alongside the the remaining results, if any. // // When using the host C library resolver, at most one result will be // returned. To bypass the host resolver, use a custom Resolver. @@ -572,16 +600,26 @@ func LookupAddr(addr string) (names []string, err error) { // of names mapping to that address. // // The returned names are validated to be properly formatted presentation-format -// domain names. +// domain names. If the response contains invalid names, those records are filtered +// out and an error will be returned alongside the the remaining results, if any. func (r *Resolver) LookupAddr(ctx context.Context, addr string) ([]string, error) { names, err := r.lookupAddr(ctx, addr) if err != nil { return nil, err } + filteredNames := make([]string, 0, len(names)) for _, name := range names { - if !isDomainName(name) { - return nil, &DNSError{Err: "PTR target is invalid", Name: addr} + if isDomainName(name) { + filteredNames = append(filteredNames, name) } } - return names, nil + if len(names) != len(filteredNames) { + return filteredNames, &DNSError{Err: errMalformedDNSRecordsDetail, Name: addr} + } + return filteredNames, nil } + +// errMalformedDNSRecordsDetail is the DNSError detail which is returned when a Resolver.Lookup... +// method recieves DNS records which contain invalid DNS names. This may be returned alongside +// results which have had the malformed records filtered out. +var errMalformedDNSRecordsDetail = "DNS response contained records which contain invalid names"