From 3a5bcac339c5b166bc1a51c38226a8dc5e6484ca Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 12 Mar 2021 19:44:12 -0800 Subject: [PATCH] libgo: update to Go 1.16.2 release Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/301459 --- gcc/go/gofrontend/MERGE | 2 +- libgo/MERGE | 2 +- libgo/VERSION | 2 +- libgo/go/archive/zip/reader.go | 2 +- libgo/go/archive/zip/reader_test.go | 35 ++++ libgo/go/cmd/go.mod | 2 +- libgo/go/cmd/go/internal/get/get.go | 30 +++- libgo/go/cmd/go/internal/modcmd/tidy.go | 9 +- libgo/go/cmd/go/internal/modcmd/vendor.go | 9 +- libgo/go/cmd/go/internal/modget/get.go | 2 +- libgo/go/cmd/go/internal/modget/query.go | 2 +- libgo/go/cmd/go/internal/modload/import.go | 18 +- libgo/go/cmd/go/internal/modload/init.go | 11 +- libgo/go/cmd/go/internal/modload/list.go | 2 +- libgo/go/cmd/go/internal/modload/load.go | 13 +- libgo/go/cmd/go/internal/run/run.go | 20 +-- .../go/testdata/script/mod_convert_dep.txt | 2 +- libgo/go/cmd/go/testdata/script/mod_edit.txt | 16 +- libgo/go/cmd/go/testdata/script/mod_find.txt | 2 +- .../go/cmd/go/testdata/script/mod_outside.txt | 52 +++--- .../cmd/go/testdata/script/mod_tidy_error.txt | 4 +- libgo/go/cmd/vendor/modules.txt | 2 +- libgo/go/encoding/xml/xml.go | 19 +- libgo/go/encoding/xml/xml_test.go | 104 ++++++++--- libgo/go/go/build/build_test.go | 2 +- libgo/go/golang.org/x/mod/modfile/rule.go | 167 +++++++++++++----- libgo/go/golang.org/x/mod/module/module.go | 40 +++-- libgo/go/time/zoneinfo.go | 6 +- libgo/go/time/zoneinfo_test.go | 60 +++++-- libgo/misc/cgo/testplugin/plugin_test.go | 15 +- .../cgo/testplugin/testdata/method2/main.go | 32 ++++ .../cgo/testplugin/testdata/method2/p/p.go | 9 + .../cgo/testplugin/testdata/method2/plugin.go | 11 ++ 33 files changed, 511 insertions(+), 193 deletions(-) create mode 100644 libgo/misc/cgo/testplugin/testdata/method2/main.go create mode 100644 libgo/misc/cgo/testplugin/testdata/method2/p/p.go create mode 100644 libgo/misc/cgo/testplugin/testdata/method2/plugin.go diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index e5756c6662c..c0bfa1ff78a 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -2f281eb24ef256a2d3bb9fc1a7ef964d82b40182 +10b00ad87303d37c68b2d54dd25d655bd316946e The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/libgo/MERGE b/libgo/MERGE index 183b0245ee2..a52dceb182f 100644 --- a/libgo/MERGE +++ b/libgo/MERGE @@ -1,4 +1,4 @@ -f21be2fdc6f1becdbed1592ea0b245cdeedc5ac8 +3979fb9af9ccfc0b7ccb613dcf256b18c2c295f0 The first line of this file holds the git revision number of the last merge done from the master library sources. diff --git a/libgo/VERSION b/libgo/VERSION index 4befab24bc9..d0b0a900460 100644 --- a/libgo/VERSION +++ b/libgo/VERSION @@ -1 +1 @@ -go1.16 +go1.16.2 diff --git a/libgo/go/archive/zip/reader.go b/libgo/go/archive/zip/reader.go index 8b4e77875fb..c288ad965bc 100644 --- a/libgo/go/archive/zip/reader.go +++ b/libgo/go/archive/zip/reader.go @@ -664,7 +664,7 @@ func toValidName(name string) string { if strings.HasPrefix(p, "/") { p = p[len("/"):] } - for strings.HasPrefix(name, "../") { + for strings.HasPrefix(p, "../") { p = p[len("../"):] } return p diff --git a/libgo/go/archive/zip/reader_test.go b/libgo/go/archive/zip/reader_test.go index 34e96f7da43..5faf1f49b51 100644 --- a/libgo/go/archive/zip/reader_test.go +++ b/libgo/go/archive/zip/reader_test.go @@ -1081,3 +1081,38 @@ func TestFS(t *testing.T) { t.Fatal(err) } } + +func TestCVE202127919(t *testing.T) { + // Archive containing only the file "../test.txt" + data := []byte{ + 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x08, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x2e, 0x2e, + 0x2f, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x74, 0x78, + 0x74, 0x0a, 0xc9, 0xc8, 0x2c, 0x56, 0xc8, 0x2c, + 0x56, 0x48, 0x54, 0x28, 0x49, 0x2d, 0x2e, 0x51, + 0x28, 0x49, 0xad, 0x28, 0x51, 0x48, 0xcb, 0xcc, + 0x49, 0xd5, 0xe3, 0x02, 0x04, 0x00, 0x00, 0xff, + 0xff, 0x50, 0x4b, 0x07, 0x08, 0xc0, 0xd7, 0xed, + 0xc3, 0x20, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, + 0x00, 0x50, 0x4b, 0x01, 0x02, 0x14, 0x00, 0x14, + 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0xd7, 0xed, 0xc3, 0x20, 0x00, 0x00, + 0x00, 0x1a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, + 0x2e, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x74, + 0x78, 0x74, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x39, 0x00, + 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, + } + r, err := NewReader(bytes.NewReader([]byte(data)), int64(len(data))) + if err != nil { + t.Fatalf("Error reading the archive: %v", err) + } + _, err = r.Open("test.txt") + if err != nil { + t.Errorf("Error reading file: %v", err) + } +} diff --git a/libgo/go/cmd/go.mod b/libgo/go/cmd/go.mod index 235e28f64f3..35582f3975f 100644 --- a/libgo/go/cmd/go.mod +++ b/libgo/go/cmd/go.mod @@ -6,7 +6,7 @@ require ( github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2 golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 - golang.org/x/mod v0.4.1 + golang.org/x/mod v0.4.2-0.20210302225053-d515b24adc21 golang.org/x/sys v0.0.0-20201204225414-ed752295db88 // indirect golang.org/x/tools v0.0.0-20210107193943-4ed967dd8eff ) diff --git a/libgo/go/cmd/go/internal/get/get.go b/libgo/go/cmd/go/internal/get/get.go index 38ff3823f22..329a2f5eda4 100644 --- a/libgo/go/cmd/go/internal/get/get.go +++ b/libgo/go/cmd/go/internal/get/get.go @@ -431,7 +431,7 @@ func downloadPackage(p *load.Package) error { } importPrefix = importPrefix[:slash] } - if err := module.CheckImportPath(importPrefix); err != nil { + if err := checkImportPath(importPrefix); err != nil { return fmt.Errorf("%s: invalid import path: %v", p.ImportPath, err) } security := web.SecureOnly @@ -591,3 +591,31 @@ func selectTag(goVersion string, tags []string) (match string) { } return "" } + +// checkImportPath is like module.CheckImportPath, but it forbids leading dots +// in path elements. This can lead to 'go get' creating .git and other VCS +// directories in places we might run VCS tools later. +func checkImportPath(path string) error { + if err := module.CheckImportPath(path); err != nil { + return err + } + checkElem := func(elem string) error { + if elem[0] == '.' { + return fmt.Errorf("malformed import path %q: leading dot in path element", path) + } + return nil + } + elemStart := 0 + for i, r := range path { + if r == '/' { + if err := checkElem(path[elemStart:]); err != nil { + return err + } + elemStart = i + 1 + } + } + if err := checkElem(path[elemStart:]); err != nil { + return err + } + return nil +} diff --git a/libgo/go/cmd/go/internal/modcmd/tidy.go b/libgo/go/cmd/go/internal/modcmd/tidy.go index 3b83d87a8eb..8bc9ed50bed 100644 --- a/libgo/go/cmd/go/internal/modcmd/tidy.go +++ b/libgo/go/cmd/go/internal/modcmd/tidy.go @@ -62,10 +62,11 @@ func runTidy(ctx context.Context, cmd *base.Command, args []string) { modload.RootMode = modload.NeedRoot modload.LoadPackages(ctx, modload.PackageOpts{ - Tags: imports.AnyTags(), - ResolveMissingImports: true, - LoadTests: true, - AllowErrors: tidyE, + Tags: imports.AnyTags(), + ResolveMissingImports: true, + LoadTests: true, + AllowErrors: tidyE, + SilenceMissingStdImports: true, }, "all") modload.TidyBuildList() diff --git a/libgo/go/cmd/go/internal/modcmd/vendor.go b/libgo/go/cmd/go/internal/modcmd/vendor.go index d3ed9e00e22..ac1fb7720aa 100644 --- a/libgo/go/cmd/go/internal/modcmd/vendor.go +++ b/libgo/go/cmd/go/internal/modcmd/vendor.go @@ -64,10 +64,11 @@ func runVendor(ctx context.Context, cmd *base.Command, args []string) { modload.RootMode = modload.NeedRoot loadOpts := modload.PackageOpts{ - Tags: imports.AnyTags(), - ResolveMissingImports: true, - UseVendorAll: true, - AllowErrors: vendorE, + Tags: imports.AnyTags(), + ResolveMissingImports: true, + UseVendorAll: true, + AllowErrors: vendorE, + SilenceMissingStdImports: true, } _, pkgs := modload.LoadPackages(ctx, loadOpts, "all") diff --git a/libgo/go/cmd/go/internal/modget/get.go b/libgo/go/cmd/go/internal/modget/get.go index dccacd3d1ee..5a98408a325 100644 --- a/libgo/go/cmd/go/internal/modget/get.go +++ b/libgo/go/cmd/go/internal/modget/get.go @@ -1514,7 +1514,7 @@ func (r *resolver) checkPackagesAndRetractions(ctx context.Context, pkgPatterns } } if retractPath != "" { - fmt.Fprintf(os.Stderr, "go: to switch to the latest unretracted version, run:\n\tgo get %s@latest", retractPath) + fmt.Fprintf(os.Stderr, "go: to switch to the latest unretracted version, run:\n\tgo get %s@latest\n", retractPath) } } diff --git a/libgo/go/cmd/go/internal/modget/query.go b/libgo/go/cmd/go/internal/modget/query.go index d8364c8c0d3..1a5a60f7eb9 100644 --- a/libgo/go/cmd/go/internal/modget/query.go +++ b/libgo/go/cmd/go/internal/modget/query.go @@ -186,7 +186,7 @@ func (q *query) validate() error { if q.pattern == "all" { // If there is no main module, "all" is not meaningful. if !modload.HasModRoot() { - return fmt.Errorf(`cannot match "all": working directory is not part of a module`) + return fmt.Errorf(`cannot match "all": %v`, modload.ErrNoModRoot) } if !versionOkForMainModule(q.version) { // TODO(bcmills): "all@none" seems like a totally reasonable way to diff --git a/libgo/go/cmd/go/internal/modload/import.go b/libgo/go/cmd/go/internal/modload/import.go index 182429aee41..995641c9f1f 100644 --- a/libgo/go/cmd/go/internal/modload/import.go +++ b/libgo/go/cmd/go/internal/modload/import.go @@ -51,7 +51,7 @@ func (e *ImportMissingError) Error() string { if e.isStd { return fmt.Sprintf("package %s is not in GOROOT (%s)", e.Path, filepath.Join(cfg.GOROOT, "src", e.Path)) } - if e.QueryErr != nil { + if e.QueryErr != nil && e.QueryErr != ErrNoModRoot { return fmt.Sprintf("cannot find module providing package %s: %v", e.Path, e.QueryErr) } if cfg.BuildMod == "mod" || (cfg.BuildMod == "readonly" && allowMissingModuleImports) { @@ -66,13 +66,11 @@ func (e *ImportMissingError) Error() string { return fmt.Sprintf("module %s provides package %s and is replaced but not required; to add it:\n\tgo get %s", e.replaced.Path, e.Path, suggestArg) } - suggestion := "" - if !HasModRoot() { - suggestion = ": working directory is not part of a module" - } else { - suggestion = fmt.Sprintf("; to add it:\n\tgo get %s", e.Path) + message := fmt.Sprintf("no required module provides package %s", e.Path) + if e.QueryErr != nil { + return fmt.Sprintf("%s: %v", message, e.QueryErr) } - return fmt.Sprintf("no required module provides package %s%s", e.Path, suggestion) + return fmt.Sprintf("%s; to add it:\n\tgo get %s", message, e.Path) } if e.newMissingVersion != "" { @@ -318,7 +316,11 @@ func importFromBuildList(ctx context.Context, path string, buildList []module.Ve return mods[0], dirs[0], nil } - return module.Version{}, "", &ImportMissingError{Path: path, isStd: pathIsStd} + var queryErr error + if !HasModRoot() { + queryErr = ErrNoModRoot + } + return module.Version{}, "", &ImportMissingError{Path: path, QueryErr: queryErr, isStd: pathIsStd} } // queryImport attempts to locate a module that can be added to the current diff --git a/libgo/go/cmd/go/internal/modload/init.go b/libgo/go/cmd/go/internal/modload/init.go index bc8d17e0a5f..8ec1c8681a9 100644 --- a/libgo/go/cmd/go/internal/modload/init.go +++ b/libgo/go/cmd/go/internal/modload/init.go @@ -177,7 +177,7 @@ func Init() { base.Fatalf("go: cannot find main module, but -modfile was set.\n\t-modfile cannot be used to set the module root directory.") } if RootMode == NeedRoot { - base.Fatalf("go: cannot find main module; see 'go help modules'") + base.Fatalf("go: %v", ErrNoModRoot) } if !mustUseModules { // GO111MODULE is 'auto', and we can't find a module root. @@ -338,9 +338,11 @@ func die() { } base.Fatalf("go: cannot find main module, but found %s in %s\n\tto create a module there, run:\n\t%sgo mod init", name, dir, cdCmd) } - base.Fatalf("go: cannot find main module; see 'go help modules'") + base.Fatalf("go: %v", ErrNoModRoot) } +var ErrNoModRoot = errors.New("go.mod file not found in current directory or any parent directory; see 'go help modules'") + // LoadModFile sets Target and, if there is a main module, parses the initial // build list from its go.mod file. // @@ -539,9 +541,10 @@ func fixVersion(ctx context.Context, fixed *bool) modfile.VersionFixer { } } if vers != "" && module.CanonicalVersion(vers) == vers { - if err := module.CheckPathMajor(vers, pathMajor); err == nil { - return vers, nil + if err := module.CheckPathMajor(vers, pathMajor); err != nil { + return "", module.VersionError(module.Version{Path: path, Version: vers}, err) } + return vers, nil } info, err := Query(ctx, path, vers, "", nil) diff --git a/libgo/go/cmd/go/internal/modload/list.go b/libgo/go/cmd/go/internal/modload/list.go index 3491f941cd3..7b1aa7fd413 100644 --- a/libgo/go/cmd/go/internal/modload/list.go +++ b/libgo/go/cmd/go/internal/modload/list.go @@ -73,7 +73,7 @@ func listModules(ctx context.Context, args []string, listVersions, listRetracted base.Fatalf("go: cannot use relative path %s to specify module", arg) } if !HasModRoot() && (arg == "all" || strings.Contains(arg, "...")) { - base.Fatalf("go: cannot match %q: working directory is not part of a module", arg) + base.Fatalf("go: cannot match %q: %v", arg, ErrNoModRoot) } if i := strings.Index(arg, "@"); i >= 0 { path := arg[:i] diff --git a/libgo/go/cmd/go/internal/modload/load.go b/libgo/go/cmd/go/internal/modload/load.go index 6d87acc6d3b..154fc3c6f0a 100644 --- a/libgo/go/cmd/go/internal/modload/load.go +++ b/libgo/go/cmd/go/internal/modload/load.go @@ -170,6 +170,12 @@ type PackageOpts struct { // that occur while loading packages. SilenceErrors implies AllowErrors. SilenceErrors bool + // SilenceMissingStdImports indicates that LoadPackages should not print + // errors or terminate the process if an imported package is missing, and the + // import path looks like it might be in the standard library (perhaps in a + // future version). + SilenceMissingStdImports bool + // SilenceUnmatchedWarnings suppresses the warnings normally emitted for // patterns that did not match any packages. SilenceUnmatchedWarnings bool @@ -287,8 +293,13 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma sumErr.importerIsTest = importer.testOf != nil } } + silence := opts.SilenceErrors + if stdErr := (*ImportMissingError)(nil); errors.As(pkg.err, &stdErr) && + stdErr.isStd && opts.SilenceMissingStdImports { + silence = true + } - if !opts.SilenceErrors { + if !silence { if opts.AllowErrors { fmt.Fprintf(os.Stderr, "%s: %v\n", pkg.stackText(), pkg.err) } else { diff --git a/libgo/go/cmd/go/internal/run/run.go b/libgo/go/cmd/go/internal/run/run.go index 99578b244c8..666b1a0e560 100644 --- a/libgo/go/cmd/go/internal/run/run.go +++ b/libgo/go/cmd/go/internal/run/run.go @@ -96,28 +96,12 @@ func runRun(ctx context.Context, cmd *base.Command, args []string) { base.Fatalf("go run: no go files listed") } cmdArgs := args[i:] - if p.Error != nil { - base.Fatalf("%s", p.Error) - } + load.CheckPackageErrors([]*load.Package{p}) - p.Internal.OmitDebug = true - if len(p.DepsErrors) > 0 { - // Since these are errors in dependencies, - // the same error might show up multiple times, - // once in each package that depends on it. - // Only print each once. - printed := map[*load.PackageError]bool{} - for _, err := range p.DepsErrors { - if !printed[err] { - printed[err] = true - base.Errorf("%s", err) - } - } - } - base.ExitIfErrors() if p.Name != "main" { base.Fatalf("go run: cannot run non-main package") } + p.Internal.OmitDebug = true p.Target = "" // must build - not up to date if p.Internal.CmdlineFiles { //set executable name if go file is given as cmd-argument diff --git a/libgo/go/cmd/go/testdata/script/mod_convert_dep.txt b/libgo/go/cmd/go/testdata/script/mod_convert_dep.txt index ad22aca5be8..875a836fd27 100644 --- a/libgo/go/cmd/go/testdata/script/mod_convert_dep.txt +++ b/libgo/go/cmd/go/testdata/script/mod_convert_dep.txt @@ -18,7 +18,7 @@ stdout '^m$' # Test that we ignore directories when trying to find alternate config files. cd $WORK/gopkgdir/x ! go list . -stderr 'cannot find main module' +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' ! stderr 'Gopkg.lock' -- $WORK/test/Gopkg.lock -- diff --git a/libgo/go/cmd/go/testdata/script/mod_edit.txt b/libgo/go/cmd/go/testdata/script/mod_edit.txt index d7e681e8313..9da69306dac 100644 --- a/libgo/go/cmd/go/testdata/script/mod_edit.txt +++ b/libgo/go/cmd/go/testdata/script/mod_edit.txt @@ -16,9 +16,9 @@ cmpenv go.mod $WORK/go.mod.init cmpenv go.mod $WORK/go.mod.init # go mod edits -go mod edit -droprequire=x.1 -require=x.1@v1.0.0 -require=x.2@v1.1.0 -droprequire=x.2 -exclude='x.1 @ v1.2.0' -exclude=x.1@v1.2.1 -replace=x.1@v1.3.0=y.1@v1.4.0 -replace='x.1@v1.4.0 = ../z' -retract=v1.6.0 -retract=[v1.1.0,v1.2.0] -retract=[v1.3.0,v1.4.0] -retract=v1.0.0 +go mod edit -droprequire=x.1 -require=x.1@v1.0.0 -require=x.2@v1.1.0 -droprequire=x.2 -exclude='x.1 @ v1.2.0' -exclude=x.1@v1.2.1 -exclude=x.1@v2.0.0+incompatible -replace=x.1@v1.3.0=y.1@v1.4.0 -replace='x.1@v1.4.0 = ../z' -retract=v1.6.0 -retract=[v1.1.0,v1.2.0] -retract=[v1.3.0,v1.4.0] -retract=v1.0.0 cmpenv go.mod $WORK/go.mod.edit1 -go mod edit -droprequire=x.1 -dropexclude=x.1@v1.2.1 -dropreplace=x.1@v1.3.0 -require=x.3@v1.99.0 -dropretract=v1.0.0 -dropretract=[v1.1.0,v1.2.0] +go mod edit -droprequire=x.1 -dropexclude=x.1@v1.2.1 -dropexclude=x.1@v2.0.0+incompatible -dropreplace=x.1@v1.3.0 -require=x.3@v1.99.0 -dropretract=v1.0.0 -dropretract=[v1.1.0,v1.2.0] cmpenv go.mod $WORK/go.mod.edit2 # -exclude and -retract reject invalid versions. @@ -27,6 +27,17 @@ stderr '^go mod: -exclude=example.com/m@bad: version "bad" invalid: must be of t ! go mod edit -retract=bad stderr '^go mod: -retract=bad: version "bad" invalid: must be of the form v1.2.3$' +! go mod edit -exclude=example.com/m@v2.0.0 +stderr '^go mod: -exclude=example.com/m@v2\.0\.0: version "v2\.0\.0" invalid: should be v2\.0\.0\+incompatible \(or module example\.com/m/v2\)$' + +! go mod edit -exclude=example.com/m/v2@v1.0.0 +stderr '^go mod: -exclude=example.com/m/v2@v1\.0\.0: version "v1\.0\.0" invalid: should be v2, not v1$' + +! go mod edit -exclude=gopkg.in/example.v1@v2.0.0 +stderr '^go mod: -exclude=gopkg\.in/example\.v1@v2\.0\.0: version "v2\.0\.0" invalid: should be v1, not v2$' + +cmpenv go.mod $WORK/go.mod.edit2 + # go mod edit -json go mod edit -json cmpenv stdout $WORK/go.mod.json @@ -88,6 +99,7 @@ require x.1 v1.0.0 exclude ( x.1 v1.2.0 x.1 v1.2.1 + x.1 v2.0.0+incompatible ) replace ( diff --git a/libgo/go/cmd/go/testdata/script/mod_find.txt b/libgo/go/cmd/go/testdata/script/mod_find.txt index 9468acfd33d..1e01973ff41 100644 --- a/libgo/go/cmd/go/testdata/script/mod_find.txt +++ b/libgo/go/cmd/go/testdata/script/mod_find.txt @@ -49,7 +49,7 @@ rm go.mod # Test that we ignore directories when trying to find go.mod. cd $WORK/gomoddir ! go list . -stderr 'cannot find main module' +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' [!symlink] stop diff --git a/libgo/go/cmd/go/testdata/script/mod_outside.txt b/libgo/go/cmd/go/testdata/script/mod_outside.txt index 8f01b5d2426..565589268ee 100644 --- a/libgo/go/cmd/go/testdata/script/mod_outside.txt +++ b/libgo/go/cmd/go/testdata/script/mod_outside.txt @@ -12,13 +12,13 @@ stdout 'NUL|/dev/null' # 'go list' without arguments implicitly operates on the current directory, # which is not in a module. ! go list -stderr 'cannot find main module' +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' go list -m stdout '^command-line-arguments$' # 'go list' in the working directory should fail even if there is a a 'package # main' present: without a main module, we do not know its package path. ! go list ./needmod -stderr 'cannot find main module' +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' # 'go list all' lists the transitive import graph of the main module, # which is empty if there is no main module. @@ -41,7 +41,7 @@ stdout 'command-line-arguments' # 'go list' on a package from a module should fail. ! go list example.com/printversion -stderr '^no required module provides package example.com/printversion: working directory is not part of a module$' +stderr '^no required module provides package example.com/printversion: go.mod file not found in current directory or any parent directory; see ''go help modules''$' # 'go list -m' with an explicit version should resolve that version. @@ -54,19 +54,19 @@ stdout 'v1.0.0\s+v1.0.1\s+v1.1.0' # 'go list -m all' should fail. "all" is not meaningful outside of a module. ! go list -m all -stderr 'go: cannot match "all": working directory is not part of a module' +stderr 'go: cannot match "all": go.mod file not found in current directory or any parent directory; see ''go help modules''$' # 'go list -m all' should also fail. ! go list -m example.com/printversion@v1.0.0 all -stderr 'go: cannot match "all": working directory is not part of a module' +stderr 'go: cannot match "all": go.mod file not found in current directory or any parent directory; see ''go help modules''$' ! stdout 'example.com/version' # 'go list -m' with wildcards should fail. Wildcards match modules in the # build list, so they aren't meaningful outside a module. ! go list -m ... -stderr 'go: cannot match "...": working directory is not part of a module' +stderr 'go: cannot match "...": go.mod file not found in current directory or any parent directory; see ''go help modules''$' ! go list -m rsc.io/quote/... -stderr 'go: cannot match "rsc.io/quote/...": working directory is not part of a module' +stderr 'go: cannot match "rsc.io/quote/...": go.mod file not found in current directory or any parent directory; see ''go help modules''$' # 'go clean' should skip the current directory if it isn't in a module. @@ -76,20 +76,20 @@ go clean -n # 'go mod graph' should fail, since there's no module graph. ! go mod graph -stderr 'cannot find main module' +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' # 'go mod why' should fail, since there is no main module to depend on anything. ! go mod why -m example.com/version -stderr 'cannot find main module' +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' # 'go mod edit', 'go mod tidy', and 'go mod fmt' should fail: # there is no go.mod file to edit. ! go mod tidy -stderr 'cannot find main module' +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' ! go mod edit -fmt -stderr 'cannot find main module' +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' ! go mod edit -require example.com/version@v1.0.0 -stderr 'cannot find main module' +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' # 'go mod download' without arguments should report an error. @@ -104,33 +104,33 @@ exists $GOPATH/pkg/mod/cache/download/example.com/printversion/@v/v1.0.0.zip # 'go mod download all' should fail. "all" is not meaningful outside of a module. ! go mod download all -stderr 'go: cannot match "all": working directory is not part of a module' +stderr 'go: cannot match "all": go.mod file not found in current directory or any parent directory; see ''go help modules''$' # 'go mod vendor' should fail: it starts by clearing the existing vendor # directory, and we don't know where that is. ! go mod vendor -stderr 'cannot find main module' +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' # 'go mod verify' should fail: we have no modules to verify. ! go mod verify -stderr 'cannot find main module' +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' # 'go get' without arguments implicitly operates on the main module, and thus # should fail. ! go get -stderr 'cannot find main module' +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' ! go get -u -stderr 'cannot find main module' +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' ! go get -u ./needmod -stderr 'cannot find main module' +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' # 'go get -u all' upgrades the transitive import graph of the main module, # which is empty. ! go get -u all -stderr 'go get: cannot match "all": working directory is not part of a module' +stderr '^go get: cannot match "all": go.mod file not found in current directory or any parent directory; see ''go help modules''$' # 'go get' should check the proposed module graph for consistency, # even though we won't write it anywhere. @@ -147,16 +147,16 @@ exists $GOPATH/pkg/mod/example.com/version@v1.0.0 # 'go build' without arguments implicitly operates on the current directory, and should fail. cd needmod ! go build -stderr 'cannot find main module' +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' cd .. # 'go build' of a non-module directory should fail too. ! go build ./needmod -stderr 'cannot find main module' +stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$' # 'go build' of source files should fail if they import anything outside std. ! go build -n ./needmod/needmod.go -stderr '^needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: working directory is not part of a module$' +stderr '^needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: go.mod file not found in current directory or any parent directory; see ''go help modules''$' # 'go build' of source files should succeed if they do not import anything outside std. go build -n -o ignore ./stdonly/stdonly.go @@ -179,7 +179,7 @@ go doc fmt # 'go doc' should fail for a package path outside a module. ! go doc example.com/version -stderr 'doc: no required module provides package example.com/version: working directory is not part of a module' +stderr 'doc: no required module provides package example.com/version: go.mod file not found in current directory or any parent directory; see ''go help modules''$' # 'go install' with a version should succeed if all constraints are met. # See mod_install_pkg_version. @@ -194,7 +194,7 @@ stderr '^go install: version is required when current directory is not in a modu # 'go install' should fail if a source file imports a package that must be # resolved to a module. ! go install ./needmod/needmod.go -stderr 'needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: working directory is not part of a module' +stderr 'needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: go.mod file not found in current directory or any parent directory; see ''go help modules''$' # 'go install' should succeed with a package in GOROOT. go install cmd/addr2line @@ -206,12 +206,12 @@ stderr 'can only use path@version syntax with' # 'go run' should fail if a package argument must be resolved to a module. ! go run example.com/printversion -stderr '^no required module provides package example.com/printversion: working directory is not part of a module$' +stderr '^no required module provides package example.com/printversion: go.mod file not found in current directory or any parent directory; see ''go help modules''$' # 'go run' should fail if a source file imports a package that must be # resolved to a module. ! go run ./needmod/needmod.go -stderr '^needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: working directory is not part of a module$' +stderr '^needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: go.mod file not found in current directory or any parent directory; see ''go help modules''$' # 'go fmt' should be able to format files outside of a module. diff --git a/libgo/go/cmd/go/testdata/script/mod_tidy_error.txt b/libgo/go/cmd/go/testdata/script/mod_tidy_error.txt index b6c24ceaf75..395537b1a71 100644 --- a/libgo/go/cmd/go/testdata/script/mod_tidy_error.txt +++ b/libgo/go/cmd/go/testdata/script/mod_tidy_error.txt @@ -4,12 +4,12 @@ env GO111MODULE=on # 'go mod tidy' and 'go mod vendor' should not hide loading errors. ! go mod tidy -stderr '^issue27063 imports\n\tnonexist: package nonexist is not in GOROOT \(.*\)' +! stderr 'package nonexist is not in GOROOT' stderr '^issue27063 imports\n\tnonexist.example.com: cannot find module providing package nonexist.example.com' stderr '^issue27063 imports\n\tissue27063/other imports\n\tother.example.com/nonexist: cannot find module providing package other.example.com/nonexist' ! go mod vendor -stderr '^issue27063 imports\n\tnonexist: package nonexist is not in GOROOT \(.*\)' +! stderr 'package nonexist is not in GOROOT' stderr '^issue27063 imports\n\tnonexist.example.com: cannot find module providing package nonexist.example.com' stderr '^issue27063 imports\n\tissue27063/other imports\n\tother.example.com/nonexist: cannot find module providing package other.example.com/nonexist' diff --git a/libgo/go/cmd/vendor/modules.txt b/libgo/go/cmd/vendor/modules.txt index e033984956b..10842768a88 100644 --- a/libgo/go/cmd/vendor/modules.txt +++ b/libgo/go/cmd/vendor/modules.txt @@ -28,7 +28,7 @@ golang.org/x/arch/x86/x86asm golang.org/x/crypto/ed25519 golang.org/x/crypto/ed25519/internal/edwards25519 golang.org/x/crypto/ssh/terminal -# golang.org/x/mod v0.4.1 +# golang.org/x/mod v0.4.2-0.20210302225053-d515b24adc21 ## explicit golang.org/x/mod/internal/lazyregexp golang.org/x/mod/modfile diff --git a/libgo/go/encoding/xml/xml.go b/libgo/go/encoding/xml/xml.go index adaf4daf198..6f9594d7ba7 100644 --- a/libgo/go/encoding/xml/xml.go +++ b/libgo/go/encoding/xml/xml.go @@ -271,7 +271,7 @@ func NewTokenDecoder(t TokenReader) *Decoder { // it will return an error. // // Token implements XML name spaces as described by -// https://www.w3.org/TR/REC-xml-names/. Each of the +// https://www.w3.org/TR/REC-xml-names/. Each of the // Name structures contained in the Token has the Space // set to the URL identifying its name space when known. // If Token encounters an unrecognized name space prefix, @@ -285,16 +285,17 @@ func (d *Decoder) Token() (Token, error) { if d.nextToken != nil { t = d.nextToken d.nextToken = nil - } else if t, err = d.rawToken(); err != nil { - switch { - case err == io.EOF && d.t != nil: - err = nil - case err == io.EOF && d.stk != nil && d.stk.kind != stkEOF: - err = d.syntaxError("unexpected EOF") + } else { + if t, err = d.rawToken(); t == nil && err != nil { + if err == io.EOF && d.stk != nil && d.stk.kind != stkEOF { + err = d.syntaxError("unexpected EOF") + } + return nil, err } - return t, err + // We still have a token to process, so clear any + // errors (e.g. EOF) and proceed. + err = nil } - if !d.Strict { if t1, ok := d.autoClose(t); ok { d.nextToken = t diff --git a/libgo/go/encoding/xml/xml_test.go b/libgo/go/encoding/xml/xml_test.go index efddca43e91..5672ebb375f 100644 --- a/libgo/go/encoding/xml/xml_test.go +++ b/libgo/go/encoding/xml/xml_test.go @@ -33,30 +33,90 @@ func (t *toks) Token() (Token, error) { func TestDecodeEOF(t *testing.T) { start := StartElement{Name: Name{Local: "test"}} - t.Run("EarlyEOF", func(t *testing.T) { - d := NewTokenDecoder(&toks{earlyEOF: true, t: []Token{ - start, - start.End(), - }}) - err := d.Decode(&struct { - XMLName Name `xml:"test"` - }{}) - if err != nil { - t.Error(err) + tests := []struct { + name string + tokens []Token + ok bool + }{ + { + name: "OK", + tokens: []Token{ + start, + start.End(), + }, + ok: true, + }, + { + name: "Malformed", + tokens: []Token{ + start, + StartElement{Name: Name{Local: "bad"}}, + start.End(), + }, + ok: false, + }, + } + for _, tc := range tests { + for _, eof := range []bool{true, false} { + name := fmt.Sprintf("%s/earlyEOF=%v", tc.name, eof) + t.Run(name, func(t *testing.T) { + d := NewTokenDecoder(&toks{ + earlyEOF: eof, + t: tc.tokens, + }) + err := d.Decode(&struct { + XMLName Name `xml:"test"` + }{}) + if tc.ok && err != nil { + t.Fatalf("d.Decode: expected nil error, got %v", err) + } + if _, ok := err.(*SyntaxError); !tc.ok && !ok { + t.Errorf("d.Decode: expected syntax error, got %v", err) + } + }) } - }) - t.Run("LateEOF", func(t *testing.T) { - d := NewTokenDecoder(&toks{t: []Token{ - start, - start.End(), - }}) - err := d.Decode(&struct { - XMLName Name `xml:"test"` - }{}) - if err != nil { - t.Error(err) + } +} + +type toksNil struct { + returnEOF bool + t []Token +} + +func (t *toksNil) Token() (Token, error) { + if len(t.t) == 0 { + if !t.returnEOF { + // Return nil, nil before returning an EOF. It's legal, but + // discouraged. + t.returnEOF = true + return nil, nil } - }) + return nil, io.EOF + } + var tok Token + tok, t.t = t.t[0], t.t[1:] + return tok, nil +} + +func TestDecodeNilToken(t *testing.T) { + for _, strict := range []bool{true, false} { + name := fmt.Sprintf("Strict=%v", strict) + t.Run(name, func(t *testing.T) { + start := StartElement{Name: Name{Local: "test"}} + bad := StartElement{Name: Name{Local: "bad"}} + d := NewTokenDecoder(&toksNil{ + // Malformed + t: []Token{start, bad, start.End()}, + }) + d.Strict = strict + err := d.Decode(&struct { + XMLName Name `xml:"test"` + }{}) + if _, ok := err.(*SyntaxError); !ok { + t.Errorf("d.Decode: expected syntax error, got %v", err) + } + }) + } } const testInput = ` diff --git a/libgo/go/go/build/build_test.go b/libgo/go/go/build/build_test.go index 490c212642c..1c0dc4692c9 100644 --- a/libgo/go/go/build/build_test.go +++ b/libgo/go/go/build/build_test.go @@ -614,7 +614,7 @@ func TestImportPackageOutsideModule(t *testing.T) { ctxt.GOPATH = gopath ctxt.Dir = filepath.Join(gopath, "src/example.com/p") - want := "working directory is not part of a module" + want := "go.mod file not found in current directory or any parent directory" if _, err := ctxt.Import("example.com/p", gopath, FindOnly); err == nil { t.Fatal("importing package when no go.mod is present succeeded unexpectedly") } else if errStr := err.Error(); !strings.Contains(errStr, want) { diff --git a/libgo/go/golang.org/x/mod/modfile/rule.go b/libgo/go/golang.org/x/mod/modfile/rule.go index c6a189dbe04..f8c93849859 100644 --- a/libgo/go/golang.org/x/mod/modfile/rule.go +++ b/libgo/go/golang.org/x/mod/modfile/rule.go @@ -125,6 +125,12 @@ func (f *File) AddComment(text string) { type VersionFixer func(path, version string) (string, error) +// errDontFix is returned by a VersionFixer to indicate the version should be +// left alone, even if it's not canonical. +var dontFixRetract VersionFixer = func(_, vers string) (string, error) { + return vers, nil +} + // Parse parses the data, reported in errors as being from file, // into a File struct. It applies fix, if non-nil, to canonicalize all module versions found. func Parse(file string, data []byte, fix VersionFixer) (*File, error) { @@ -142,7 +148,7 @@ func ParseLax(file string, data []byte, fix VersionFixer) (*File, error) { return parseToFile(file, data, fix, false) } -func parseToFile(file string, data []byte, fix VersionFixer, strict bool) (*File, error) { +func parseToFile(file string, data []byte, fix VersionFixer, strict bool) (parsed *File, err error) { fs, err := parse(file, data) if err != nil { return nil, err @@ -150,8 +156,18 @@ func parseToFile(file string, data []byte, fix VersionFixer, strict bool) (*File f := &File{ Syntax: fs, } - var errs ErrorList + + // fix versions in retract directives after the file is parsed. + // We need the module path to fix versions, and it might be at the end. + defer func() { + oldLen := len(errs) + f.fixRetract(fix, &errs) + if len(errs) > oldLen { + parsed, err = nil, errs + } + }() + for _, x := range fs.Stmt { switch x := x.(type) { case *Line: @@ -370,7 +386,7 @@ func (f *File) add(errs *ErrorList, block *LineBlock, line *Line, verb string, a case "retract": rationale := parseRetractRationale(block, line) - vi, err := parseVersionInterval(verb, &args, fix) + vi, err := parseVersionInterval(verb, "", &args, dontFixRetract) if err != nil { if strict { wrapError(err) @@ -397,6 +413,47 @@ func (f *File) add(errs *ErrorList, block *LineBlock, line *Line, verb string, a } } +// fixRetract applies fix to each retract directive in f, appending any errors +// to errs. +// +// Most versions are fixed as we parse the file, but for retract directives, +// the relevant module path is the one specified with the module directive, +// and that might appear at the end of the file (or not at all). +func (f *File) fixRetract(fix VersionFixer, errs *ErrorList) { + if fix == nil { + return + } + path := "" + if f.Module != nil { + path = f.Module.Mod.Path + } + var r *Retract + wrapError := func(err error) { + *errs = append(*errs, Error{ + Filename: f.Syntax.Name, + Pos: r.Syntax.Start, + Err: err, + }) + } + + for _, r = range f.Retract { + if path == "" { + wrapError(errors.New("no module directive found, so retract cannot be used")) + return // only print the first one of these + } + + args := r.Syntax.Token + if args[0] == "retract" { + args = args[1:] + } + vi, err := parseVersionInterval("retract", path, &args, fix) + if err != nil { + wrapError(err) + } + r.VersionInterval = vi + } +} + // isIndirect reports whether line has a "// indirect" comment, // meaning it is in go.mod only for its effect on indirect dependencies, // so that it can be dropped entirely once the effective version of the @@ -491,13 +548,13 @@ func AutoQuote(s string) string { return s } -func parseVersionInterval(verb string, args *[]string, fix VersionFixer) (VersionInterval, error) { +func parseVersionInterval(verb string, path string, args *[]string, fix VersionFixer) (VersionInterval, error) { toks := *args if len(toks) == 0 || toks[0] == "(" { return VersionInterval{}, fmt.Errorf("expected '[' or version") } if toks[0] != "[" { - v, err := parseVersion(verb, "", &toks[0], fix) + v, err := parseVersion(verb, path, &toks[0], fix) if err != nil { return VersionInterval{}, err } @@ -509,7 +566,7 @@ func parseVersionInterval(verb string, args *[]string, fix VersionFixer) (Versio if len(toks) == 0 { return VersionInterval{}, fmt.Errorf("expected version after '['") } - low, err := parseVersion(verb, "", &toks[0], fix) + low, err := parseVersion(verb, path, &toks[0], fix) if err != nil { return VersionInterval{}, err } @@ -523,7 +580,7 @@ func parseVersionInterval(verb string, args *[]string, fix VersionFixer) (Versio if len(toks) == 0 { return VersionInterval{}, fmt.Errorf("expected version after ','") } - high, err := parseVersion(verb, "", &toks[0], fix) + high, err := parseVersion(verb, path, &toks[0], fix) if err != nil { return VersionInterval{}, err } @@ -631,8 +688,7 @@ func parseVersion(verb string, path string, s *string, fix VersionFixer) (string } } if fix != nil { - var err error - t, err = fix(path, t) + fixed, err := fix(path, t) if err != nil { if err, ok := err.(*module.ModuleError); ok { return "", &Error{ @@ -643,19 +699,23 @@ func parseVersion(verb string, path string, s *string, fix VersionFixer) (string } return "", err } + t = fixed + } else { + cv := module.CanonicalVersion(t) + if cv == "" { + return "", &Error{ + Verb: verb, + ModPath: path, + Err: &module.InvalidVersionError{ + Version: t, + Err: errors.New("must be of the form v1.2.3"), + }, + } + } + t = cv } - if v := module.CanonicalVersion(t); v != "" { - *s = v - return *s, nil - } - return "", &Error{ - Verb: verb, - ModPath: path, - Err: &module.InvalidVersionError{ - Version: t, - Err: errors.New("must be of the form v1.2.3"), - }, - } + *s = t + return *s, nil } func modulePathMajor(path string) (string, error) { @@ -835,11 +895,8 @@ func (f *File) DropRequire(path string) error { // AddExclude adds a exclude statement to the mod file. Errors if the provided // version is not a canonical version string func (f *File) AddExclude(path, vers string) error { - if !isCanonicalVersion(vers) { - return &module.InvalidVersionError{ - Version: vers, - Err: errors.New("must be of the form v1.2.3"), - } + if err := checkCanonicalVersion(path, vers); err != nil { + return err } var hint *Line @@ -916,17 +973,15 @@ func (f *File) DropReplace(oldPath, oldVers string) error { // AddRetract adds a retract statement to the mod file. Errors if the provided // version interval does not consist of canonical version strings func (f *File) AddRetract(vi VersionInterval, rationale string) error { - if !isCanonicalVersion(vi.High) { - return &module.InvalidVersionError{ - Version: vi.High, - Err: errors.New("must be of the form v1.2.3"), - } + var path string + if f.Module != nil { + path = f.Module.Mod.Path } - if !isCanonicalVersion(vi.Low) { - return &module.InvalidVersionError{ - Version: vi.Low, - Err: errors.New("must be of the form v1.2.3"), - } + if err := checkCanonicalVersion(path, vi.High); err != nil { + return err + } + if err := checkCanonicalVersion(path, vi.Low); err != nil { + return err } r := &Retract{ @@ -1086,8 +1141,40 @@ func lineRetractLess(li, lj *Line) bool { return semver.Compare(vii.High, vij.High) > 0 } -// isCanonicalVersion tests if the provided version string represents a valid -// canonical version. -func isCanonicalVersion(vers string) bool { - return vers != "" && semver.Canonical(vers) == vers +// checkCanonicalVersion returns a non-nil error if vers is not a canonical +// version string or does not match the major version of path. +// +// If path is non-empty, the error text suggests a format with a major version +// corresponding to the path. +func checkCanonicalVersion(path, vers string) error { + _, pathMajor, pathMajorOk := module.SplitPathVersion(path) + + if vers == "" || vers != module.CanonicalVersion(vers) { + if pathMajor == "" { + return &module.InvalidVersionError{ + Version: vers, + Err: fmt.Errorf("must be of the form v1.2.3"), + } + } + return &module.InvalidVersionError{ + Version: vers, + Err: fmt.Errorf("must be of the form %s.2.3", module.PathMajorPrefix(pathMajor)), + } + } + + if pathMajorOk { + if err := module.CheckPathMajor(vers, pathMajor); err != nil { + if pathMajor == "" { + // In this context, the user probably wrote "v2.3.4" when they meant + // "v2.3.4+incompatible". Suggest that instead of "v0 or v1". + return &module.InvalidVersionError{ + Version: vers, + Err: fmt.Errorf("should be %s+incompatible (or module %s/%v)", vers, path, semver.Major(vers)), + } + } + return err + } + } + + return nil } diff --git a/libgo/go/golang.org/x/mod/module/module.go b/libgo/go/golang.org/x/mod/module/module.go index c1c5263c427..272baeef176 100644 --- a/libgo/go/golang.org/x/mod/module/module.go +++ b/libgo/go/golang.org/x/mod/module/module.go @@ -270,7 +270,7 @@ func fileNameOK(r rune) bool { // CheckPath checks that a module path is valid. // A valid module path is a valid import path, as checked by CheckImportPath, -// with two additional constraints. +// with three additional constraints. // First, the leading path element (up to the first slash, if any), // by convention a domain name, must contain only lower-case ASCII letters, // ASCII digits, dots (U+002E), and dashes (U+002D); @@ -280,8 +280,9 @@ func fileNameOK(r rune) bool { // and must not contain any dots. For paths beginning with "gopkg.in/", // this second requirement is replaced by a requirement that the path // follow the gopkg.in server's conventions. +// Third, no path element may begin with a dot. func CheckPath(path string) error { - if err := checkPath(path, false); err != nil { + if err := checkPath(path, modulePath); err != nil { return fmt.Errorf("malformed module path %q: %v", path, err) } i := strings.Index(path, "/") @@ -315,7 +316,7 @@ func CheckPath(path string) error { // // A valid path element is a non-empty string made up of // ASCII letters, ASCII digits, and limited ASCII punctuation: - . _ and ~. -// It must not begin or end with a dot (U+002E), nor contain two dots in a row. +// It must not end with a dot (U+002E), nor contain two dots in a row. // // The element prefix up to the first dot must not be a reserved file name // on Windows, regardless of case (CON, com1, NuL, and so on). The element @@ -326,19 +327,29 @@ func CheckPath(path string) error { // top-level package documentation for additional information about // subtleties of Unicode. func CheckImportPath(path string) error { - if err := checkPath(path, false); err != nil { + if err := checkPath(path, importPath); err != nil { return fmt.Errorf("malformed import path %q: %v", path, err) } return nil } +// pathKind indicates what kind of path we're checking. Module paths, +// import paths, and file paths have different restrictions. +type pathKind int + +const ( + modulePath pathKind = iota + importPath + filePath +) + // checkPath checks that a general path is valid. // It returns an error describing why but not mentioning path. // Because these checks apply to both module paths and import paths, // the caller is expected to add the "malformed ___ path %q: " prefix. // fileName indicates whether the final element of the path is a file name // (as opposed to a directory name). -func checkPath(path string, fileName bool) error { +func checkPath(path string, kind pathKind) error { if !utf8.ValidString(path) { return fmt.Errorf("invalid UTF-8") } @@ -357,35 +368,34 @@ func checkPath(path string, fileName bool) error { elemStart := 0 for i, r := range path { if r == '/' { - if err := checkElem(path[elemStart:i], fileName); err != nil { + if err := checkElem(path[elemStart:i], kind); err != nil { return err } elemStart = i + 1 } } - if err := checkElem(path[elemStart:], fileName); err != nil { + if err := checkElem(path[elemStart:], kind); err != nil { return err } return nil } // checkElem checks whether an individual path element is valid. -// fileName indicates whether the element is a file name (not a directory name). -func checkElem(elem string, fileName bool) error { +func checkElem(elem string, kind pathKind) error { if elem == "" { return fmt.Errorf("empty path element") } if strings.Count(elem, ".") == len(elem) { return fmt.Errorf("invalid path element %q", elem) } - if elem[0] == '.' && !fileName { + if elem[0] == '.' && kind == modulePath { return fmt.Errorf("leading dot in path element") } if elem[len(elem)-1] == '.' { return fmt.Errorf("trailing dot in path element") } charOK := pathOK - if fileName { + if kind == filePath { charOK = fileNameOK } for _, r := range elem { @@ -406,7 +416,7 @@ func checkElem(elem string, fileName bool) error { } } - if fileName { + if kind == filePath { // don't check for Windows short-names in file names. They're // only an issue for import paths. return nil @@ -444,7 +454,7 @@ func checkElem(elem string, fileName bool) error { // top-level package documentation for additional information about // subtleties of Unicode. func CheckFilePath(path string) error { - if err := checkPath(path, true); err != nil { + if err := checkPath(path, filePath); err != nil { return fmt.Errorf("malformed file path %q: %v", path, err) } return nil @@ -647,7 +657,7 @@ func EscapePath(path string) (escaped string, err error) { // Versions are allowed to be in non-semver form but must be valid file names // and not contain exclamation marks. func EscapeVersion(v string) (escaped string, err error) { - if err := checkElem(v, true); err != nil || strings.Contains(v, "!") { + if err := checkElem(v, filePath); err != nil || strings.Contains(v, "!") { return "", &InvalidVersionError{ Version: v, Err: fmt.Errorf("disallowed version string"), @@ -706,7 +716,7 @@ func UnescapeVersion(escaped string) (v string, err error) { if !ok { return "", fmt.Errorf("invalid escaped version %q", escaped) } - if err := checkElem(v, true); err != nil { + if err := checkElem(v, filePath); err != nil { return "", fmt.Errorf("invalid escaped version %q: %v", v, err) } return v, nil diff --git a/libgo/go/time/zoneinfo.go b/libgo/go/time/zoneinfo.go index c3662297c7d..6db94434747 100644 --- a/libgo/go/time/zoneinfo.go +++ b/libgo/go/time/zoneinfo.go @@ -377,8 +377,10 @@ func tzsetOffset(s string) (offset int, rest string, ok bool) { neg = true } + // The tzdata code permits values up to 24 * 7 here, + // although POSIX does not. var hours int - hours, s, ok = tzsetNum(s, 0, 24) + hours, s, ok = tzsetNum(s, 0, 24*7) if !ok { return 0, "", false } @@ -487,7 +489,7 @@ func tzsetRule(s string) (rule, string, bool) { } offset, s, ok := tzsetOffset(s[1:]) - if !ok || offset < 0 { + if !ok { return rule{}, "", false } r.time = offset diff --git a/libgo/go/time/zoneinfo_test.go b/libgo/go/time/zoneinfo_test.go index d543f93e3b7..3e32da02b2e 100644 --- a/libgo/go/time/zoneinfo_test.go +++ b/libgo/go/time/zoneinfo_test.go @@ -189,22 +189,50 @@ func TestMalformedTZData(t *testing.T) { } } +var slimTests = []struct { + zoneName string + tzData string + wantName string + wantOffset int +}{ + { + // 2020b slim tzdata for Europe/Berlin. + zoneName: "Europe/Berlin", + tzData: "TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00<\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xffo\xa2a\xf8\xff\xff\xff\xff\x9b\f\x17`\xff\xff\xff\xff\x9b\xd5\xda\xf0\xff\xff\xff\xff\x9cٮ\x90\xff\xff\xff\xff\x9d\xa4\xb5\x90\xff\xff\xff\xff\x9e\xb9\x90\x90\xff\xff\xff\xff\x9f\x84\x97\x90\xff\xff\xff\xff\xc8\tq\x90\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xffͩ\x17\x90\xff\xff\xff\xff\u03a2C\x10\xff\xff\xff\xffϒ4\x10\xff\xff\xff\xffЂ%\x10\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xffѶ\x96\x00\xff\xff\xff\xff\xd2X\xbe\x80\xff\xff\xff\xffҡO\x10\xff\xff\xff\xff\xd3c\x1b\x90\xff\xff\xff\xff\xd4K#\x90\xff\xff\xff\xff\xd59\xd1 \xff\xff\xff\xff\xd5g\xe7\x90\xff\xff\xff\xffըs\x00\xff\xff\xff\xff\xd6)\xb4\x10\xff\xff\xff\xff\xd7,\x1a\x10\xff\xff\xff\xff\xd8\t\x96\x10\xff\xff\xff\xff\xd9\x02\xc1\x90\xff\xff\xff\xff\xd9\xe9x\x10\x00\x00\x00\x00\x13MD\x10\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13ܐ\x00\x00\x00\x00\x17\x03͐\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18㯐\x00\x00\x00\x00\x19Ӡ\x90\x00\x00\x00\x00\x1aÑ\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\\c\x10\x00\x00\x00\x00\"LT\x10\x00\x00\x00\x00#3<-02>,M3.5.0/-2,M10.5.0/-1\n", + wantName: "-03", + wantOffset: -10800, + }, + { + // 2021a slim tzdata for Asia/Gaza. + zoneName: "Asia/Gaza", + tzData: "TZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00s\x00\x00\x00\x05\x00\x00\x00\x15\xff\xff\xff\xff}\xbdJ\xb0\xff\xff\xff\xff\xc8Y\xcf\x00\xff\xff\xff\xff\xc8\xfa\xa6\x00\xff\xff\xff\xff\xc98\x9c\x80\xff\xff\xff\xff\xcc\xe5\xeb\x80\xff\xff\xff\xffͬ\xfe\x00\xff\xff\xff\xff\xce\xc7\x1f\x00\xff\xff\xff\xffϏ\x83\x00\xff\xff\xff\xffЩ\xa4\x00\xff\xff\xff\xffф}\x00\xff\xff\xff\xffҊ׀\xff\xff\xff\xff\xd3e\xb0\x80\xff\xff\xff\xff\xd4l\v\x00\xff\xff\xff\xff\xe86c`\xff\xff\xff\xff\xe8\xf4-P\xff\xff\xff\xff\xea\v\xb9`\xff\xff\xff\xff\xea\xd5`\xd0\xff\xff\xff\xff\xeb\xec\xfa\xf0\xff\xff\xff\xff\xec\xb5m\x00\xff\xff\xff\xff\xed\xcf\u007f\xf0\xff\xff\xff\xff\xee\x97\xf2\x00\xff\xff\xff\xffﰳp\xff\xff\xff\xff\xf0y%\x80\xff\xff\xff\xff\xf1\x91\xe6\xf0\xff\xff\xff\xff\xf2ZY\x00\xff\xff\xff\xff\xf3s\x1ap\xff\xff\xff\xff\xf4;\x8c\x80\xff\xff\xff\xff\xf5U\x9fp\xff\xff\xff\xff\xf6\x1e\x11\x80\xff\xff\xff\xff\xf76\xd2\xf0\xff\xff\xff\xff\xf7\xffE\x00\xff\xff\xff\xff\xf9\x18\x06p\xff\xff\xff\xff\xf9\xe1\xca\x00\xff\xff\xff\xff\xfa\xf99\xf0\xff\xff\xff\xff\xfb'BP\x00\x00\x00\x00\b|\x8b\xe0\x00\x00\x00\x00\b\xfd\xb0\xd0\x00\x00\x00\x00\t\xf6\xea`\x00\x00\x00\x00\n\xa63\xd0\x00\x00\x00\x00\x13\xe9\xfc`\x00\x00\x00\x00\x14![`\x00\x00\x00\x00\x1a\xfa\xc6`\x00\x00\x00\x00\x1b\x8en`\x00\x00\x00\x00\x1c\xbe\xf8\xe0\x00\x00\x00\x00\x1dw|\xd0\x00\x00\x00\x00\x1e\xcc\xff`\x00\x00\x00\x00\x1f`\x99P\x00\x00\x00\x00 \x82\xb1`\x00\x00\x00\x00!I\xb5\xd0\x00\x00\x00\x00\"^\x9e\xe0\x00\x00\x00\x00# ]P\x00\x00\x00\x00$Z0`\x00\x00\x00\x00%\x00?P\x00\x00\x00\x00&\v\xed\xe0\x00\x00\x00\x00&\xd6\xe6\xd0\x00\x00\x00\x00'\xeb\xcf\xe0\x00\x00\x00\x00(\xc0\x03P\x00\x00\x00\x00)\xd4\xec`\x00\x00\x00\x00*\xa9\x1f\xd0\x00\x00\x00\x00+\xbbe\xe0\x00\x00\x00\x00,\x89\x01\xd0\x00\x00\x00\x00-\x9bG\xe0\x00\x00\x00\x00._\xa9P\x00\x00\x00\x00/{)\xe0\x00\x00\x00\x000H\xc5\xd0\x00\x00\x00\x000\xe7\a\xe0\x00\x00\x00\x001dF`\x00\x00\x00\x002A\xc2`\x00\x00\x00\x003D(`\x00\x00\x00\x004!\xa4`\x00\x00\x00\x005$\n`\x00\x00\x00\x006\x01\x86`\x00\x00\x00\x007\x16a`\x00\x00\x00\x008\x06DP\x00\x00\x00\x008\xff}\xe0\x00\x00\x00\x009\xef`\xd0\x00\x00\x00\x00:\xdf_\xe0\x00\x00\x00\x00;\xcfB\xd0\x00\x00\x00\x00<\xbfA\xe0\x00\x00\x00\x00=\xaf$\xd0\x00\x00\x00\x00>\x9f#\xe0\x00\x00\x00\x00?\x8f\x06\xd0\x00\x00\x00\x00@\u007f\x05\xe0\x00\x00\x00\x00A\\\x81\xe0\x00\x00\x00\x00B^\xe7\xe0\x00\x00\x00\x00CA\xb7\xf0\x00\x00\x00\x00D-\xa6`\x00\x00\x00\x00E\x12\xfdP\x00\x00\x00\x00F\x0e\xd9\xe0\x00\x00\x00\x00F\xe8op\x00\x00\x00\x00G\xec\x18\xe0\x00\x00\x00\x00H\xb7\x11\xd0\x00\x00\x00\x00I\xcb\xfa\xe0\x00\x00\x00\x00J\xa0<`\x00\x00\x00\x00K\xad.\x9c\x00\x00\x00\x00La\xbd\xd0\x00\x00\x00\x00M\x94\xf9\x9c\x00\x00\x00\x00N5\xc2P\x00\x00\x00\x00Ot\xdb`\x00\x00\x00\x00P[\x91\xe0\x00\x00\x00\x00QT\xbd`\x00\x00\x00\x00RD\xa0P\x00\x00\x00\x00S4\x9f`\x00\x00\x00\x00TIlP\x00\x00\x00\x00U\x15\xd2\xe0\x00\x00\x00\x00V)\\`\x00\x00\x00\x00V\xf5\xc2\xf0\x00\x00\x00\x00X\x13\xca`\x00\x00\x00\x00Xդ\xf0\x00\x00\x00\x00Y\xf3\xac`\x00\x00\x00\x00Z\xb5\x86\xf0\x00\x00\x00\x00[ӎ`\x00\x00\x00\x00\\\x9dC\xe0\x00\x00\x00\x00]\xb3bP\x00\x00\x00\x00^~w`\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x00\x00 P\x00\x00\x00\x00*0\x01\x04\x00\x00\x1c \x00\t\x00\x00*0\x01\r\x00\x00\x1c \x00\x11LMT\x00EEST\x00EET\x00IDT\x00IST\x00\nEET-2EEST,M3.4.4/48,M10.4.4/49\n", + wantName: "EET", + wantOffset: 7200, + }, +} + func TestLoadLocationFromTZDataSlim(t *testing.T) { - // A 2020b slim tzdata for Europe/Berlin - tzData := "TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00<\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xffo\xa2a\xf8\xff\xff\xff\xff\x9b\f\x17`\xff\xff\xff\xff\x9b\xd5\xda\xf0\xff\xff\xff\xff\x9cٮ\x90\xff\xff\xff\xff\x9d\xa4\xb5\x90\xff\xff\xff\xff\x9e\xb9\x90\x90\xff\xff\xff\xff\x9f\x84\x97\x90\xff\xff\xff\xff\xc8\tq\x90\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xffͩ\x17\x90\xff\xff\xff\xff\u03a2C\x10\xff\xff\xff\xffϒ4\x10\xff\xff\xff\xffЂ%\x10\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xffѶ\x96\x00\xff\xff\xff\xff\xd2X\xbe\x80\xff\xff\xff\xffҡO\x10\xff\xff\xff\xff\xd3c\x1b\x90\xff\xff\xff\xff\xd4K#\x90\xff\xff\xff\xff\xd59\xd1 \xff\xff\xff\xff\xd5g\xe7\x90\xff\xff\xff\xffըs\x00\xff\xff\xff\xff\xd6)\xb4\x10\xff\xff\xff\xff\xd7,\x1a\x10\xff\xff\xff\xff\xd8\t\x96\x10\xff\xff\xff\xff\xd9\x02\xc1\x90\xff\xff\xff\xff\xd9\xe9x\x10\x00\x00\x00\x00\x13MD\x10\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13ܐ\x00\x00\x00\x00\x17\x03͐\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18㯐\x00\x00\x00\x00\x19Ӡ\x90\x00\x00\x00\x00\x1aÑ\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\\c\x10\x00\x00\x00\x00\"LT\x10\x00\x00\x00\x00#