From: Ian Lance Taylor Date: Fri, 19 Feb 2021 02:54:38 +0000 (-0800) Subject: libgo: update to Go1.16 release X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=13e6fadd96dc00c611a3d2f26a1a6d7a0a29ea27;p=gcc.git libgo: update to Go1.16 release Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/293793 --- diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index eed9ce01905..217bdd55f1d 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -c406de0594782b1d6782a732a50f5b76387852dc +78a840e4940159a66072237f6b002ab79f441b79 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 b2fc633f06c..183b0245ee2 100644 --- a/libgo/MERGE +++ b/libgo/MERGE @@ -1,4 +1,4 @@ -3e06467282c6d5678a6273747658c04314e013ef +f21be2fdc6f1becdbed1592ea0b245cdeedc5ac8 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 a19294250b3..4befab24bc9 100644 --- a/libgo/VERSION +++ b/libgo/VERSION @@ -1 +1 @@ -go1.16rc1 +go1.16 diff --git a/libgo/go/archive/tar/strconv.go b/libgo/go/archive/tar/strconv.go index 6d0a4038082..f0b61e6dba6 100644 --- a/libgo/go/archive/tar/strconv.go +++ b/libgo/go/archive/tar/strconv.go @@ -265,8 +265,27 @@ func parsePAXRecord(s string) (k, v, r string, err error) { return "", "", s, ErrHeader } + afterSpace := int64(sp + 1) + beforeLastNewLine := n - 1 + // In some cases, "length" was perhaps padded/malformed, and + // trying to index past where the space supposedly is goes past + // the end of the actual record. + // For example: + // "0000000000000000000000000000000030 mtime=1432668921.098285006\n30 ctime=2147483649.15163319" + // ^ ^ + // | | + // | afterSpace=35 + // | + // beforeLastNewLine=29 + // yet indexOf(firstSpace) MUST BE before endOfRecord. + // + // See https://golang.org/issues/40196. + if afterSpace >= beforeLastNewLine { + return "", "", s, ErrHeader + } + // Extract everything between the space and the final newline. - rec, nl, rem := s[sp+1:n-1], s[n-1:n], s[n:] + rec, nl, rem := s[afterSpace:beforeLastNewLine], s[beforeLastNewLine:n], s[n:] if nl != "\n" { return "", "", s, ErrHeader } diff --git a/libgo/go/archive/tar/strconv_test.go b/libgo/go/archive/tar/strconv_test.go index dd3505a758a..add65e272ae 100644 --- a/libgo/go/archive/tar/strconv_test.go +++ b/libgo/go/archive/tar/strconv_test.go @@ -368,6 +368,13 @@ func TestParsePAXRecord(t *testing.T) { {"16 longkeyname=hahaha\n", "16 longkeyname=hahaha\n", "", "", false}, {"3 somelongkey=\n", "3 somelongkey=\n", "", "", false}, {"50 tooshort=\n", "50 tooshort=\n", "", "", false}, + {"0000000000000000000000000000000030 mtime=1432668921.098285006\n30 ctime=2147483649.15163319", "0000000000000000000000000000000030 mtime=1432668921.098285006\n30 ctime=2147483649.15163319", "mtime", "1432668921.098285006", false}, + {"06 k=v\n", "06 k=v\n", "", "", false}, + {"00006 k=v\n", "00006 k=v\n", "", "", false}, + {"000006 k=v\n", "000006 k=v\n", "", "", false}, + {"000000 k=v\n", "000000 k=v\n", "", "", false}, + {"0 k=v\n", "0 k=v\n", "", "", false}, + {"+0000005 x=\n", "+0000005 x=\n", "", "", false}, } for _, v := range vectors { diff --git a/libgo/go/cmd/go/alldocs.go b/libgo/go/cmd/go/alldocs.go index 49d390297cd..e7c63f0749d 100644 --- a/libgo/go/cmd/go/alldocs.go +++ b/libgo/go/cmd/go/alldocs.go @@ -1808,7 +1808,7 @@ // The directory where the go command will write // temporary source files, packages, and binaries. // GOVCS -// Lists version control commands that may be used with matching servers. +// Lists version control commands that may be used with matching servers. // See 'go help vcs'. // // Environment variables for use with cgo: @@ -2410,6 +2410,17 @@ // // For a detailed reference on modules, see https://golang.org/ref/mod. // +// By default, the go command may download modules from https://proxy.golang.org. +// It may authenticate modules using the checksum database at +// https://sum.golang.org. Both services are operated by the Go team at Google. +// The privacy policies for these services are available at +// https://proxy.golang.org/privacy and https://sum.golang.org/privacy, +// respectively. +// +// The go command's download behavior may be configured using GOPROXY, GOSUMDB, +// GOPRIVATE, and other environment variables. See 'go help environment' +// and https://golang.org/ref/mod#private-module-privacy for more information. +// // // Module authentication using go.sum // @@ -2868,20 +2879,23 @@ // legal reasons). Therefore, clients can still access public code served from // Bazaar, Fossil, or Subversion repositories by default, because those downloads // use the Go module mirror, which takes on the security risk of running the -// version control commands, using a custom sandbox. +// version control commands using a custom sandbox. // // The GOVCS variable can be used to change the allowed version control systems // for specific packages (identified by a module or import path). -// The GOVCS variable applies both when using modules and when using GOPATH. -// When using modules, the patterns match against the module path. -// When using GOPATH, the patterns match against the import path -// corresponding to the root of the version control repository. +// The GOVCS variable applies when building package in both module-aware mode +// and GOPATH mode. When using modules, the patterns match against the module path. +// When using GOPATH, the patterns match against the import path corresponding to +// the root of the version control repository. // // The general form of the GOVCS setting is a comma-separated list of // pattern:vcslist rules. The pattern is a glob pattern that must match // one or more leading elements of the module or import path. The vcslist // is a pipe-separated list of allowed version control commands, or "all" -// to allow use of any known command, or "off" to allow nothing. +// to allow use of any known command, or "off" to disallow all commands. +// Note that if a module matches a pattern with vcslist "off", it may still be +// downloaded if the origin server uses the "mod" scheme, which instructs the +// go command to download the module using the GOPROXY protocol. // The earliest matching pattern in the list applies, even if later patterns // might also match. // @@ -2889,7 +2903,7 @@ // // GOVCS=github.com:git,evil.com:off,*:git|hg // -// With this setting, code with an module or import path beginning with +// With this setting, code with a module or import path beginning with // github.com/ can only use git; paths on evil.com cannot use any version // control command, and all other paths (* matches everything) can use // only git or hg. diff --git a/libgo/go/cmd/go/internal/help/helpdoc.go b/libgo/go/cmd/go/internal/help/helpdoc.go index e07ad0e1db1..57cee4ff96c 100644 --- a/libgo/go/cmd/go/internal/help/helpdoc.go +++ b/libgo/go/cmd/go/internal/help/helpdoc.go @@ -542,7 +542,7 @@ General-purpose environment variables: The directory where the go command will write temporary source files, packages, and binaries. GOVCS - Lists version control commands that may be used with matching servers. + Lists version control commands that may be used with matching servers. See 'go help vcs'. Environment variables for use with cgo: diff --git a/libgo/go/cmd/go/internal/load/pkg.go b/libgo/go/cmd/go/internal/load/pkg.go index 8757d666fb2..e83f1d2cea9 100644 --- a/libgo/go/cmd/go/internal/load/pkg.go +++ b/libgo/go/cmd/go/internal/load/pkg.go @@ -36,6 +36,8 @@ import ( "cmd/go/internal/str" "cmd/go/internal/trace" "cmd/internal/sys" + + "golang.org/x/mod/module" ) var IgnoreImports bool // control whether we ignore imports in packages @@ -2096,6 +2098,9 @@ func validEmbedPattern(pattern string) bool { // can't or won't be included in modules and therefore shouldn't be treated // as existing for embedding. func isBadEmbedName(name string) bool { + if err := module.CheckFilePath(name); err != nil { + return true + } switch name { // Empty string should be impossible but make it bad. case "": diff --git a/libgo/go/cmd/go/internal/modget/get.go b/libgo/go/cmd/go/internal/modget/get.go index 574f3e194d1..dccacd3d1ee 100644 --- a/libgo/go/cmd/go/internal/modget/get.go +++ b/libgo/go/cmd/go/internal/modget/get.go @@ -176,20 +176,23 @@ packages or when the mirror refuses to serve a public package (typically for legal reasons). Therefore, clients can still access public code served from Bazaar, Fossil, or Subversion repositories by default, because those downloads use the Go module mirror, which takes on the security risk of running the -version control commands, using a custom sandbox. +version control commands using a custom sandbox. The GOVCS variable can be used to change the allowed version control systems for specific packages (identified by a module or import path). -The GOVCS variable applies both when using modules and when using GOPATH. -When using modules, the patterns match against the module path. -When using GOPATH, the patterns match against the import path -corresponding to the root of the version control repository. +The GOVCS variable applies when building package in both module-aware mode +and GOPATH mode. When using modules, the patterns match against the module path. +When using GOPATH, the patterns match against the import path corresponding to +the root of the version control repository. The general form of the GOVCS setting is a comma-separated list of pattern:vcslist rules. The pattern is a glob pattern that must match one or more leading elements of the module or import path. The vcslist is a pipe-separated list of allowed version control commands, or "all" -to allow use of any known command, or "off" to allow nothing. +to allow use of any known command, or "off" to disallow all commands. +Note that if a module matches a pattern with vcslist "off", it may still be +downloaded if the origin server uses the "mod" scheme, which instructs the +go command to download the module using the GOPROXY protocol. The earliest matching pattern in the list applies, even if later patterns might also match. @@ -197,7 +200,7 @@ For example, consider: GOVCS=github.com:git,evil.com:off,*:git|hg -With this setting, code with an module or import path beginning with +With this setting, code with a module or import path beginning with github.com/ can only use git; paths on evil.com cannot use any version control command, and all other paths (* matches everything) can use only git or hg. @@ -380,10 +383,9 @@ func runGet(ctx context.Context, cmd *base.Command, args []string) { pkgs := load.PackagesAndErrors(ctx, pkgPatterns) load.CheckPackageErrors(pkgs) work.InstallPackages(ctx, pkgPatterns, pkgs) - // TODO(#40276): After Go 1.16, print a deprecation notice when building - // and installing main packages. 'go install pkg' or - // 'go install pkg@version' should be used instead. - // Give the specific argument to use if possible. + // TODO(#40276): After Go 1.16, print a deprecation notice when building and + // installing main packages. 'go install pkg' or 'go install pkg@version' + // should be used instead. Give the specific argument to use if possible. } if !modload.HasModRoot() { @@ -1453,7 +1455,18 @@ func (r *resolver) checkPackagesAndRetractions(ctx context.Context, pkgPatterns } } for _, pkg := range pkgs { - if _, _, err := modload.Lookup("", false, pkg); err != nil { + if dir, _, err := modload.Lookup("", false, pkg); err != nil { + if dir != "" && errors.Is(err, imports.ErrNoGo) { + // Since dir is non-empty, we must have located source files + // associated with either the package or its test — ErrNoGo must + // indicate that none of those source files happen to apply in this + // configuration. If we are actually building the package (no -d + // flag), the compiler will report the problem; otherwise, assume that + // the user is going to build or test it in some other configuration + // and suppress the error. + continue + } + base.SetExitStatus(1) if ambiguousErr := (*modload.AmbiguousImportError)(nil); errors.As(err, &ambiguousErr) { for _, m := range ambiguousErr.Modules { diff --git a/libgo/go/cmd/go/internal/modload/help.go b/libgo/go/cmd/go/internal/modload/help.go index 1cb58961bed..fd39ddd94ec 100644 --- a/libgo/go/cmd/go/internal/modload/help.go +++ b/libgo/go/cmd/go/internal/modload/help.go @@ -6,8 +6,6 @@ package modload import "cmd/go/internal/base" -// TODO(rsc): The "module code layout" section needs to be written. - var HelpModules = &base.Command{ UsageLine: "modules", Short: "modules, module versions, and more", @@ -22,6 +20,17 @@ For a series of tutorials on modules, see https://golang.org/doc/tutorial/create-module. For a detailed reference on modules, see https://golang.org/ref/mod. + +By default, the go command may download modules from https://proxy.golang.org. +It may authenticate modules using the checksum database at +https://sum.golang.org. Both services are operated by the Go team at Google. +The privacy policies for these services are available at +https://proxy.golang.org/privacy and https://sum.golang.org/privacy, +respectively. + +The go command's download behavior may be configured using GOPROXY, GOSUMDB, +GOPRIVATE, and other environment variables. See 'go help environment' +and https://golang.org/ref/mod#private-module-privacy for more information. `, } diff --git a/libgo/go/cmd/go/internal/vet/vetflag.go b/libgo/go/cmd/go/internal/vet/vetflag.go index 5bf5cf44467..b5b3c462ff2 100644 --- a/libgo/go/cmd/go/internal/vet/vetflag.go +++ b/libgo/go/cmd/go/internal/vet/vetflag.go @@ -184,7 +184,8 @@ func exitWithUsage() { if vetTool != "" { cmd = vetTool } - fmt.Fprintf(os.Stderr, "Run '%s -help' for the vet tool's flags.\n", cmd) + fmt.Fprintf(os.Stderr, "Run '%s help' for a full list of flags and analyzers.\n", cmd) + fmt.Fprintf(os.Stderr, "Run '%s -help' for an overview.\n", cmd) base.SetExitStatus(2) base.Exit() diff --git a/libgo/go/cmd/go/testdata/script/build_trimpath.txt b/libgo/go/cmd/go/testdata/script/build_trimpath.txt index e1ea0a48b2a..2c3bee8fdc7 100644 --- a/libgo/go/cmd/go/testdata/script/build_trimpath.txt +++ b/libgo/go/cmd/go/testdata/script/build_trimpath.txt @@ -121,6 +121,7 @@ package main import ( "bytes" "fmt" + "io/ioutil" "log" "os" "os/exec" @@ -130,7 +131,7 @@ import ( func main() { exe := os.Args[1] - data, err := os.ReadFile(exe) + data, err := ioutil.ReadFile(exe) if err != nil { log.Fatal(err) } diff --git a/libgo/go/cmd/go/testdata/script/help.txt b/libgo/go/cmd/go/testdata/script/help.txt index 9752ede2e37..26a0194be56 100644 --- a/libgo/go/cmd/go/testdata/script/help.txt +++ b/libgo/go/cmd/go/testdata/script/help.txt @@ -34,9 +34,10 @@ stderr 'Run ''go help mod'' for usage.' # Earlier versions of Go printed the same as 'go -h' here. # Also make sure we print the short help line. ! go vet -h -stderr 'usage: go vet' -stderr 'Run ''go help vet'' for details' -stderr 'Run ''go tool vet -help'' for the vet tool''s flags' +stderr 'usage: go vet .*' +stderr 'Run ''go help vet'' for details.' +stderr 'Run ''go tool vet help'' for a full list of flags and analyzers.' +stderr 'Run ''go tool vet -help'' for an overview.' # Earlier versions of Go printed a large document here, instead of these two # lines. diff --git a/libgo/go/embed/embed.go b/libgo/go/embed/embed.go index cc6855e6a5b..98da870ac6b 100644 --- a/libgo/go/embed/embed.go +++ b/libgo/go/embed/embed.go @@ -9,18 +9,28 @@ // files read from the package directory or subdirectories at compile time. // // For example, here are three ways to embed a file named hello.txt -// and then print its contents at run time: +// and then print its contents at run time. // -// import "embed" +// Embedding one file into a string: +// +// import _ "embed" // // //go:embed hello.txt // var s string // print(s) // +// Embedding one file into a slice of bytes: +// +// import _ "embed" +// // //go:embed hello.txt // var b []byte // print(string(b)) // +// Embedded one or more files into a file system: +// +// import "embed" +// // //go:embed hello.txt // var f embed.FS // data, _ := f.ReadFile("hello.txt") @@ -34,8 +44,8 @@ // The directive must immediately precede a line containing the declaration of a single variable. // Only blank lines and ‘//’ line comments are permitted between the directive and the declaration. // -// The variable must be of type string, []byte, or FS exactly. Named types or type aliases -// derived from those types are not allowed. +// The type of the variable must be a string type, or a slice of a byte type, +// or FS (or an alias of FS). // // For example: // @@ -51,12 +61,15 @@ // The Go build system will recognize the directives and arrange for the declared variable // (in the example above, content) to be populated with the matching files from the file system. // -// The //go:embed directive accepts multiple space-separated patterns for brevity, -// but it can also be repeated, to avoid very long lines when there are many patterns. -// The patterns are interpreted relative to the package directory containing the source file. -// The path separator is a forward slash, even on Windows systems. -// To allow for naming files with spaces in their names, patterns can be written -// as Go double-quoted or back-quoted string literals. +// The //go:embed directive accepts multiple space-separated patterns for +// brevity, but it can also be repeated, to avoid very long lines when there are +// many patterns. The patterns are interpreted relative to the package directory +// containing the source file. The path separator is a forward slash, even on +// Windows systems. Patterns may not contain ‘.’ or ‘..’ or empty path elements, +// nor may they begin or end with a slash. To match everything in the current +// directory, use ‘*’ instead of ‘.’. To allow for naming files with spaces in +// their names, patterns can be written as Go double-quoted or back-quoted +// string literals. // // If a pattern names a directory, all files in the subtree rooted at that directory are // embedded (recursively), except that files with names beginning with ‘.’ or ‘_’ @@ -70,16 +83,13 @@ // // The //go:embed directive can be used with both exported and unexported variables, // depending on whether the package wants to make the data available to other packages. -// Similarly, it can be used with both global and function-local variables, -// depending on what is more convenient in context. +// It can only be used with global variables at package scope, +// not with local variables. // // Patterns must not match files outside the package's module, such as ‘.git/*’ or symbolic links. // Matches for empty directories are ignored. After that, each pattern in a //go:embed line // must match at least one file or non-empty directory. // -// Patterns must not contain ‘.’ or ‘..’ path elements nor begin with a leading slash. -// To match everything in the current directory, use ‘*’ instead of ‘.’. -// // If any patterns are invalid or have invalid matches, the build will fail. // // Strings and Bytes diff --git a/libgo/go/internal/poll/copy_file_range_linux.go b/libgo/go/internal/poll/copy_file_range_linux.go index fc34aef4cba..01b242a4ea4 100644 --- a/libgo/go/internal/poll/copy_file_range_linux.go +++ b/libgo/go/internal/poll/copy_file_range_linux.go @@ -112,7 +112,15 @@ func CopyFileRange(dst, src *FD, remain int64) (written int64, handled bool, err return 0, false, nil case nil: if n == 0 { - // src is at EOF, which means we are done. + // If we did not read any bytes at all, + // then this file may be in a file system + // where copy_file_range silently fails. + // https://lore.kernel.org/linux-fsdevel/20210126233840.GG4626@dread.disaster.area/T/#m05753578c7f7882f6e9ffe01f981bc223edef2b0 + if written == 0 { + return 0, false, nil + } + // Otherwise src is at EOF, which means + // we are done. return written, true, nil } remain -= n diff --git a/libgo/go/internal/poll/sendfile_bsd.go b/libgo/go/internal/poll/sendfile_bsd.go index a24e41dcaa8..66005a9f5c9 100644 --- a/libgo/go/internal/poll/sendfile_bsd.go +++ b/libgo/go/internal/poll/sendfile_bsd.go @@ -18,6 +18,10 @@ func SendFile(dstFD *FD, src int, pos, remain int64) (int64, error) { return 0, err } defer dstFD.writeUnlock() + if err := dstFD.pd.prepareWrite(dstFD.isFile); err != nil { + return 0, err + } + dst := int(dstFD.Sysfd) var written int64 var err error diff --git a/libgo/go/internal/poll/sendfile_glibc.go b/libgo/go/internal/poll/sendfile_glibc.go index 6652e3fedc1..d95e496a265 100644 --- a/libgo/go/internal/poll/sendfile_glibc.go +++ b/libgo/go/internal/poll/sendfile_glibc.go @@ -18,6 +18,9 @@ func SendFile(dstFD *FD, src int, remain int64) (int64, error) { return 0, err } defer dstFD.writeUnlock() + if err := dstFD.pd.prepareWrite(dstFD.isFile); err != nil { + return 0, err + } dst := int(dstFD.Sysfd) var written int64 @@ -34,6 +37,9 @@ func SendFile(dstFD *FD, src int, remain int64) (int64, error) { } else if n == 0 && err1 == nil { break } + if err1 == syscall.EINTR { + continue + } if err1 == syscall.EAGAIN { if err1 = dstFD.pd.waitWrite(dstFD.isFile); err1 == nil { continue diff --git a/libgo/go/internal/poll/sendfile_solaris.go b/libgo/go/internal/poll/sendfile_solaris.go index 762992e9eb3..748c85131e6 100644 --- a/libgo/go/internal/poll/sendfile_solaris.go +++ b/libgo/go/internal/poll/sendfile_solaris.go @@ -20,6 +20,9 @@ func SendFile(dstFD *FD, src int, pos, remain int64) (int64, error) { return 0, err } defer dstFD.writeUnlock() + if err := dstFD.pd.prepareWrite(dstFD.isFile); err != nil { + return 0, err + } dst := int(dstFD.Sysfd) var written int64 diff --git a/libgo/go/io/fs/fs.go b/libgo/go/io/fs/fs.go index b691a860498..3d2e2ee2ac9 100644 --- a/libgo/go/io/fs/fs.go +++ b/libgo/go/io/fs/fs.go @@ -10,6 +10,7 @@ package fs import ( "internal/oserror" "time" + "unicode/utf8" ) // An FS provides access to a hierarchical file system. @@ -32,14 +33,22 @@ type FS interface { // ValidPath reports whether the given path name // is valid for use in a call to Open. -// Path names passed to open are unrooted, slash-separated -// sequences of path elements, like “x/y/z”. -// Path names must not contain a “.” or “..” or empty element, +// +// Path names passed to open are UTF-8-encoded, +// unrooted, slash-separated sequences of path elements, like “x/y/z”. +// Path names must not contain an element that is “.” or “..” or the empty string, // except for the special case that the root directory is named “.”. +// Paths must not start or end with a slash: “/x” and “x/” are invalid. // -// Paths are slash-separated on all systems, even Windows. -// Backslashes must not appear in path names. +// Note that paths are slash-separated on all systems, even Windows. +// Paths containing other characters such as backslash and colon +// are accepted as valid, but those characters must never be +// interpreted by an FS implementation as path element separators. func ValidPath(name string) bool { + if !utf8.ValidString(name) { + return false + } + if name == "." { // special case return true @@ -49,9 +58,6 @@ func ValidPath(name string) bool { for { i := 0 for i < len(name) && name[i] != '/' { - if name[i] == '\\' { - return false - } i++ } elem := name[:i] diff --git a/libgo/go/io/fs/fs_test.go b/libgo/go/io/fs/fs_test.go index 8d395fc0db1..aae1a7606f4 100644 --- a/libgo/go/io/fs/fs_test.go +++ b/libgo/go/io/fs/fs_test.go @@ -33,9 +33,10 @@ var isValidPathTests = []struct { {"x/..", false}, {"x/../y", false}, {"x//y", false}, - {`x\`, false}, - {`x\y`, false}, - {`\x`, false}, + {`x\`, true}, + {`x\y`, true}, + {`x:y`, true}, + {`\x`, true}, } func TestValidPath(t *testing.T) { diff --git a/libgo/go/io/fs/glob.go b/libgo/go/io/fs/glob.go index 549f2175429..45d9cb61b96 100644 --- a/libgo/go/io/fs/glob.go +++ b/libgo/go/io/fs/glob.go @@ -6,7 +6,6 @@ package fs import ( "path" - "runtime" ) // A GlobFS is a file system with a Glob method. @@ -111,8 +110,8 @@ func glob(fs FS, dir, pattern string, matches []string) (m []string, e error) { // recognized by path.Match. func hasMeta(path string) bool { for i := 0; i < len(path); i++ { - c := path[i] - if c == '*' || c == '?' || c == '[' || runtime.GOOS == "windows" && c == '\\' { + switch path[i] { + case '*', '?', '[', '\\': return true } } diff --git a/libgo/go/io/fs/glob_test.go b/libgo/go/io/fs/glob_test.go index 440ebd6bf4b..bcd2e1bfae9 100644 --- a/libgo/go/io/fs/glob_test.go +++ b/libgo/go/io/fs/glob_test.go @@ -17,6 +17,7 @@ var globTests = []struct { }{ {os.DirFS("."), "glob.go", "glob.go"}, {os.DirFS("."), "gl?b.go", "glob.go"}, + {os.DirFS("."), `gl\ob.go`, "glob.go"}, {os.DirFS("."), "*", "glob.go"}, // This test fails on gofrontend because the directory structure // is different. @@ -34,7 +35,7 @@ func TestGlob(t *testing.T) { t.Errorf("Glob(%#q) = %#v want %v", tt.pattern, matches, tt.result) } } - for _, pattern := range []string{"no_match", "../*/no_match"} { + for _, pattern := range []string{"no_match", "../*/no_match", `\*`} { matches, err := Glob(os.DirFS("."), pattern) if err != nil { t.Errorf("Glob error for %q: %s", pattern, err) diff --git a/libgo/go/math/big/nat.go b/libgo/go/math/big/nat.go index 068176e1c1a..bbd6c8850b6 100644 --- a/libgo/go/math/big/nat.go +++ b/libgo/go/math/big/nat.go @@ -881,7 +881,7 @@ func (z nat) divRecursiveStep(u, v nat, depth int, tmp *nat, temps []*nat) { // then floor(u1/v1) >= floor(u/v) // // Moreover, the difference is at most 2 if len(v1) >= len(u/v) - // We choose s = B-1 since len(v)-B >= B+1 >= len(u/v) + // We choose s = B-1 since len(v)-s >= B+1 >= len(u/v) s := (B - 1) // Except for the first step, the top bits are always // a division remainder, so the quotient length is <= n. diff --git a/libgo/go/net/sendfile_test.go b/libgo/go/net/sendfile_test.go index 657a36599f9..d6057fd8391 100644 --- a/libgo/go/net/sendfile_test.go +++ b/libgo/go/net/sendfile_test.go @@ -10,8 +10,10 @@ import ( "bytes" "crypto/sha256" "encoding/hex" + "errors" "fmt" "io" + "io/ioutil" "os" "runtime" "sync" @@ -313,3 +315,66 @@ func TestSendfilePipe(t *testing.T) { wg.Wait() } + +// Issue 43822: tests that returns EOF when conn write timeout. +func TestSendfileOnWriteTimeoutExceeded(t *testing.T) { + ln, err := newLocalListener("tcp") + if err != nil { + t.Fatal(err) + } + defer ln.Close() + + errc := make(chan error, 1) + go func(ln Listener) (retErr error) { + defer func() { + errc <- retErr + close(errc) + }() + + conn, err := ln.Accept() + if err != nil { + return err + } + defer conn.Close() + + // Set the write deadline in the past(1h ago). It makes + // sure that it is always write timeout. + if err := conn.SetWriteDeadline(time.Now().Add(-1 * time.Hour)); err != nil { + return err + } + + f, err := os.Open(newton) + if err != nil { + return err + } + defer f.Close() + + _, err = io.Copy(conn, f) + if errors.Is(err, os.ErrDeadlineExceeded) { + return nil + } + + if err == nil { + err = fmt.Errorf("expected ErrDeadlineExceeded, but got nil") + } + return err + }(ln) + + conn, err := Dial("tcp", ln.Addr().String()) + if err != nil { + t.Fatal(err) + } + defer conn.Close() + + n, err := io.Copy(ioutil.Discard, conn) + if err != nil { + t.Fatalf("expected nil error, but got %v", err) + } + if n != 0 { + t.Fatalf("expected receive zero, but got %d byte(s)", n) + } + + if err := <-errc; err != nil { + t.Fatal(err) + } +} diff --git a/libgo/go/os/file.go b/libgo/go/os/file.go index 416bc0efa62..52dd94339b8 100644 --- a/libgo/go/os/file.go +++ b/libgo/go/os/file.go @@ -620,10 +620,21 @@ func DirFS(dir string) fs.FS { return dirFS(dir) } +func containsAny(s, chars string) bool { + for i := 0; i < len(s); i++ { + for j := 0; j < len(chars); j++ { + if s[i] == chars[j] { + return true + } + } + } + return false +} + type dirFS string func (dir dirFS) Open(name string) (fs.File, error) { - if !fs.ValidPath(name) { + if !fs.ValidPath(name) || runtime.GOOS == "windows" && containsAny(name, `\:`) { return nil, &PathError{Op: "open", Path: name, Err: ErrInvalid} } f, err := Open(string(dir) + "/" + name) diff --git a/libgo/go/os/os_test.go b/libgo/go/os/os_test.go index 40ba05697b6..734c655e6f7 100644 --- a/libgo/go/os/os_test.go +++ b/libgo/go/os/os_test.go @@ -2721,6 +2721,40 @@ func TestDirFS(t *testing.T) { if err := fstest.TestFS(DirFS("./testdata/dirfs"), "a", "b", "dir/x"); err != nil { t.Fatal(err) } + + // Test that Open does not accept backslash as separator. + d := DirFS(".") + _, err := d.Open(`testdata\dirfs`) + if err == nil { + t.Fatalf(`Open testdata\dirfs succeeded`) + } +} + +func TestDirFSPathsValid(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skipf("skipping on Windows") + } + + d := t.TempDir() + if err := os.WriteFile(filepath.Join(d, "control.txt"), []byte(string("Hello, world!")), 0644); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(d, `e:xperi\ment.txt`), []byte(string("Hello, colon and backslash!")), 0644); err != nil { + t.Fatal(err) + } + + fsys := os.DirFS(d) + err := fs.WalkDir(fsys, ".", func(path string, e fs.DirEntry, err error) error { + if fs.ValidPath(e.Name()) { + t.Logf("%q ok", e.Name()) + } else { + t.Errorf("%q INVALID", e.Name()) + } + return nil + }) + if err != nil { + t.Fatal(err) + } } func TestReadFileProc(t *testing.T) { diff --git a/libgo/go/os/readfrom_linux_test.go b/libgo/go/os/readfrom_linux_test.go index 37047175e6f..1d145dadb08 100644 --- a/libgo/go/os/readfrom_linux_test.go +++ b/libgo/go/os/readfrom_linux_test.go @@ -361,3 +361,35 @@ func (h *copyFileRangeHook) install() { func (h *copyFileRangeHook) uninstall() { *PollCopyFileRangeP = h.original } + +// On some kernels copy_file_range fails on files in /proc. +func TestProcCopy(t *testing.T) { + const cmdlineFile = "/proc/self/cmdline" + cmdline, err := os.ReadFile(cmdlineFile) + if err != nil { + t.Skipf("can't read /proc file: %v", err) + } + in, err := os.Open(cmdlineFile) + if err != nil { + t.Fatal(err) + } + defer in.Close() + outFile := filepath.Join(t.TempDir(), "cmdline") + out, err := os.Create(outFile) + if err != nil { + t.Fatal(err) + } + if _, err := io.Copy(out, in); err != nil { + t.Fatal(err) + } + if err := out.Close(); err != nil { + t.Fatal(err) + } + copy, err := os.ReadFile(outFile) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(cmdline, copy) { + t.Errorf("copy of %q got %q want %q\n", cmdlineFile, copy, cmdline) + } +} diff --git a/libgo/go/runtime/histogram.go b/libgo/go/runtime/histogram.go index 42baa6c5e2c..da4910d341c 100644 --- a/libgo/go/runtime/histogram.go +++ b/libgo/go/runtime/histogram.go @@ -26,7 +26,7 @@ const ( // The number of super-buckets (timeHistNumSuperBuckets), on the // other hand, defines the range. To reserve room for sub-buckets, // bit timeHistSubBucketBits is the first bit considered for - // super-buckets, so super-bucket indicies are adjusted accordingly. + // super-buckets, so super-bucket indices are adjusted accordingly. // // As an example, consider 45 super-buckets with 16 sub-buckets. // diff --git a/libgo/go/runtime/metrics/doc.go b/libgo/go/runtime/metrics/doc.go index 021a0bddcaf..7f790afc12e 100644 --- a/libgo/go/runtime/metrics/doc.go +++ b/libgo/go/runtime/metrics/doc.go @@ -16,13 +16,12 @@ Interface Metrics are designated by a string key, rather than, for example, a field name in a struct. The full list of supported metrics is always available in the slice of Descriptions returned by All. Each Description also includes useful information -about the metric, such as how to display it (e.g. gauge vs. counter) and how difficult -or disruptive it is to obtain it (e.g. do you need to stop the world?). +about the metric. Thus, users of this API are encouraged to sample supported metrics defined by the slice returned by All to remain compatible across Go versions. Of course, situations arise where reading specific metrics is critical. For these cases, users are -encouranged to use build tags, and although metrics may be deprecated and removed, +encouraged to use build tags, and although metrics may be deprecated and removed, users should consider this to be an exceptional and rare event, coinciding with a very large change in a particular Go implementation. diff --git a/libgo/go/runtime/metrics/example_test.go b/libgo/go/runtime/metrics/example_test.go index cade0c38bfd..624d9d8a6bd 100644 --- a/libgo/go/runtime/metrics/example_test.go +++ b/libgo/go/runtime/metrics/example_test.go @@ -88,7 +88,7 @@ func medianBucket(h *metrics.Float64Histogram) float64 { total = 0 for i, count := range h.Counts { total += count - if total > thresh { + if total >= thresh { return h.Buckets[i] } } diff --git a/libgo/go/runtime/metrics/sample.go b/libgo/go/runtime/metrics/sample.go index 35534dd70da..4cf8cdf7994 100644 --- a/libgo/go/runtime/metrics/sample.go +++ b/libgo/go/runtime/metrics/sample.go @@ -14,7 +14,7 @@ type Sample struct { // Name is the name of the metric sampled. // // It must correspond to a name in one of the metric descriptions - // returned by Descriptions. + // returned by All. Name string // Value is the value of the metric sample. @@ -32,9 +32,9 @@ func runtime_readMetrics(unsafe.Pointer, int, int) // // Note that re-use has some caveats. Notably, Values should not be read or // manipulated while a Read with that value is outstanding; that is a data race. -// This property includes pointer-typed Values (e.g. Float64Histogram) whose -// underlying storage will be reused by Read when possible. To safely use such -// values in a concurrent setting, all data must be deep-copied. +// This property includes pointer-typed Values (for example, Float64Histogram) +// whose underlying storage will be reused by Read when possible. To safely use +// such values in a concurrent setting, all data must be deep-copied. // // It is safe to execute multiple Read calls concurrently, but their arguments // must share no underlying memory. When in doubt, create a new []Sample from diff --git a/libgo/go/runtime/metrics/value.go b/libgo/go/runtime/metrics/value.go index 61e8a192a30..ed9a33d87cc 100644 --- a/libgo/go/runtime/metrics/value.go +++ b/libgo/go/runtime/metrics/value.go @@ -33,7 +33,7 @@ type Value struct { pointer unsafe.Pointer // contains non-scalar values. } -// Kind returns the a tag representing the kind of value this is. +// Kind returns the tag representing the kind of value this is. func (v Value) Kind() ValueKind { return v.kind } diff --git a/libgo/go/runtime/stubs.go b/libgo/go/runtime/stubs.go index b0c5b38e56a..6d20c384330 100644 --- a/libgo/go/runtime/stubs.go +++ b/libgo/go/runtime/stubs.go @@ -89,7 +89,15 @@ func badsystemstack() { // *ptr is uninitialized memory (e.g., memory that's being reused // for a new allocation) and hence contains only "junk". // +// memclrNoHeapPointers ensures that if ptr is pointer-aligned, and n +// is a multiple of the pointer size, then any pointer-aligned, +// pointer-sized portion is cleared atomically. Despite the function +// name, this is necessary because this function is the underlying +// implementation of typedmemclr and memclrHasPointers. See the doc of +// memmove for more details. +// // The (CPU-specific) implementations of this function are in memclr_*.s. +// //go:noescape func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr) diff --git a/libgo/go/testing/fstest/testfs.go b/libgo/go/testing/fstest/testfs.go index a7f8007333e..8fc8acaaf3b 100644 --- a/libgo/go/testing/fstest/testfs.go +++ b/libgo/go/testing/fstest/testfs.go @@ -403,9 +403,10 @@ func (t *fsTester) checkStat(path string, entry fs.DirEntry) { return } fentry := formatEntry(entry) - finfo := formatInfoEntry(info) - if fentry != finfo { - t.errorf("%s: mismatch:\n\tentry = %s\n\tfile.Stat() = %s", path, fentry, finfo) + fientry := formatInfoEntry(info) + // Note: mismatch here is OK for symlink, because Open dereferences symlink. + if fentry != fientry && entry.Type()&fs.ModeSymlink == 0 { + t.errorf("%s: mismatch:\n\tentry = %s\n\tfile.Stat() = %s", path, fentry, fientry) } einfo, err := entry.Info() @@ -413,12 +414,22 @@ func (t *fsTester) checkStat(path string, entry fs.DirEntry) { t.errorf("%s: entry.Info: %v", path, err) return } - fentry = formatInfo(einfo) - finfo = formatInfo(info) - if fentry != finfo { - t.errorf("%s: mismatch:\n\tentry.Info() = %s\n\tfile.Stat() = %s\n", path, fentry, finfo) + finfo := formatInfo(info) + if entry.Type()&fs.ModeSymlink != 0 { + // For symlink, just check that entry.Info matches entry on common fields. + // Open deferences symlink, so info itself may differ. + feentry := formatInfoEntry(einfo) + if fentry != feentry { + t.errorf("%s: mismatch\n\tentry = %s\n\tentry.Info() = %s\n", path, fentry, feentry) + } + } else { + feinfo := formatInfo(einfo) + if feinfo != finfo { + t.errorf("%s: mismatch:\n\tentry.Info() = %s\n\tfile.Stat() = %s\n", path, feinfo, finfo) + } } + // Stat should be the same as Open+Stat, even for symlinks. info2, err := fs.Stat(t.fsys, path) if err != nil { t.errorf("%s: fs.Stat: %v", path, err) diff --git a/libgo/go/testing/fstest/testfs_test.go b/libgo/go/testing/fstest/testfs_test.go new file mode 100644 index 00000000000..5b8813c3431 --- /dev/null +++ b/libgo/go/testing/fstest/testfs_test.go @@ -0,0 +1,31 @@ +// 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 fstest + +import ( + "internal/testenv" + "os" + "path/filepath" + "testing" +) + +func TestSymlink(t *testing.T) { + testenv.MustHaveSymlink(t) + + tmp := t.TempDir() + tmpfs := os.DirFS(tmp) + + if err := os.WriteFile(filepath.Join(tmp, "hello"), []byte("hello, world\n"), 0644); err != nil { + t.Fatal(err) + } + + if err := os.Symlink(filepath.Join(tmp, "hello"), filepath.Join(tmp, "hello.link")); err != nil { + t.Fatal(err) + } + + if err := TestFS(tmpfs, "hello", "hello.link"); err != nil { + t.Fatal(err) + } +} diff --git a/libgo/misc/cgo/testshared/shared_test.go b/libgo/misc/cgo/testshared/shared_test.go index 5e0893784b6..f52391c6f6c 100644 --- a/libgo/misc/cgo/testshared/shared_test.go +++ b/libgo/misc/cgo/testshared/shared_test.go @@ -1063,3 +1063,11 @@ func TestGCData(t *testing.T) { goCmd(t, "build", "-linkshared", "./gcdata/main") runWithEnv(t, "running gcdata/main", []string{"GODEBUG=clobberfree=1"}, "./main") } + +// Test that we don't decode type symbols from shared libraries (which has no data, +// causing panic). See issue 44031. +func TestIssue44031(t *testing.T) { + goCmd(t, "install", "-buildmode=shared", "-linkshared", "./issue44031/a") + goCmd(t, "install", "-buildmode=shared", "-linkshared", "./issue44031/b") + goCmd(t, "run", "-linkshared", "./issue44031/main") +} diff --git a/libgo/misc/cgo/testshared/testdata/issue44031/a/a.go b/libgo/misc/cgo/testshared/testdata/issue44031/a/a.go new file mode 100644 index 00000000000..48827e682fb --- /dev/null +++ b/libgo/misc/cgo/testshared/testdata/issue44031/a/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 + +type ATypeWithALoooooongName interface { // a long name, so the type descriptor symbol name is mangled + M() +} diff --git a/libgo/misc/cgo/testshared/testdata/issue44031/b/b.go b/libgo/misc/cgo/testshared/testdata/issue44031/b/b.go new file mode 100644 index 00000000000..ad3ebec2b98 --- /dev/null +++ b/libgo/misc/cgo/testshared/testdata/issue44031/b/b.go @@ -0,0 +1,17 @@ +// 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 + +import "testshared/issue44031/a" + +type T int + +func (T) M() {} + +var i = a.ATypeWithALoooooongName(T(0)) + +func F() { + i.M() +} diff --git a/libgo/misc/cgo/testshared/testdata/issue44031/main/main.go b/libgo/misc/cgo/testshared/testdata/issue44031/main/main.go new file mode 100644 index 00000000000..47f2e3a98e8 --- /dev/null +++ b/libgo/misc/cgo/testshared/testdata/issue44031/main/main.go @@ -0,0 +1,20 @@ +// 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 "testshared/issue44031/b" + +type t int + +func (t) m() {} + +type i interface{ m() } // test that unexported method is correctly marked + +var v interface{} = t(0) + +func main() { + b.F() + v.(i).m() +}