diff options
author | Filippo Valsorda <filippo@golang.org> | 2019-10-24 06:36:26 -0400 |
---|---|---|
committer | Filippo Valsorda <filippo@golang.org> | 2019-10-24 06:36:26 -0400 |
commit | cba6efa89376c6a6660e1c24d5dadcd3fd0735b1 (patch) | |
tree | f815811b16e046ed6662bb2c195b276a4691d4b8 | |
parent | 6a1c22797f9cf16e0098be1d618b6c49a3b9ec34 (diff) | |
parent | e64356a4484deb5da57396a4cd80e26667b86b79 (diff) | |
download | go-cba6efa89376c6a6660e1c24d5dadcd3fd0735b1.tar.gz go-cba6efa89376c6a6660e1c24d5dadcd3fd0735b1.zip |
[dev.boringcrypto.go1.13] all: merge go1.13.3 into dev.boringcrypto.go1.13
Change-Id: I6153fcf6c7b933ae651228e8ce3593e861c80e49
83 files changed, 952 insertions, 1527 deletions
diff --git a/doc/devel/release.html b/doc/devel/release.html index fc858d418b..0ac3b86334 100644 --- a/doc/devel/release.html +++ b/doc/devel/release.html @@ -46,6 +46,14 @@ See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.13.2">Go 1.13.2 milestone</a> on our issue tracker for details. </p> +<p> +go1.13.3 (released 2019/10/17) includes fixes to the go command, +the toolchain, the runtime, <code>syscall</code>, <code>net</code>, +<code>net/http</code>, and <code>crypto/ecdsa</code> packages. +See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.13.3">Go +1.13.3 milestone</a> on our issue tracker for details. +</p> + <h2 id="go1.12">go1.12 (released 2019/02/25)</h2> <p> @@ -135,6 +143,13 @@ See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.12.11">Go 1.12.11 milestone</a> on our issue tracker for details. </p> +<p> +go1.12.12 (released 2019/10/17) includes fixes to the go command, +runtime, <code>syscall</code> and <code>net</code> packages. +See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.12.12">Go +1.12.12 milestone</a> on our issue tracker for details. +</p> + <h2 id="go1.11">go1.11 (released 2018/08/24)</h2> <p> diff --git a/doc/go1.13.html b/doc/go1.13.html index d5809d6ad1..d4a762721f 100644 --- a/doc/go1.13.html +++ b/doc/go1.13.html @@ -102,7 +102,7 @@ Do not send CLs removing the interior tags from such phrases. <h2 id="ports">Ports</h2> -<p> +<p id="nacl"> Go 1.13 is the last release that will run on Native Client (NaCl). </p> @@ -821,7 +821,7 @@ godoc <p><!-- CL 154383 --> <a href="/pkg/net/http/#TimeoutHandler"><code>TimeoutHandler</code></a>'s <a href="/pkg/net/http/#ResponseWriter"><code>ResponseWriter</code></a> now implements the - <a href="/pkg/net/http/#Pusher"><code>Pusher</code></a> and <a href="/pkg/net/http/#Flusher"><code>Flusher</code></a> interfaces. + <a href="/pkg/net/http/#Pusher"><code>Pusher</code></a> interface. </p> <p><!-- CL 157339 --> diff --git a/src/cmd/compile/internal/gc/noder.go b/src/cmd/compile/internal/gc/noder.go index 93d355278e..6aca89cad9 100644 --- a/src/cmd/compile/internal/gc/noder.go +++ b/src/cmd/compile/internal/gc/noder.go @@ -1330,7 +1330,7 @@ func checkLangCompat(lit *syntax.BasicLit) { } // len(s) > 2 if strings.Contains(s, "_") { - yyerror("underscores in numeric literals only supported as of -lang=go1.13") + yyerrorv("go1.13", "underscores in numeric literals") return } if s[0] != '0' { @@ -1338,15 +1338,15 @@ func checkLangCompat(lit *syntax.BasicLit) { } base := s[1] if base == 'b' || base == 'B' { - yyerror("binary literals only supported as of -lang=go1.13") + yyerrorv("go1.13", "binary literals") return } if base == 'o' || base == 'O' { - yyerror("0o/0O-style octal literals only supported as of -lang=go1.13") + yyerrorv("go1.13", "0o/0O-style octal literals") return } if lit.Kind != syntax.IntLit && (base == 'x' || base == 'X') { - yyerror("hexadecimal floating-point literals only supported as of -lang=go1.13") + yyerrorv("go1.13", "hexadecimal floating-point literals") } } diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go index f3ec21c7cb..d33fd4eb6c 100644 --- a/src/cmd/compile/internal/gc/subr.go +++ b/src/cmd/compile/internal/gc/subr.go @@ -154,6 +154,11 @@ func yyerrorl(pos src.XPos, format string, args ...interface{}) { } } +func yyerrorv(lang string, format string, args ...interface{}) { + what := fmt.Sprintf(format, args...) + yyerrorl(lineno, "%s requires %s or later (-lang was set to %s; check go.mod)", what, lang, flag_lang) +} + func yyerror(format string, args ...interface{}) { yyerrorl(lineno, format, args...) } diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go index 4cb28d6100..223e5add36 100644 --- a/src/cmd/compile/internal/gc/typecheck.go +++ b/src/cmd/compile/internal/gc/typecheck.go @@ -632,7 +632,7 @@ func typecheck1(n *Node, top int) (res *Node) { return n } if t.IsSigned() && !langSupported(1, 13) { - yyerror("invalid operation: %v (signed shift count type %v, only supported as of -lang=go1.13)", n, r.Type) + yyerrorv("go1.13", "invalid operation: %v (signed shift count type %v)", n, r.Type) n.Type = nil return n } diff --git a/src/cmd/cover/func.go b/src/cmd/cover/func.go index fe64374189..988c4caebf 100644 --- a/src/cmd/cover/func.go +++ b/src/cmd/cover/func.go @@ -191,6 +191,10 @@ func findPkgs(profiles []*Profile) (map[string]*Pkg, error) { } } + if len(list) == 0 { + return pkgs, nil + } + // Note: usually run as "go tool cover" in which case $GOROOT is set, // in which case runtime.GOROOT() does exactly what we want. goTool := filepath.Join(runtime.GOROOT(), "bin/go") diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index ebbead5d31..0a8935b6bc 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -1018,7 +1018,6 @@ // Dir string // absolute path to cached source root directory // Sum string // checksum for path, version (as in go.sum) // GoModSum string // checksum for go.mod (as in go.sum) -// Latest bool // would @latest resolve to this version? // } // // See 'go help modules' for more about module queries. diff --git a/src/cmd/go/internal/get/vcs.go b/src/cmd/go/internal/get/vcs.go index 705bb66dbe..6ae3cffd93 100644 --- a/src/cmd/go/internal/get/vcs.go +++ b/src/cmd/go/internal/get/vcs.go @@ -904,7 +904,7 @@ func metaImportsForPrefix(importPrefix string, mod ModuleMode, security web.Secu } resp, err := web.Get(security, url) if err != nil { - return setCache(fetchResult{url: url, err: fmt.Errorf("fetch %s: %v", resp.URL, err)}) + return setCache(fetchResult{url: url, err: fmt.Errorf("fetching %s: %v", importPrefix, err)}) } body := resp.Body defer body.Close() @@ -913,7 +913,7 @@ func metaImportsForPrefix(importPrefix string, mod ModuleMode, security web.Secu return setCache(fetchResult{url: url, err: fmt.Errorf("parsing %s: %v", resp.URL, err)}) } if len(imports) == 0 { - err = fmt.Errorf("fetch %s: no go-import meta tag", url) + err = fmt.Errorf("fetching %s: no go-import meta tag found in %s", importPrefix, resp.URL) } return setCache(fetchResult{url: url, imports: imports, err: err}) }) diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go index 64267a4a46..07f7115e33 100644 --- a/src/cmd/go/internal/load/pkg.go +++ b/src/cmd/go/internal/load/pkg.go @@ -1956,9 +1956,14 @@ func Packages(args []string) []*Package { // cannot be loaded at all. // The packages that fail to load will have p.Error != nil. func PackagesAndErrors(patterns []string) []*Package { - if len(patterns) > 0 { - for _, p := range patterns { - if strings.HasSuffix(p, ".go") { + for _, p := range patterns { + // Listing is only supported with all patterns referring to either: + // - Files that are part of the same directory. + // - Explicit package paths or patterns. + if strings.HasSuffix(p, ".go") { + // We need to test whether the path is an actual Go file and not a + // package path or pattern ending in '.go' (see golang.org/issue/34653). + if fi, err := os.Stat(p); err == nil && !fi.IsDir() { return []*Package{GoFilesPackage(patterns)} } } diff --git a/src/cmd/go/internal/load/test.go b/src/cmd/go/internal/load/test.go index afff5deaaa..aac7d7d481 100644 --- a/src/cmd/go/internal/load/test.go +++ b/src/cmd/go/internal/load/test.go @@ -399,10 +399,13 @@ func recompileForTest(pmain, preal, ptest, pxtest *Package) { } } - // Don't compile build info from a main package. This can happen - // if -coverpkg patterns include main packages, since those packages - // are imported by pmain. See golang.org/issue/30907. - if p.Internal.BuildInfo != "" && p != pmain { + // Force main packages the test imports to be built as libraries. + // Normal imports of main packages are forbidden by the package loader, + // but this can still happen if -coverpkg patterns include main packages: + // covered packages are imported by pmain. Linking multiple packages + // compiled with '-p main' causes duplicate symbol errors. + // See golang.org/issue/30907, golang.org/issue/34114. + if p.Name == "main" && p != pmain && p != ptest { split() } } diff --git a/src/cmd/go/internal/modcmd/download.go b/src/cmd/go/internal/modcmd/download.go index 60d0d5b6e2..0d432e9549 100644 --- a/src/cmd/go/internal/modcmd/download.go +++ b/src/cmd/go/internal/modcmd/download.go @@ -43,7 +43,6 @@ corresponding to this Go struct: Dir string // absolute path to cached source root directory Sum string // checksum for path, version (as in go.sum) GoModSum string // checksum for go.mod (as in go.sum) - Latest bool // would @latest resolve to this version? } See 'go help modules' for more about module queries. @@ -66,7 +65,6 @@ type moduleJSON struct { Dir string `json:",omitempty"` Sum string `json:",omitempty"` GoModSum string `json:",omitempty"` - Latest bool `json:",omitempty"` } func runDownload(cmd *base.Command, args []string) { @@ -105,31 +103,6 @@ func runDownload(cmd *base.Command, args []string) { work.Add(m) } - latest := map[string]string{} // path → version - if *downloadJSON { - // We need to populate the Latest field, but if the main module depends on a - // version newer than latest — or if the version requested on the command - // line is itself newer than latest — that's not trivial to determine from - // the info returned by ListModules. Instead, we issue a separate - // ListModules request for "latest", which should be inexpensive relative to - // downloading the modules. - var latestArgs []string - for _, m := range mods { - if m.Error != "" { - continue - } - latestArgs = append(latestArgs, m.Path+"@latest") - } - - if len(latestArgs) > 0 { - for _, info := range modload.ListModules(latestArgs, listU, listVersions) { - if info.Version != "" { - latest[info.Path] = info.Version - } - } - } - } - work.Do(10, func(item interface{}) { m := item.(*moduleJSON) var err error @@ -160,9 +133,6 @@ func runDownload(cmd *base.Command, args []string) { m.Error = err.Error() return } - if latest[m.Path] == m.Version { - m.Latest = true - } }) if *downloadJSON { diff --git a/src/cmd/go/internal/modfetch/codehost/git.go b/src/cmd/go/internal/modfetch/codehost/git.go index d382e8ac9a..dc5add906b 100644 --- a/src/cmd/go/internal/modfetch/codehost/git.go +++ b/src/cmd/go/internal/modfetch/codehost/git.go @@ -241,13 +241,6 @@ func (r *gitRepo) findRef(hash string) (ref string, ok bool) { return "", false } -func unshallow(gitDir string) []string { - if _, err := os.Stat(filepath.Join(gitDir, "shallow")); err == nil { - return []string{"--unshallow"} - } - return []string{} -} - // minHashDigits is the minimum number of digits to require // before accepting a hex digit sequence as potentially identifying // a specific commit in a git repo. (Of course, users can always @@ -397,29 +390,27 @@ func (r *gitRepo) stat(rev string) (*RevInfo, error) { // fetchRefsLocked requires that r.mu remain locked for the duration of the call. func (r *gitRepo) fetchRefsLocked() error { if r.fetchLevel < fetchAll { - if err := r.fetchUnshallow("refs/heads/*:refs/heads/*", "refs/tags/*:refs/tags/*"); err != nil { + // NOTE: To work around a bug affecting Git clients up to at least 2.23.0 + // (2019-08-16), we must first expand the set of local refs, and only then + // unshallow the repository as a separate fetch operation. (See + // golang.org/issue/34266 and + // https://github.com/git/git/blob/4c86140027f4a0d2caaa3ab4bd8bfc5ce3c11c8a/transport.c#L1303-L1309.) + + if _, err := Run(r.dir, "git", "fetch", "-f", r.remote, "refs/heads/*:refs/heads/*", "refs/tags/*:refs/tags/*"); err != nil { return err } + + if _, err := os.Stat(filepath.Join(r.dir, "shallow")); err == nil { + if _, err := Run(r.dir, "git", "fetch", "--unshallow", "-f", r.remote); err != nil { + return err + } + } + r.fetchLevel = fetchAll } return nil } -func (r *gitRepo) fetchUnshallow(refSpecs ...string) error { - // To work around a protocol version 2 bug that breaks --unshallow, - // add -c protocol.version=0. - // TODO(rsc): The bug is believed to be server-side, meaning only - // on Google's Git servers. Once the servers are fixed, drop the - // protocol.version=0. See Google-internal bug b/110495752. - var protoFlag []string - unshallowFlag := unshallow(r.dir) - if len(unshallowFlag) > 0 { - protoFlag = []string{"-c", "protocol.version=0"} - } - _, err := Run(r.dir, "git", protoFlag, "fetch", unshallowFlag, "-f", r.remote, refSpecs) - return err -} - // statLocal returns a RevInfo describing rev in the local git repository. // It uses version as info.Version. func (r *gitRepo) statLocal(version, rev string) (*RevInfo, error) { @@ -539,39 +530,10 @@ func (r *gitRepo) ReadFileRevs(revs []string, file string, maxSize int64) (map[s } defer unlock() - var refs []string - var protoFlag []string - var unshallowFlag []string - for _, tag := range redo { - refs = append(refs, "refs/tags/"+tag+":refs/tags/"+tag) - } - if len(refs) > 1 { - unshallowFlag = unshallow(r.dir) - if len(unshallowFlag) > 0 { - // To work around a protocol version 2 bug that breaks --unshallow, - // add -c protocol.version=0. - // TODO(rsc): The bug is believed to be server-side, meaning only - // on Google's Git servers. Once the servers are fixed, drop the - // protocol.version=0. See Google-internal bug b/110495752. - protoFlag = []string{"-c", "protocol.version=0"} - } - } - if _, err := Run(r.dir, "git", protoFlag, "fetch", unshallowFlag, "-f", r.remote, refs); err != nil { + if err := r.fetchRefsLocked(); err != nil { return nil, err } - // TODO(bcmills): after the 1.11 freeze, replace the block above with: - // if r.fetchLevel <= fetchSome { - // r.fetchLevel = fetchSome - // var refs []string - // for _, tag := range redo { - // refs = append(refs, "refs/tags/"+tag+":refs/tags/"+tag) - // } - // if _, err := Run(r.dir, "git", "fetch", "--update-shallow", "-f", r.remote, refs); err != nil { - // return nil, err - // } - // } - if _, err := r.readFileRevs(redo, file, files); err != nil { return nil, err } diff --git a/src/cmd/go/internal/modfetch/coderepo_test.go b/src/cmd/go/internal/modfetch/coderepo_test.go index 1f2b95bd23..663324b3dd 100644 --- a/src/cmd/go/internal/modfetch/coderepo_test.go +++ b/src/cmd/go/internal/modfetch/coderepo_test.go @@ -338,10 +338,10 @@ var codeRepoTests = []codeRepoTest{ vcs: "git", path: "gopkg.in/yaml.v2", rev: "v2", - version: "v2.2.3-0.20190319135612-7b8349ac747c", - name: "7b8349ac747c6a24702b762d2c4fd9266cf4f1d6", - short: "7b8349ac747c", - time: time.Date(2019, 03, 19, 13, 56, 12, 0, time.UTC), + version: "v2.2.5-0.20191002202810-970885f01c8b", + name: "970885f01c8bc1fecb7ab1c8ce8e7609bda45530", + short: "970885f01c8b", + time: time.Date(2019, 10, 2, 20, 28, 10, 0, time.UTC), gomod: "module \"gopkg.in/yaml.v2\"\n\nrequire (\n\t\"gopkg.in/check.v1\" v0.0.0-20161208181325-20d25e280405\n)\n", }, { diff --git a/src/cmd/go/internal/modload/import_test.go b/src/cmd/go/internal/modload/import_test.go index c6ade5d17f..c58892e2ab 100644 --- a/src/cmd/go/internal/modload/import_test.go +++ b/src/cmd/go/internal/modload/import_test.go @@ -21,7 +21,7 @@ var importTests = []struct { }, { path: "golang.org/x/net", - err: "module golang.org/x/net@.* found, but does not contain package golang.org/x/net", + err: `module golang.org/x/net@.* found \(v0.0.0-.*\), but does not contain package golang.org/x/net`, }, { path: "golang.org/x/text", diff --git a/src/cmd/go/internal/modload/load.go b/src/cmd/go/internal/modload/load.go index b50a084166..92e76a9246 100644 --- a/src/cmd/go/internal/modload/load.go +++ b/src/cmd/go/internal/modload/load.go @@ -1205,6 +1205,11 @@ func (*mvsReqs) next(m module.Version) (module.Version, error) { return module.Version{Path: m.Path, Version: "none"}, nil } +// fetch downloads the given module (or its replacement) +// and returns its location. +// +// The isLocal return value reports whether the replacement, +// if any, is local to the filesystem. func fetch(mod module.Version) (dir string, isLocal bool, err error) { if mod == Target { return ModRoot(), true, nil diff --git a/src/cmd/go/internal/modload/query.go b/src/cmd/go/internal/modload/query.go index 602bf47275..75c18f25cc 100644 --- a/src/cmd/go/internal/modload/query.go +++ b/src/cmd/go/internal/modload/query.go @@ -381,9 +381,10 @@ func QueryPattern(pattern, query string, allowed func(module.Version) bool) ([]Q r.Packages = match(r.Mod, root, isLocal) if len(r.Packages) == 0 { return r, &PackageNotInModuleError{ - Mod: r.Mod, - Query: query, - Pattern: pattern, + Mod: r.Mod, + Replacement: Replacement(r.Mod), + Query: query, + Pattern: pattern, } } return r, nil @@ -471,7 +472,17 @@ func queryPrefixModules(candidateModules []string, queryModule func(path string) notExistErr = rErr } } else if err == nil { - err = r.err + if len(found) > 0 || noPackage != nil { + // golang.org/issue/34094: If we have already found a module that + // could potentially contain the target package, ignore unclassified + // errors for modules with shorter paths. + + // golang.org/issue/34383 is a special case of this: if we have + // already found example.com/foo/v2@v2.0.0 with a matching go.mod + // file, ignore the error from example.com/foo@v2.0.0. + } else { + err = r.err + } } } } @@ -526,21 +537,32 @@ func (e *NoMatchingVersionError) Error() string { // code for the versions it knows about, and thus did not have the opportunity // to return a non-400 status code to suppress fallback. type PackageNotInModuleError struct { - Mod module.Version - Query string - Pattern string + Mod module.Version + Replacement module.Version + Query string + Pattern string } func (e *PackageNotInModuleError) Error() string { found := "" - if e.Query != e.Mod.Version { + if r := e.Replacement; r.Path != "" { + replacement := r.Path + if r.Version != "" { + replacement = fmt.Sprintf("%s@%s", r.Path, r.Version) + } + if e.Query == e.Mod.Version { + found = fmt.Sprintf(" (replaced by %s)", replacement) + } else { + found = fmt.Sprintf(" (%s, replaced by %s)", e.Mod.Version, replacement) + } + } else if e.Query != e.Mod.Version { found = fmt.Sprintf(" (%s)", e.Mod.Version) } if strings.Contains(e.Pattern, "...") { - return fmt.Sprintf("module %s@%s%s found, but does not contain packages matching %s", e.Mod.Path, e.Query, found, e.Pattern) + return fmt.Sprintf("module %s@%s found%s, but does not contain packages matching %s", e.Mod.Path, e.Query, found, e.Pattern) } - return fmt.Sprintf("module %s@%s%s found, but does not contain package %s", e.Mod.Path, e.Query, found, e.Pattern) + return fmt.Sprintf("module %s@%s found%s, but does not contain package %s", e.Mod.Path, e.Query, found, e.Pattern) } // ModuleHasRootPackage returns whether module m contains a package m.Path. diff --git a/src/cmd/go/internal/search/search.go b/src/cmd/go/internal/search/search.go index 0167c8d755..d794287583 100644 --- a/src/cmd/go/internal/search/search.go +++ b/src/cmd/go/internal/search/search.go @@ -363,30 +363,40 @@ func ImportPathsQuiet(patterns []string) []*Match { // CleanPatterns returns the patterns to use for the given // command line. It canonicalizes the patterns but does not -// evaluate any matches. +// evaluate any matches. It preserves text after '@' for commands +// that accept versions. func CleanPatterns(patterns []string) []string { if len(patterns) == 0 { return []string{"."} } var out []string for _, a := range patterns { + var p, v string + if i := strings.IndexByte(a, '@'); i < 0 { + p = a + } else { + p = a[:i] + v = a[i:] + } + // Arguments are supposed to be import paths, but // as a courtesy to Windows developers, rewrite \ to / // in command-line arguments. Handles .\... and so on. if filepath.Separator == '\\' { - a = strings.ReplaceAll(a, `\`, `/`) + p = strings.ReplaceAll(p, `\`, `/`) } // Put argument in canonical form, but preserve leading ./. - if strings.HasPrefix(a, "./") { - a = "./" + path.Clean(a) - if a == "./." { - a = "." + if strings.HasPrefix(p, "./") { + p = "./" + path.Clean(p) + if p == "./." { + p = "." } } else { - a = path.Clean(a) + p = path.Clean(p) } - out = append(out, a) + + out = append(out, p+v) } return out } diff --git a/src/cmd/go/internal/test/test.go b/src/cmd/go/internal/test/test.go index 95000011d8..8141e31c99 100644 --- a/src/cmd/go/internal/test/test.go +++ b/src/cmd/go/internal/test/test.go @@ -572,8 +572,9 @@ func runTest(cmd *base.Command, args []string) { } // Pass timeout to tests if it exists. + // Prepend rather than appending so that it appears before positional arguments. if testActualTimeout > 0 { - testArgs = append(testArgs, "-test.timeout="+testActualTimeout.String()) + testArgs = append([]string{"-test.timeout=" + testActualTimeout.String()}, testArgs...) } // show passing test output (after buffering) with -v flag. diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go index b68f902853..7dd9a90c18 100644 --- a/src/cmd/go/internal/work/exec.go +++ b/src/cmd/go/internal/work/exec.go @@ -200,12 +200,12 @@ func (b *Builder) buildActionID(a *Action) cache.ActionID { // same compiler settings and can reuse each other's results. // If not, the reason is already recorded in buildGcflags. fmt.Fprintf(h, "compile\n") + // Only include the package directory if it may affect the output. + // We trim workspace paths for all packages when -trimpath is set. // The compiler hides the exact value of $GOROOT - // when building things in GOROOT, - // but it does not hide the exact value of $GOPATH. - // Include the full dir in that case. + // when building things in GOROOT. // Assume b.WorkDir is being trimmed properly. - if !p.Goroot && !strings.HasPrefix(p.Dir, b.WorkDir) { + if !p.Goroot && !cfg.BuildTrimpath && !strings.HasPrefix(p.Dir, b.WorkDir) { fmt.Fprintf(h, "dir %s\n", p.Dir) } fmt.Fprintf(h, "goos %s goarch %s\n", cfg.Goos, cfg.Goarch) @@ -1030,7 +1030,7 @@ func (b *Builder) vet(a *Action) error { // dependency tree turn on *more* analysis, as here. // (The unsafeptr check does not write any facts for use by // later vet runs.) - if a.Package.Goroot && !VetExplicit { + if a.Package.Goroot && !VetExplicit && VetTool == "" { // Note that $GOROOT/src/buildall.bash // does the same for the misc-compile trybots // and should be updated if these flags are diff --git a/src/cmd/go/script_test.go b/src/cmd/go/script_test.go index 4dcb4b4e0d..5e50dd14c7 100644 --- a/src/cmd/go/script_test.go +++ b/src/cmd/go/script_test.go @@ -441,10 +441,15 @@ func (ts *testScript) cmdCmp(neg bool, args []string) { // It would be strange to say "this file can have any content except this precise byte sequence". ts.fatalf("unsupported: ! cmp") } + quiet := false + if len(args) > 0 && args[0] == "-q" { + quiet = true + args = args[1:] + } if len(args) != 2 { ts.fatalf("usage: cmp file1 file2") } - ts.doCmdCmp(args, false) + ts.doCmdCmp(args, false, quiet) } // cmpenv compares two files with environment variable substitution. @@ -452,13 +457,18 @@ func (ts *testScript) cmdCmpenv(neg bool, args []string) { if neg { ts.fatalf("unsupported: ! cmpenv") } + quiet := false + if len(args) > 0 && args[0] == "-q" { + quiet = true + args = args[1:] + } if len(args) != 2 { ts.fatalf("usage: cmpenv file1 file2") } - ts.doCmdCmp(args, true) + ts.doCmdCmp(args, true, quiet) } -func (ts *testScript) doCmdCmp(args []string, env bool) { +func (ts *testScript) doCmdCmp(args []string, env, quiet bool) { name1, name2 := args[0], args[1] var text1, text2 string if name1 == "stdout" { @@ -484,7 +494,9 @@ func (ts *testScript) doCmdCmp(args []string, env bool) { return } - fmt.Fprintf(&ts.log, "[diff -%s +%s]\n%s\n", name1, name2, diff(text1, text2)) + if !quiet { + fmt.Fprintf(&ts.log, "[diff -%s +%s]\n%s\n", name1, name2, diff(text1, text2)) + } ts.fatalf("%s and %s differ", name1, name2) } diff --git a/src/cmd/go/testdata/mod/example.com_dotgo.go_v1.0.0.txt b/src/cmd/go/testdata/mod/example.com_dotgo.go_v1.0.0.txt new file mode 100644 index 0000000000..4f7f4d7dd2 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_dotgo.go_v1.0.0.txt @@ -0,0 +1,16 @@ +This module's path ends with ".go". +Based on github.com/nats-io/nats.go. +Used in regression tests for golang.org/issue/32483. + +-- .mod -- +module example.com/dotgo.go + +go 1.13 +-- .info -- +{"Version":"v1.0.0"} +-- go.mod -- +module example.com/dotgo.go + +go 1.13 +-- dotgo.go -- +package dotgo diff --git a/src/cmd/go/testdata/script/build_trimpath.txt b/src/cmd/go/testdata/script/build_trimpath.txt index f785b0cb9e..668f75599e 100644 --- a/src/cmd/go/testdata/script/build_trimpath.txt +++ b/src/cmd/go/testdata/script/build_trimpath.txt @@ -1,21 +1,44 @@ [short] skip env -r GOROOT_REGEXP=$GOROOT -env -r WORK_REGEXP=$WORK +env -r WORK_REGEXP='$WORK' # don't expand $WORK; grep replaces $WORK in text before matching. env GOROOT GOROOT_REGEXP WORK WORK_REGEXP +# A binary built without -trimpath should contain the current workspace +# and GOROOT for debugging and stack traces. +cd a +go build -o hello.exe hello.go +grep -q $WORK_REGEXP hello.exe +grep -q $GOROOT_REGEXP hello.exe + +# A binary built with -trimpath should not contain the current workspace +# or GOROOT. go build -trimpath -o hello.exe hello.go ! grep -q $GOROOT_REGEXP hello.exe ! grep -q $WORK_REGEXP hello.exe +cd .. +# A binary from an external module built with -trimpath should not contain +# the current workspace or GOROOT. env GO111MODULE=on go build -trimpath -o fortune.exe rsc.io/fortune ! grep -q $GOROOT_REGEXP fortune.exe ! grep -q $WORK_REGEXP fortune.exe --- hello.go -- +# Two binaries built from identical packages in different directories +# should be identical. +mkdir b +cp a/go.mod a/hello.go b +cd a +go build -trimpath -o ../a.exe . +cd ../b +go build -trimpath -o ../b.exe . +cd .. +cmp -q a.exe b.exe + +-- a/hello.go -- package main func main() { println("hello") } --- go.mod -- +-- a/go.mod -- module m diff --git a/src/cmd/go/testdata/script/cover_mod_empty.txt b/src/cmd/go/testdata/script/cover_mod_empty.txt new file mode 100644 index 0000000000..3c45243edb --- /dev/null +++ b/src/cmd/go/testdata/script/cover_mod_empty.txt @@ -0,0 +1,9 @@ +go tool cover -func=cover.out +stdout total.*statements.*0.0% + +go mod init golang.org/issue/33855 + +go tool cover -func=cover.out +stdout total.*statements.*0.0% + +-- cover.out -- diff --git a/src/cmd/go/testdata/script/cover_pkgall_multiple_mains.txt b/src/cmd/go/testdata/script/cover_pkgall_multiple_mains.txt index ab7cd66949..f21cd8b3a8 100644 --- a/src/cmd/go/testdata/script/cover_pkgall_multiple_mains.txt +++ b/src/cmd/go/testdata/script/cover_pkgall_multiple_mains.txt @@ -1,29 +1,32 @@ # This test checks that multiple main packages can be tested # with -coverpkg=all without duplicate symbol errors. -# Verifies golang.org/issue/30374. - -env GO111MODULE=on +# Verifies golang.org/issue/30374, golang.org/issue/34114. [short] skip +cd $GOPATH/src/example.com/cov + +env GO111MODULE=on +go test -coverpkg=all ./... +env GO111MODULE=off go test -coverpkg=all ./... --- go.mod -- +-- $GOPATH/src/example.com/cov/go.mod -- module example.com/cov --- mainonly/mainonly.go -- +-- $GOPATH/src/example.com/cov/mainonly/mainonly.go -- package main func main() {} --- mainwithtest/mainwithtest.go -- +-- $GOPATH/src/example.com/cov/mainwithtest/mainwithtest.go -- package main func main() {} func Foo() {} --- mainwithtest/mainwithtest_test.go -- +-- $GOPATH/src/example.com/cov/mainwithtest/mainwithtest_test.go -- package main import "testing" @@ -32,10 +35,10 @@ func TestFoo(t *testing.T) { Foo() } --- xtest/x.go -- +-- $GOPATH/src/example.com/cov/xtest/x.go -- package x --- xtest/x_test.go -- +-- $GOPATH/src/example.com/cov/xtest/x_test.go -- package x_test import "testing" diff --git a/src/cmd/go/testdata/script/get_insecure_redirect.txt b/src/cmd/go/testdata/script/get_insecure_redirect.txt index a83b17672d..0478d1f75d 100644 --- a/src/cmd/go/testdata/script/get_insecure_redirect.txt +++ b/src/cmd/go/testdata/script/get_insecure_redirect.txt @@ -1,11 +1,10 @@ # golang.org/issue/29591: 'go get' was following plain-HTTP redirects even without -insecure. +# golang.org/issue/34049: 'go get' would panic in case of an insecure redirect in GOPATH mode [!net] skip [!exec:git] skip -env GO111MODULE=on -env GOPROXY=direct -env GOSUMDB=off +env GO111MODULE=off ! go get -d vcs-test.golang.org/insecure/go/insecure stderr 'redirected .* to insecure URL' diff --git a/src/cmd/go/testdata/script/list_ambiguous_path.txt b/src/cmd/go/testdata/script/list_ambiguous_path.txt new file mode 100644 index 0000000000..9f1aa37be8 --- /dev/null +++ b/src/cmd/go/testdata/script/list_ambiguous_path.txt @@ -0,0 +1,37 @@ +# Ensures that we can correctly list package patterns ending in '.go'. +# See golang.org/issue/34653. + +# A single pattern for a package ending in '.go'. +go list ./foo.go +stdout '^test/foo.go$' + +# Multiple patterns for packages including one ending in '.go'. +go list ./bar ./foo.go +stdout '^test/bar$' +stdout '^test/foo.go$' + +# A single pattern for a Go file. +go list ./a.go +stdout '^command-line-arguments$' + +# A single typo-ed pattern for a Go file. This should +# treat the wrong pattern as if it were a package. +! go list ./foo.go/b.go +stderr 'package ./foo.go/b.go: cannot find package "."' + +# Multiple patterns for Go files with a typo. This should +# treat the wrong pattern as if it were a non-existint file. +! go list ./foo.go/a.go ./foo.go/b.go +[windows] stderr './foo.go/b.go: The system cannot find the file specified' +[!windows] stderr './foo.go/b.go: no such file or directory' + +-- a.go -- +package main +-- bar/a.go -- +package bar +-- foo.go/a.go -- +package foo.go +-- go.mod -- +module "test" + +go 1.13 diff --git a/src/cmd/go/testdata/script/list_split_main.txt b/src/cmd/go/testdata/script/list_split_main.txt new file mode 100644 index 0000000000..74e7d5d74c --- /dev/null +++ b/src/cmd/go/testdata/script/list_split_main.txt @@ -0,0 +1,25 @@ +# This test checks that a "main" package with an external test package +# is recompiled only once. +# Verifies golang.org/issue/34321. + +env GO111MODULE=off + +go list -e -test -deps -f '{{if not .Standard}}{{.ImportPath}}{{end}}' pkg +cmp stdout want + +-- $GOPATH/src/pkg/pkg.go -- +package main + +func main() {} + +-- $GOPATH/src/pkg/pkg_test.go -- +package main + +import "testing" + +func Test(t *testing.T) {} + +-- want -- +pkg +pkg [pkg.test] +pkg.test diff --git a/src/cmd/go/testdata/script/mod_download.txt b/src/cmd/go/testdata/script/mod_download.txt index 9eb3140c33..0777913786 100644 --- a/src/cmd/go/testdata/script/mod_download.txt +++ b/src/cmd/go/testdata/script/mod_download.txt @@ -17,7 +17,6 @@ stderr 'this.domain.is.invalid' stdout '"Error": ".*this.domain.is.invalid.*"' # download -json with version should print JSON -# and download the .info file for the 'latest' version. go mod download -json 'rsc.io/quote@<=v1.5.0' stdout '^\t"Path": "rsc.io/quote"' stdout '^\t"Version": "v1.5.0"' @@ -28,14 +27,13 @@ stdout '^\t"Sum": "h1:6fJa6E\+wGadANKkUMlZ0DhXFpoKlslOQDCo259XtdIE="' # hash of stdout '^\t"GoModSum": "h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe\+TKr0="' ! stdout '"Error"' -exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.info - # download queries above should not have added to go.mod. go list -m all ! stdout rsc.io # add to go.mod so we can test non-query downloads go mod edit -require rsc.io/quote@v1.5.2 +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.info ! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.mod ! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip diff --git a/src/cmd/go/testdata/script/mod_download_latest.txt b/src/cmd/go/testdata/script/mod_download_latest.txt deleted file mode 100644 index 60d860e4da..0000000000 --- a/src/cmd/go/testdata/script/mod_download_latest.txt +++ /dev/null @@ -1,20 +0,0 @@ -env GO111MODULE=on - -# If the module is the latest version of itself, -# the Latest field should be set. -go mod download -json rsc.io/quote@v1.5.2 -stdout '"Latest":\s*true' - -# If the module is older than latest, the field should be unset. -go mod download -json rsc.io/quote@v1.5.1 -! stdout '"Latest":' - -# If the module is newer than "latest", the field should be unset... -go mod download -json rsc.io/quote@v1.5.3-pre1 -! stdout '"Latest":' - -# ...even if that version is also what is required by the main module. -go mod init example.com -go mod edit -require rsc.io/quote@v1.5.3-pre1 -go mod download -json rsc.io/quote@v1.5.3-pre1 -! stdout '"Latest":' diff --git a/src/cmd/go/testdata/script/mod_get_direct.txt b/src/cmd/go/testdata/script/mod_get_direct.txt new file mode 100644 index 0000000000..42ccbcd38a --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_direct.txt @@ -0,0 +1,20 @@ +# Regression test for golang.org/issue/34092: with an empty module cache, +# 'GOPROXY=direct go get golang.org/x/tools/gopls@master' did not correctly +# resolve the pseudo-version for its dependency on golang.org/x/tools. + +[short] skip +[!net] skip +[!exec:git] skip + +env GO111MODULE=on +env GOPROXY=direct +env GOSUMDB=off + +go list -m cloud.google.com/go@master +! stdout 'v0.0.0-' + +-- go.mod -- +module example.com + +go 1.14 +-- go.sum -- diff --git a/src/cmd/go/testdata/script/mod_get_insecure_redirect.txt b/src/cmd/go/testdata/script/mod_get_insecure_redirect.txt new file mode 100644 index 0000000000..a83b17672d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_insecure_redirect.txt @@ -0,0 +1,13 @@ +# golang.org/issue/29591: 'go get' was following plain-HTTP redirects even without -insecure. + +[!net] skip +[!exec:git] skip + +env GO111MODULE=on +env GOPROXY=direct +env GOSUMDB=off + +! go get -d vcs-test.golang.org/insecure/go/insecure +stderr 'redirected .* to insecure URL' + +go get -d -insecure vcs-test.golang.org/insecure/go/insecure diff --git a/src/cmd/go/testdata/script/mod_get_major.txt b/src/cmd/go/testdata/script/mod_get_major.txt new file mode 100644 index 0000000000..367ede9ded --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_major.txt @@ -0,0 +1,23 @@ +[!net] skip +[!exec:git] skip + +env GO111MODULE=on +env GOPROXY=direct +env GOSUMDB=off + +# golang.org/issue/34383: if a module path ends in a major-version suffix, +# ensure that 'direct' mode can resolve the package to a module. + +go get -d vcs-test.golang.org/git/v3pkg.git/v3@v3.0.0 + +go list -m vcs-test.golang.org/git/v3pkg.git/v3 +stdout '^vcs-test.golang.org/git/v3pkg.git/v3 v3.0.0$' + +go get -d vcs-test.golang.org/git/empty-v2-without-v1.git/v2@v2.0.0 + +go list -m vcs-test.golang.org/git/empty-v2-without-v1.git/v2 +stdout '^vcs-test.golang.org/git/empty-v2-without-v1.git/v2 v2.0.0$' + +-- go.mod -- +module example.com +go 1.13 diff --git a/src/cmd/go/testdata/script/mod_get_patterns.txt b/src/cmd/go/testdata/script/mod_get_patterns.txt index bfab70090c..8adc4b0c06 100644 --- a/src/cmd/go/testdata/script/mod_get_patterns.txt +++ b/src/cmd/go/testdata/script/mod_get_patterns.txt @@ -10,11 +10,11 @@ grep 'require rsc.io/quote' go.mod cp go.mod.orig go.mod ! go get -d rsc.io/quote/x... -stderr 'go get rsc.io/quote/x...: module rsc.io/quote@upgrade \(v1.5.2\) found, but does not contain packages matching rsc.io/quote/x...' +stderr 'go get rsc.io/quote/x...: module rsc.io/quote@upgrade found \(v1.5.2\), but does not contain packages matching rsc.io/quote/x...' ! grep 'require rsc.io/quote' go.mod ! go get -d rsc.io/quote/x/... -stderr 'go get rsc.io/quote/x/...: module rsc.io/quote@upgrade \(v1.5.2\) found, but does not contain packages matching rsc.io/quote/x/...' +stderr 'go get rsc.io/quote/x/...: module rsc.io/quote@upgrade found \(v1.5.2\), but does not contain packages matching rsc.io/quote/x/...' ! grep 'require rsc.io/quote' go.mod # If a pattern matches no packages within a module, the module should not diff --git a/src/cmd/go/testdata/script/mod_get_trailing_slash.txt b/src/cmd/go/testdata/script/mod_get_trailing_slash.txt new file mode 100644 index 0000000000..7b5d90c50b --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_trailing_slash.txt @@ -0,0 +1,30 @@ +# go list should succeed to load a package ending with ".go" if the path does +# not correspond to an existing local file. Listing a pattern ending with +# ".go/" should try to list a package regardless of whether a file exists at the +# path without the suffixed "/" or not. +go list example.com/dotgo.go +stdout ^example.com/dotgo.go$ +go list example.com/dotgo.go/ +stdout ^example.com/dotgo.go$ + +# go get -d should succeed in either case, with or without a version. +# Arguments are interpreted as packages or package patterns with versions, +# not source files. +go get -d example.com/dotgo.go +go get -d example.com/dotgo.go/ +go get -d example.com/dotgo.go@v1.0.0 +go get -d example.com/dotgo.go/@v1.0.0 + +# go get (without -d) should also succeed in either case. +[short] skip +go get example.com/dotgo.go +go get example.com/dotgo.go/ +go get example.com/dotgo.go@v1.0.0 +go get example.com/dotgo.go/@v1.0.0 + +-- go.mod -- +module m + +go 1.13 + +require example.com/dotgo.go v1.0.0 diff --git a/src/cmd/go/testdata/script/mod_list_upgrade.txt b/src/cmd/go/testdata/script/mod_list_upgrade.txt index f2d0649092..474df0dc26 100644 --- a/src/cmd/go/testdata/script/mod_list_upgrade.txt +++ b/src/cmd/go/testdata/script/mod_list_upgrade.txt @@ -1,28 +1,8 @@ env GO111MODULE=on -# If the current version is not latest, 'go list -u' should include its upgrade. go list -m -u all stdout 'rsc.io/quote v1.2.0 \[v1\.5\.2\]' -# If the current version is latest, 'go list -u' should omit the upgrade. -go get -d rsc.io/quote@v1.5.2 -go list -m -u all -stdout 'rsc.io/quote v1.5.2$' - -# If the current version is newer than latest, 'go list -u' should -# omit the upgrade. -go get -d rsc.io/quote@v1.5.3-pre1 -go list -m -u all -stdout 'rsc.io/quote v1.5.3-pre1$' - -# If the current build list has a higher version and the user asks about -# a lower one, -u should report the upgrade for the lower one -# but leave the build list unchanged. -go list -m -u rsc.io/quote@v1.5.1 -stdout 'rsc.io/quote v1.5.1 \[v1.5.2\]$' -go list -m -u rsc.io/quote -stdout 'rsc.io/quote v1.5.3-pre1$' - -- go.mod -- module x require rsc.io/quote v1.2.0 diff --git a/src/cmd/go/testdata/script/mod_replace.txt b/src/cmd/go/testdata/script/mod_replace.txt index 35824b3a8a..e4301b50d0 100644 --- a/src/cmd/go/testdata/script/mod_replace.txt +++ b/src/cmd/go/testdata/script/mod_replace.txt @@ -38,6 +38,13 @@ grep 'not-rsc.io/quote/v3 v3.1.0' go.mod exec ./a5.exe stdout 'Concurrency is not parallelism.' +# Error messages for modules not found in replacements should +# indicate the replacement module. +cp go.mod.orig go.mod +go mod edit -replace=rsc.io/quote/v3=./local/rsc.io/quote/v3 +! go get -d rsc.io/quote/v3/missing-package +stderr 'module rsc.io/quote/v3@upgrade found \(v3.0.0, replaced by ./local/rsc.io/quote/v3\), but does not contain package' + -- go.mod -- module quoter diff --git a/src/cmd/go/testdata/script/test_timeout.txt b/src/cmd/go/testdata/script/test_timeout.txt index 8dead0a439..4de4df4508 100644 --- a/src/cmd/go/testdata/script/test_timeout.txt +++ b/src/cmd/go/testdata/script/test_timeout.txt @@ -2,12 +2,13 @@ env GO111MODULE=off cd a -# No timeout is passed via 'go test' command. -go test -v +# If no timeout is set explicitly, 'go test' should set +# -test.timeout to its internal deadline. +go test -v . -- stdout '10m0s' -# Timeout is passed via 'go test' command. -go test -v -timeout 30m +# An explicit -timeout argument should be propagated to -test.timeout. +go test -v -timeout 30m . -- stdout '30m0s' -- a/timeout_test.go -- @@ -19,4 +20,4 @@ import ( ) func TestTimeout(t *testing.T) { fmt.Println(flag.Lookup("test.timeout").Value.String()) -}
\ No newline at end of file +} diff --git a/src/crypto/ecdsa/ecdsa.go b/src/crypto/ecdsa/ecdsa.go index be01a29606..22de2a5661 100644 --- a/src/crypto/ecdsa/ecdsa.go +++ b/src/crypto/ecdsa/ecdsa.go @@ -225,21 +225,14 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err // See [NSA] 3.4.1 c := priv.PublicKey.Curve - e := hashToInt(hash, c) - r, s, err = sign(priv, &csprng, c, e) - return -} - -func signGeneric(priv *PrivateKey, csprng *cipher.StreamReader, c elliptic.Curve, e *big.Int) (r, s *big.Int, err error) { N := c.Params().N if N.Sign() == 0 { return nil, nil, errZeroParam } - var k, kInv *big.Int for { for { - k, err = randFieldElement(c, *csprng) + k, err = randFieldElement(c, csprng) if err != nil { r = nil return @@ -257,6 +250,8 @@ func signGeneric(priv *PrivateKey, csprng *cipher.StreamReader, c elliptic.Curve break } } + + e := hashToInt(hash, c) s = new(big.Int).Mul(priv.D, r) s.Add(s, e) s.Mul(s, kInv) @@ -265,6 +260,7 @@ func signGeneric(priv *PrivateKey, csprng *cipher.StreamReader, c elliptic.Curve break } } + return } @@ -291,12 +287,8 @@ func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool { return false } e := hashToInt(hash, c) - return verify(pub, c, e, r, s) -} -func verifyGeneric(pub *PublicKey, c elliptic.Curve, e, r, s *big.Int) bool { var w *big.Int - N := c.Params().N if in, ok := c.(invertible); ok { w = in.Inverse(s) } else { diff --git a/src/crypto/ecdsa/ecdsa_noasm.go b/src/crypto/ecdsa/ecdsa_noasm.go deleted file mode 100644 index 2dfdb866d6..0000000000 --- a/src/crypto/ecdsa/ecdsa_noasm.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2019 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. - -// +build !s390x - -package ecdsa - -import ( - "crypto/cipher" - "crypto/elliptic" - "math/big" -) - -func sign(priv *PrivateKey, csprng *cipher.StreamReader, c elliptic.Curve, e *big.Int) (r, s *big.Int, err error) { - r, s, err = signGeneric(priv, csprng, c, e) - return -} - -func verify(pub *PublicKey, c elliptic.Curve, e, r, s *big.Int) bool { - return verifyGeneric(pub, c, e, r, s) -} diff --git a/src/crypto/ecdsa/ecdsa_s390x.go b/src/crypto/ecdsa/ecdsa_s390x.go deleted file mode 100644 index f07c3bf50c..0000000000 --- a/src/crypto/ecdsa/ecdsa_s390x.go +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright 2019 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. - -// +build s390x,!gccgo - -package ecdsa - -import ( - "crypto/cipher" - "crypto/elliptic" - "internal/cpu" - "math/big" -) - -// s390x accelerated signatures -//go:noescape -func kdsaSig(fc uint64, block *[1720]byte) (errn uint64) - -type signverify int - -const ( - signing signverify = iota - verifying -) - -// bufferOffsets represents the offset of a particular parameter in -// the buffer passed to the KDSA instruction. -type bufferOffsets struct { - baseSize int - hashSize int - offsetHash int - offsetKey1 int - offsetRNorKey2 int - offsetR int - offsetS int - functionCode uint64 -} - -func canUseKDSA(sv signverify, c elliptic.Curve, bo *bufferOffsets) bool { - if !cpu.S390X.HasECDSA { - return false - } - - switch c.Params().Name { - case "P-256": - bo.baseSize = 32 - bo.hashSize = 32 - bo.offsetHash = 64 - bo.offsetKey1 = 96 - bo.offsetRNorKey2 = 128 - bo.offsetR = 0 - bo.offsetS = 32 - if sv == signing { - bo.functionCode = 137 - } else { - bo.functionCode = 1 - } - return true - case "P-384": - bo.baseSize = 48 - bo.hashSize = 48 - bo.offsetHash = 96 - bo.offsetKey1 = 144 - bo.offsetRNorKey2 = 192 - bo.offsetR = 0 - bo.offsetS = 48 - if sv == signing { - bo.functionCode = 138 - } else { - bo.functionCode = 2 - } - return true - case "P-521": - bo.baseSize = 66 - bo.hashSize = 80 - bo.offsetHash = 160 - bo.offsetKey1 = 254 - bo.offsetRNorKey2 = 334 - bo.offsetR = 14 - bo.offsetS = 94 - if sv == signing { - bo.functionCode = 139 - } else { - bo.functionCode = 3 - } - return true - } - return false -} - -// zeroExtendAndCopy pads src with leading zeros until it has the size given. -// It then copies the padded src into the dst. Bytes beyond size in dst are -// not modified. -func zeroExtendAndCopy(dst, src []byte, size int) { - nz := size - len(src) - if nz < 0 { - panic("src is too long") - } - // the compiler should replace this loop with a memclr call - z := dst[:nz] - for i := range z { - z[i] = 0 - } - copy(dst[nz:size], src[:size-nz]) - return -} - -func sign(priv *PrivateKey, csprng *cipher.StreamReader, c elliptic.Curve, e *big.Int) (r, s *big.Int, err error) { - var bo bufferOffsets - if canUseKDSA(signing, c, &bo) && e.Sign() != 0 { - var buffer [1720]byte - for { - var k *big.Int - k, err = randFieldElement(c, csprng) - if err != nil { - return nil, nil, err - } - zeroExtendAndCopy(buffer[bo.offsetHash:], e.Bytes(), bo.hashSize) - zeroExtendAndCopy(buffer[bo.offsetKey1:], priv.D.Bytes(), bo.baseSize) - zeroExtendAndCopy(buffer[bo.offsetRNorKey2:], k.Bytes(), bo.baseSize) - errn := kdsaSig(bo.functionCode, &buffer) - if errn == 2 { - return nil, nil, errZeroParam - } - if errn == 0 { // success == 0 means successful signing - r = new(big.Int) - r.SetBytes(buffer[bo.offsetR : bo.offsetR+bo.baseSize]) - s = new(big.Int) - s.SetBytes(buffer[bo.offsetS : bo.offsetS+bo.baseSize]) - return - } - //at this point, it must be that errn == 1: retry - } - } - r, s, err = signGeneric(priv, csprng, c, e) - return -} - -func verify(pub *PublicKey, c elliptic.Curve, e, r, s *big.Int) bool { - var bo bufferOffsets - if canUseKDSA(verifying, c, &bo) && e.Sign() != 0 { - var buffer [1720]byte - zeroExtendAndCopy(buffer[bo.offsetR:], r.Bytes(), bo.baseSize) - zeroExtendAndCopy(buffer[bo.offsetS:], s.Bytes(), bo.baseSize) - zeroExtendAndCopy(buffer[bo.offsetHash:], e.Bytes(), bo.hashSize) - zeroExtendAndCopy(buffer[bo.offsetKey1:], pub.X.Bytes(), bo.baseSize) - zeroExtendAndCopy(buffer[bo.offsetRNorKey2:], pub.Y.Bytes(), bo.baseSize) - errn := kdsaSig(bo.functionCode, &buffer) - return errn == 0 - } - return verifyGeneric(pub, c, e, r, s) -} diff --git a/src/crypto/ecdsa/ecdsa_s390x.s b/src/crypto/ecdsa/ecdsa_s390x.s deleted file mode 100644 index 6ee00ce79c..0000000000 --- a/src/crypto/ecdsa/ecdsa_s390x.s +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2019 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. - -#include "textflag.h" - -// func kdsaSig(fc uint64, block *[1720]byte) (errn uint64) -TEXT ·kdsaSig(SB), NOSPLIT|NOFRAME, $0-24 - MOVD fc+0(FP), R0 // function code - MOVD block+8(FP), R1 // address parameter block - -loop: - WORD $0xB93A0008 // compute digital signature authentication - BVS loop // branch back if interrupted - BEQ success // signature creation successful - BGT retry // signing unsuccessful, but retry with new CSPRN - -error: - MOVD $2, R2 // fallthrough indicates fatal error - MOVD R2, errn+16(FP) // return 2 - sign/verify abort - RET - -retry: - MOVD $1, R2 - MOVD R2, errn+16(FP) // return 1 - sign/verify was unsuccessful -- if sign, retry with new RN - RET - -success: - MOVD $0, R2 - MOVD R2, errn+16(FP) // return 0 - sign/verify was successful - RET diff --git a/src/crypto/ecdsa/ecdsa_s390x_test.go b/src/crypto/ecdsa/ecdsa_s390x_test.go deleted file mode 100644 index 80babc9cb4..0000000000 --- a/src/crypto/ecdsa/ecdsa_s390x_test.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 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. - -// +build s390x,!gccgo - -package ecdsa - -import ( - "crypto/elliptic" - "testing" -) - -func TestNoAsm(t *testing.T) { - curves := [...]elliptic.Curve{ - elliptic.P256(), - elliptic.P384(), - elliptic.P521(), - } - - for _, curve := range curves { - // override the name of the curve to stop the assembly path being taken - params := *curve.Params() - name := params.Name - params.Name = name + "_GENERIC_OVERRIDE" - - testKeyGeneration(t, ¶ms, name) - testSignAndVerify(t, ¶ms, name) - testNonceSafety(t, ¶ms, name) - testINDCCA(t, ¶ms, name) - testNegativeInputs(t, ¶ms, name) - } -} diff --git a/src/errors/errors.go b/src/errors/errors.go index 85d4260762..d923ad4b70 100644 --- a/src/errors/errors.go +++ b/src/errors/errors.go @@ -13,16 +13,16 @@ // // If e.Unwrap() returns a non-nil error w, then we say that e wraps w. // +// Unwrap unpacks wrapped errors. If its argument's type has an +// Unwrap method, it calls the method once. Otherwise, it returns nil. +// // A simple way to create wrapped errors is to call fmt.Errorf and apply the %w verb // to the error argument: // -// fmt.Errorf("... %w ...", ..., err, ...).Unwrap() +// errors.Unwrap(fmt.Errorf("... %w ...", ..., err, ...)) // // returns err. // -// Unwrap unpacks wrapped errors. If its argument's type has an -// Unwrap method, it calls the method once. Otherwise, it returns nil. -// // Is unwraps its first argument sequentially looking for an error that matches the // second. It reports whether it finds a match. It should be used in preference to // simple equality checks: diff --git a/src/internal/syscall/windows/mksyscall.go b/src/internal/syscall/windows/mksyscall.go index 0bf87dc95c..95e36f7aa3 100644 --- a/src/internal/syscall/windows/mksyscall.go +++ b/src/internal/syscall/windows/mksyscall.go @@ -6,4 +6,4 @@ package windows -//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go security_windows.go psapi_windows.go symlink_windows.go +//go:generate go run golang.org/x/sys/windows/mkwinsyscall -output zsyscall_windows.go syscall_windows.go security_windows.go psapi_windows.go symlink_windows.go diff --git a/src/internal/syscall/windows/registry/mksyscall.go b/src/internal/syscall/windows/registry/mksyscall.go index fa8e27e8ff..cb4906a7b2 100644 --- a/src/internal/syscall/windows/registry/mksyscall.go +++ b/src/internal/syscall/windows/registry/mksyscall.go @@ -6,4 +6,4 @@ package registry -//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go syscall.go +//go:generate go run golang.org/x/sys/windows/mkwinsyscall -output zsyscall_windows.go syscall.go diff --git a/src/log/syslog/syslog_test.go b/src/log/syslog/syslog_test.go index 447654a874..8a28d67c98 100644 --- a/src/log/syslog/syslog_test.go +++ b/src/log/syslog/syslog_test.go @@ -134,6 +134,9 @@ func startServer(n, la string, done chan<- string) (addr string, sock io.Closer, } func TestWithSimulated(t *testing.T) { + if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") { + t.Skipf("sysctl is not supported on iOS") + } t.Parallel() msg := "Test 123" var transport []string @@ -272,6 +275,9 @@ func check(t *testing.T, in, out string) { } func TestWrite(t *testing.T) { + if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") { + t.Skipf("sysctl is not supported on iOS") + } t.Parallel() tests := []struct { pri Priority diff --git a/src/net/dnsclient_unix.go b/src/net/dnsclient_unix.go index e0a7ef8552..c90892b833 100644 --- a/src/net/dnsclient_unix.go +++ b/src/net/dnsclient_unix.go @@ -765,6 +765,14 @@ func (r *Resolver) goLookupPTR(ctx context.Context, addr string) ([]string, erro } } if h.Type != dnsmessage.TypePTR { + err := p.SkipAnswer() + if err != nil { + return nil, &DNSError{ + Err: "cannot marshal DNS message", + Name: addr, + Server: server, + } + } continue } ptr, err := p.PTRResource() diff --git a/src/net/dnsclient_unix_test.go b/src/net/dnsclient_unix_test.go index 98304d36ea..31cb6f721a 100644 --- a/src/net/dnsclient_unix_test.go +++ b/src/net/dnsclient_unix_test.go @@ -1753,3 +1753,50 @@ func TestDNSUseTCP(t *testing.T) { t.Fatal("exchange failed:", err) } } + +// Issue 34660: PTR response with non-PTR answers should ignore non-PTR +func TestPTRandNonPTR(t *testing.T) { + fake := fakeDNSServer{ + rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) { + r := dnsmessage.Message{ + Header: dnsmessage.Header{ + ID: q.Header.ID, + Response: true, + RCode: dnsmessage.RCodeSuccess, + }, + Questions: q.Questions, + Answers: []dnsmessage.Resource{ + { + Header: dnsmessage.ResourceHeader{ + Name: q.Questions[0].Name, + Type: dnsmessage.TypePTR, + Class: dnsmessage.ClassINET, + }, + Body: &dnsmessage.PTRResource{ + PTR: dnsmessage.MustNewName("golang.org."), + }, + }, + { + Header: dnsmessage.ResourceHeader{ + Name: q.Questions[0].Name, + Type: dnsmessage.TypeTXT, + Class: dnsmessage.ClassINET, + }, + Body: &dnsmessage.TXTResource{ + TXT: []string{"PTR 8 6 60 ..."}, // fake RRSIG + }, + }, + }, + } + return r, nil + }, + } + r := Resolver{PreferGo: true, Dial: fake.DialContext} + names, err := r.lookupAddr(context.Background(), "192.0.2.123") + if err != nil { + t.Fatalf("LookupAddr: %v", err) + } + if want := []string{"golang.org."}; !reflect.DeepEqual(names, want) { + t.Errorf("names = %q; want %q", names, want) + } +} diff --git a/src/net/http/client.go b/src/net/http/client.go index 65a9d51cc6..20496d2f0e 100644 --- a/src/net/http/client.go +++ b/src/net/http/client.go @@ -238,7 +238,7 @@ func send(ireq *Request, rt RoundTripper, deadline time.Time) (resp *Response, d username := u.Username() password, _ := u.Password() forkReq() - req.Header = ireq.Header.Clone() + req.Header = cloneOrMakeHeader(ireq.Header) req.Header.Set("Authorization", "Basic "+basicAuth(username, password)) } @@ -668,7 +668,7 @@ func (c *Client) makeHeadersCopier(ireq *Request) func(*Request) { // The headers to copy are from the very initial request. // We use a closured callback to keep a reference to these original headers. var ( - ireqhdr = ireq.Header.Clone() + ireqhdr = cloneOrMakeHeader(ireq.Header) icookies map[string][]*Cookie ) if c.Jar != nil && ireq.Header.Get("Cookie") != "" { diff --git a/src/net/http/clone.go b/src/net/http/clone.go index 5f2784d280..3a3375bff7 100644 --- a/src/net/http/clone.go +++ b/src/net/http/clone.go @@ -62,3 +62,13 @@ func cloneMultipartFileHeader(fh *multipart.FileHeader) *multipart.FileHeader { fh2.Header = textproto.MIMEHeader(Header(fh.Header).Clone()) return fh2 } + +// cloneOrMakeHeader invokes Header.Clone but if the +// result is nil, it'll instead make and return a non-nil Header. +func cloneOrMakeHeader(hdr Header) Header { + clone := hdr.Clone() + if clone == nil { + clone = make(Header) + } + return clone +} diff --git a/src/net/http/export_test.go b/src/net/http/export_test.go index d265cd3f72..e5c06a8903 100644 --- a/src/net/http/export_test.go +++ b/src/net/http/export_test.go @@ -208,6 +208,30 @@ func (t *Transport) PutIdleTestConn(scheme, addr string) bool { }) == nil } +// PutIdleTestConnH2 reports whether it was able to insert a fresh +// HTTP/2 persistConn for scheme, addr into the idle connection pool. +func (t *Transport) PutIdleTestConnH2(scheme, addr string, alt RoundTripper) bool { + key := connectMethodKey{"", scheme, addr, false} + + if t.MaxConnsPerHost > 0 { + // Transport is tracking conns-per-host. + // Increment connection count to account + // for new persistConn created below. + t.connsPerHostMu.Lock() + if t.connsPerHost == nil { + t.connsPerHost = make(map[connectMethodKey]int) + } + t.connsPerHost[key]++ + t.connsPerHostMu.Unlock() + } + + return t.tryPutIdleConn(&persistConn{ + t: t, + alt: alt, + cacheKey: key, + }) == nil +} + // All test hooks must be non-nil so they can be called directly, // but the tests use nil to mean hook disabled. func unnilTestHook(f *func()) { diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go index 53cc5bd1b8..e9a55f388a 100644 --- a/src/net/http/h2_bundle.go +++ b/src/net/http/h2_bundle.go @@ -10148,7 +10148,8 @@ type http2randomWriteScheduler struct { zero http2writeQueue // sq contains the stream-specific queues, keyed by stream ID. - // When a stream is idle or closed, it's deleted from the map. + // When a stream is idle, closed, or emptied, it's deleted + // from the map. sq map[uint32]*http2writeQueue // pool of empty queues for reuse. @@ -10192,8 +10193,12 @@ func (ws *http2randomWriteScheduler) Pop() (http2FrameWriteRequest, bool) { return ws.zero.shift(), true } // Iterate over all non-idle streams until finding one that can be consumed. - for _, q := range ws.sq { + for streamID, q := range ws.sq { if wr, ok := q.consume(math.MaxInt32); ok { + if q.empty() { + delete(ws.sq, streamID) + ws.queuePool.put(q) + } return wr, true } } diff --git a/src/net/http/header_test.go b/src/net/http/header_test.go index 51fcab103b..4789362919 100644 --- a/src/net/http/header_test.go +++ b/src/net/http/header_test.go @@ -7,6 +7,7 @@ package http import ( "bytes" "internal/race" + "reflect" "runtime" "testing" "time" @@ -219,3 +220,34 @@ func TestHeaderWriteSubsetAllocs(t *testing.T) { t.Errorf("allocs = %g; want 0", n) } } + +// Issue 34878: test that every call to +// cloneOrMakeHeader never returns a nil Header. +func TestCloneOrMakeHeader(t *testing.T) { + tests := []struct { + name string + in, want Header + }{ + {"nil", nil, Header{}}, + {"empty", Header{}, Header{}}, + { + name: "non-empty", + in: Header{"foo": {"bar"}}, + want: Header{"foo": {"bar"}}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := cloneOrMakeHeader(tt.in) + if got == nil { + t.Fatal("unexpected nil Header") + } + if !reflect.DeepEqual(got, tt.want) { + t.Fatalf("Got: %#v\nWant: %#v", got, tt.want) + } + got.Add("A", "B") + got.Get("A") + }) + } +} diff --git a/src/net/http/request_test.go b/src/net/http/request_test.go index b072f95802..bb06d922f0 100644 --- a/src/net/http/request_test.go +++ b/src/net/http/request_test.go @@ -826,6 +826,34 @@ func TestWithContextDeepCopiesURL(t *testing.T) { } } +func TestNoPanicOnRoundTripWithBasicAuth_h1(t *testing.T) { + testNoPanicWithBasicAuth(t, h1Mode) +} + +func TestNoPanicOnRoundTripWithBasicAuth_h2(t *testing.T) { + testNoPanicWithBasicAuth(t, h2Mode) +} + +// Issue 34878: verify we don't panic when including basic auth (Go 1.13 regression) +func testNoPanicWithBasicAuth(t *testing.T, h2 bool) { + defer afterTest(t) + cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {})) + defer cst.close() + + u, err := url.Parse(cst.ts.URL) + if err != nil { + t.Fatal(err) + } + u.User = url.UserPassword("foo", "bar") + req := &Request{ + URL: u, + Method: "GET", + } + if _, err := cst.c.Do(req); err != nil { + t.Fatalf("Unexpected error: %v", err) + } +} + // verify that NewRequest sets Request.GetBody and that it works func TestNewRequestGetBody(t *testing.T) { tests := []struct { diff --git a/src/net/http/server.go b/src/net/http/server.go index f554c81300..95a5eabaa2 100644 --- a/src/net/http/server.go +++ b/src/net/http/server.go @@ -3267,7 +3267,6 @@ type timeoutWriter struct { } var _ Pusher = (*timeoutWriter)(nil) -var _ Flusher = (*timeoutWriter)(nil) // Push implements the Pusher interface. func (tw *timeoutWriter) Push(target string, opts *PushOptions) error { @@ -3277,14 +3276,6 @@ func (tw *timeoutWriter) Push(target string, opts *PushOptions) error { return ErrNotSupported } -// Flush implements the Flusher interface. -func (tw *timeoutWriter) Flush() { - f, ok := tw.w.(Flusher) - if ok { - f.Flush() - } -} - func (tw *timeoutWriter) Header() Header { return tw.h } func (tw *timeoutWriter) Write(p []byte) (int, error) { diff --git a/src/net/http/transport.go b/src/net/http/transport.go index ee279877e0..caa4bdc36f 100644 --- a/src/net/http/transport.go +++ b/src/net/http/transport.go @@ -539,6 +539,7 @@ func (t *Transport) roundTrip(req *Request) (*Response, error) { } if http2isNoCachedConnError(err) { t.removeIdleConn(pconn) + t.decConnsPerHost(pconn.cacheKey) } else if !pconn.shouldRetryRequest(req, err) { // Issue 16465: return underlying net.Conn.Read error from peek, // as we've historically done. @@ -1206,7 +1207,9 @@ func (t *Transport) getConn(treq *transportRequest, cm connectMethod) (pc *persi // Queue for idle connection. if delivered := t.queueForIdleConn(w); delivered { pc := w.pc - if trace != nil && trace.GotConn != nil { + // Trace only for HTTP/1. + // HTTP/2 calls trace.GotConn itself. + if pc.alt == nil && trace != nil && trace.GotConn != nil { trace.GotConn(pc.gotIdleConnTrace(pc.idleAt)) } // set request canceler to some non-nil function so we diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go index 181d944d85..e43c8956ee 100644 --- a/src/net/http/transport_test.go +++ b/src/net/http/transport_test.go @@ -3562,6 +3562,76 @@ func TestTransportCloseIdleConnsThenReturn(t *testing.T) { wantIdle("after final put", 1) } +// Test for issue 34282 +// Ensure that getConn doesn't call the GotConn trace hook on a HTTP/2 idle conn +func TestTransportTraceGotConnH2IdleConns(t *testing.T) { + tr := &Transport{} + wantIdle := func(when string, n int) bool { + got := tr.IdleConnCountForTesting("https", "example.com:443") // key used by PutIdleTestConnH2 + if got == n { + return true + } + t.Errorf("%s: idle conns = %d; want %d", when, got, n) + return false + } + wantIdle("start", 0) + alt := funcRoundTripper(func() {}) + if !tr.PutIdleTestConnH2("https", "example.com:443", alt) { + t.Fatal("put failed") + } + wantIdle("after put", 1) + ctx := httptrace.WithClientTrace(context.Background(), &httptrace.ClientTrace{ + GotConn: func(httptrace.GotConnInfo) { + // tr.getConn should leave it for the HTTP/2 alt to call GotConn. + t.Error("GotConn called") + }, + }) + req, _ := NewRequestWithContext(ctx, MethodGet, "https://example.com", nil) + _, err := tr.RoundTrip(req) + if err != errFakeRoundTrip { + t.Errorf("got error: %v; want %q", err, errFakeRoundTrip) + } + wantIdle("after round trip", 1) +} + +func TestTransportRemovesH2ConnsAfterIdle(t *testing.T) { + if testing.Short() { + t.Skip("skipping in short mode") + } + + trFunc := func(tr *Transport) { + tr.MaxConnsPerHost = 1 + tr.MaxIdleConnsPerHost = 1 + tr.IdleConnTimeout = 10 * time.Millisecond + } + cst := newClientServerTest(t, h2Mode, HandlerFunc(func(w ResponseWriter, r *Request) {}), trFunc) + defer cst.close() + + if _, err := cst.c.Get(cst.ts.URL); err != nil { + t.Fatalf("got error: %s", err) + } + + time.Sleep(100 * time.Millisecond) + got := make(chan error) + go func() { + if _, err := cst.c.Get(cst.ts.URL); err != nil { + got <- err + } + close(got) + }() + + timeout := time.NewTimer(5 * time.Second) + defer timeout.Stop() + select { + case err := <-got: + if err != nil { + t.Fatalf("got error: %s", err) + } + case <-timeout.C: + t.Fatal("request never completed") + } +} + // This tests that an client requesting a content range won't also // implicitly ask for gzip support. If they want that, they need to do it // on their own. diff --git a/src/net/interface_test.go b/src/net/interface_test.go index fb6032fbc0..6cdfb6265f 100644 --- a/src/net/interface_test.go +++ b/src/net/interface_test.go @@ -51,6 +51,9 @@ func ipv6LinkLocalUnicastAddr(ifi *Interface) string { } func TestInterfaces(t *testing.T) { + if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") { + t.Skipf("sysctl is not supported on iOS") + } ift, err := Interfaces() if err != nil { t.Fatal(err) @@ -82,6 +85,9 @@ func TestInterfaces(t *testing.T) { } func TestInterfaceAddrs(t *testing.T) { + if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") { + t.Skipf("sysctl is not supported on iOS") + } ift, err := Interfaces() if err != nil { t.Fatal(err) @@ -101,6 +107,9 @@ func TestInterfaceAddrs(t *testing.T) { } func TestInterfaceUnicastAddrs(t *testing.T) { + if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") { + t.Skipf("sysctl is not supported on iOS") + } ift, err := Interfaces() if err != nil { t.Fatal(err) @@ -128,6 +137,9 @@ func TestInterfaceUnicastAddrs(t *testing.T) { } func TestInterfaceMulticastAddrs(t *testing.T) { + if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") { + t.Skipf("sysctl is not supported on iOS") + } ift, err := Interfaces() if err != nil { t.Fatal(err) diff --git a/src/os/os_test.go b/src/os/os_test.go index 6c88d7e8b8..b94ab0d232 100644 --- a/src/os/os_test.go +++ b/src/os/os_test.go @@ -1521,6 +1521,9 @@ func testWindowsHostname(t *testing.T, hostname string) { } func TestHostname(t *testing.T) { + if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") { + t.Skipf("sysctl is not supported on iOS") + } hostname, err := Hostname() if err != nil { t.Fatal(err) @@ -2251,8 +2254,6 @@ func TestPipeThreads(t *testing.T) { t.Skip("skipping on Plan 9; does not support runtime poller") case "js": t.Skip("skipping on js; no support for os.Pipe") - case "darwin": - t.Skip("skipping on Darwin; issue 33953") } threads := 100 diff --git a/src/runtime/export_test.go b/src/runtime/export_test.go index 6009932056..e4a7faf965 100644 --- a/src/runtime/export_test.go +++ b/src/runtime/export_test.go @@ -345,6 +345,9 @@ func ReadMemStatsSlow() (base, slow MemStats) { slow.HeapReleased += uint64(i.span().released()) } + // Unused space in the current arena also counts as released space. + slow.HeapReleased += uint64(mheap_.curArena.end - mheap_.curArena.base) + getg().m.mallocing-- }) diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go index 823b556e53..8a6b860c96 100644 --- a/src/runtime/mgc.go +++ b/src/runtime/mgc.go @@ -229,6 +229,8 @@ func setGCPercent(in int32) (out int32) { gcSetTriggerRatio(memstats.triggerRatio) unlock(&mheap_.lock) }) + // Pacing changed, so the scavenger should be awoken. + wakeScavenger() // If we just disabled GC, wait for any concurrent GC mark to // finish so we always return with no GC running. @@ -1649,9 +1651,16 @@ func gcMarkTermination(nextTriggerRatio float64) { throw("gc done but gcphase != _GCoff") } + // Record next_gc and heap_inuse for scavenger. + memstats.last_next_gc = memstats.next_gc + memstats.last_heap_inuse = memstats.heap_inuse + // Update GC trigger and pacing for the next cycle. gcSetTriggerRatio(nextTriggerRatio) + // Pacing changed, so the scavenger should be awoken. + wakeScavenger() + // Update timing memstats now := nanotime() sec, nsec, _ := time_now() diff --git a/src/runtime/mgcscavenge.go b/src/runtime/mgcscavenge.go index 45a9eb2b2a..c4394a3d60 100644 --- a/src/runtime/mgcscavenge.go +++ b/src/runtime/mgcscavenge.go @@ -17,7 +17,29 @@ // scavenger's primary goal is to bring the estimated heap RSS of the // application down to a goal. // -// That goal is defined as (retainExtraPercent+100) / 100 * next_gc. +// That goal is defined as: +// (retainExtraPercent+100) / 100 * (next_gc / last_next_gc) * last_heap_inuse +// +// Essentially, we wish to have the application's RSS track the heap goal, but +// the heap goal is defined in terms of bytes of objects, rather than pages like +// RSS. As a result, we need to take into account for fragmentation internal to +// spans. next_gc / last_next_gc defines the ratio between the current heap goal +// and the last heap goal, which tells us by how much the heap is growing and +// shrinking. We estimate what the heap will grow to in terms of pages by taking +// this ratio and multiplying it by heap_inuse at the end of the last GC, which +// allows us to account for this additional fragmentation. Note that this +// procedure makes the assumption that the degree of fragmentation won't change +// dramatically over the next GC cycle. Overestimating the amount of +// fragmentation simply results in higher memory use, which will be accounted +// for by the next pacing up date. Underestimating the fragmentation however +// could lead to performance degradation. Handling this case is not within the +// scope of the scavenger. Situations where the amount of fragmentation balloons +// over the course of a single GC cycle should be considered pathologies, +// flagged as bugs, and fixed appropriately. +// +// An additional factor of retainExtraPercent is added as a buffer to help ensure +// that there's more unscavenged memory to allocate out of, since each allocation +// out of scavenged memory incurs a potentially expensive page fault. // // The goal is updated after each GC and the scavenger's pacing parameters // (which live in mheap_) are updated to match. The pacing parameters work much @@ -81,14 +103,24 @@ func heapRetained() uint64 { // // mheap_.lock must be held or the world must be stopped. func gcPaceScavenger() { - // Compute our scavenging goal and align it to a physical page boundary - // to make the following calculations more exact. - retainedGoal := memstats.next_gc + // If we're called before the first GC completed, disable scavenging. + // We never scavenge before the 2nd GC cycle anyway (we don't have enough + // information about the heap yet) so this is fine, and avoids a fault + // or garbage data later. + if memstats.last_next_gc == 0 { + mheap_.scavengeBytesPerNS = 0 + return + } + // Compute our scavenging goal. + goalRatio := float64(memstats.next_gc) / float64(memstats.last_next_gc) + retainedGoal := uint64(float64(memstats.last_heap_inuse) * goalRatio) // Add retainExtraPercent overhead to retainedGoal. This calculation // looks strange but the purpose is to arrive at an integer division // (e.g. if retainExtraPercent = 12.5, then we get a divisor of 8) // that also avoids the overflow from a multiplication. retainedGoal += retainedGoal / (1.0 / (retainExtraPercent / 100.0)) + // Align it to a physical page boundary to make the following calculations + // a bit more exact. retainedGoal = (retainedGoal + uint64(physPageSize) - 1) &^ (uint64(physPageSize) - 1) // Represents where we are now in the heap's contribution to RSS in bytes. @@ -154,36 +186,41 @@ func gcPaceScavenger() { now := nanotime() - lock(&scavenge.lock) - // Update all the pacing parameters in mheap with scavenge.lock held, // so that scavenge.gen is kept in sync with the updated values. mheap_.scavengeRetainedGoal = retainedGoal mheap_.scavengeRetainedBasis = retainedNow mheap_.scavengeTimeBasis = now mheap_.scavengeBytesPerNS = float64(totalWork) / float64(totalTime) - scavenge.gen++ // increase scavenge generation - - // Wake up background scavenger if needed, since the pacing was just updated. - wakeScavengerLocked() - - unlock(&scavenge.lock) + mheap_.scavengeGen++ // increase scavenge generation } -// State of the background scavenger. +// Sleep/wait state of the background scavenger. var scavenge struct { lock mutex g *g parked bool timer *timer - gen uint32 // read with either lock or mheap_.lock, write with both + + // Generation counter. + // + // It represents the last generation count (as defined by + // mheap_.scavengeGen) checked by the scavenger and is updated + // each time the scavenger checks whether it is on-pace. + // + // Skew between this field and mheap_.scavengeGen is used to + // determine whether a new update is available. + // + // Protected by mheap_.lock. + gen uint64 } -// wakeScavengerLocked unparks the scavenger if necessary. It must be called +// wakeScavenger unparks the scavenger if necessary. It must be called // after any pacing update. // -// scavenge.lock must be held. -func wakeScavengerLocked() { +// mheap_.lock and scavenge.lock must not be held. +func wakeScavenger() { + lock(&scavenge.lock) if scavenge.parked { // Try to stop the timer but we don't really care if we succeed. // It's possible that either a timer was never started, or that @@ -198,11 +235,10 @@ func wakeScavengerLocked() { scavenge.parked = false ready(scavenge.g, 0, true) } + unlock(&scavenge.lock) } // scavengeSleep attempts to put the scavenger to sleep for ns. -// It also checks to see if gen != scavenge.gen before going to sleep, -// and aborts if true (meaning an update had occurred). // // Note that this function should only be called by the scavenger. // @@ -210,24 +246,32 @@ func wakeScavengerLocked() { // to sleep at all if there's a pending pacing change. // // Returns false if awoken early (i.e. true means a complete sleep). -func scavengeSleep(gen uint32, ns int64) bool { +func scavengeSleep(ns int64) bool { lock(&scavenge.lock) - // If there was an update, just abort the sleep. - if scavenge.gen != gen { + // First check if there's a pending update. + // If there is one, don't bother sleeping. + var hasUpdate bool + systemstack(func() { + lock(&mheap_.lock) + hasUpdate = mheap_.scavengeGen != scavenge.gen + unlock(&mheap_.lock) + }) + if hasUpdate { unlock(&scavenge.lock) return false } // Set the timer. + // + // This must happen here instead of inside gopark + // because we can't close over any variables without + // failing escape analysis. now := nanotime() scavenge.timer.when = now + ns startTimer(scavenge.timer) - // Park the goroutine. It's fine that we don't publish the - // fact that the timer was set; even if the timer wakes up - // and fire scavengeReady before we park, it'll block on - // scavenge.lock. + // Mark ourself as asleep and go to sleep. scavenge.parked = true goparkunlock(&scavenge.lock, waitReasonSleep, traceEvGoSleep, 2) @@ -248,9 +292,7 @@ func bgscavenge(c chan int) { scavenge.timer = new(timer) scavenge.timer.f = func(_ interface{}, _ uintptr) { - lock(&scavenge.lock) - wakeScavengerLocked() - unlock(&scavenge.lock) + wakeScavenger() } c <- 1 @@ -279,14 +321,14 @@ func bgscavenge(c chan int) { released := uintptr(0) park := false ttnext := int64(0) - gen := uint32(0) // Run on the system stack since we grab the heap lock, // and a stack growth with the heap lock means a deadlock. systemstack(func() { lock(&mheap_.lock) - gen = scavenge.gen + // Update the last generation count that the scavenger has handled. + scavenge.gen = mheap_.scavengeGen // If background scavenging is disabled or if there's no work to do just park. retained := heapRetained() @@ -343,7 +385,7 @@ func bgscavenge(c chan int) { if released == 0 { // If we were unable to release anything this may be because there's // no free memory available to scavenge. Go to sleep and try again. - if scavengeSleep(gen, retryDelayNS) { + if scavengeSleep(retryDelayNS) { // If we successfully slept through the delay, back off exponentially. retryDelayNS *= 2 } @@ -355,7 +397,7 @@ func bgscavenge(c chan int) { // If there's an appreciable amount of time until the next scavenging // goal, just sleep. We'll get woken up if anything changes and this // way we avoid spinning. - scavengeSleep(gen, ttnext) + scavengeSleep(ttnext) continue } diff --git a/src/runtime/mheap.go b/src/runtime/mheap.go index 706603aba4..3807050cbe 100644 --- a/src/runtime/mheap.go +++ b/src/runtime/mheap.go @@ -107,6 +107,7 @@ type mheap struct { scavengeRetainedBasis uint64 scavengeBytesPerNS float64 scavengeRetainedGoal uint64 + scavengeGen uint64 // incremented on each pacing update // Page reclaimer state @@ -185,6 +186,12 @@ type mheap struct { // simply blocking GC (by disabling preemption). sweepArenas []arenaIdx + // curArena is the arena that the heap is currently growing + // into. This should always be physPageSize-aligned. + curArena struct { + base, end uintptr + } + _ uint32 // ensure 64-bit alignment of central // central free lists for small size classes. @@ -1220,16 +1227,6 @@ HaveSpan: // heap_released since we already did so earlier. sysUsed(unsafe.Pointer(s.base()), s.npages<<_PageShift) s.scavenged = false - - // Since we allocated out of a scavenged span, we just - // grew the RSS. Mitigate this by scavenging enough free - // space to make up for it but only if we need to. - // - // scavengeLocked may cause coalescing, so prevent - // coalescing with s by temporarily changing its state. - s.state = mSpanManual - h.scavengeIfNeededLocked(s.npages * pageSize) - s.state = mSpanFree } h.setSpans(s.base(), npage, s) @@ -1249,29 +1246,78 @@ HaveSpan: // h must be locked. func (h *mheap) grow(npage uintptr) bool { ask := npage << _PageShift - v, size := h.sysAlloc(ask) - if v == nil { - print("runtime: out of memory: cannot allocate ", ask, "-byte block (", memstats.heap_sys, " in use)\n") - return false - } - // Create a fake "in use" span and free it, so that the - // right accounting and coalescing happens. + nBase := round(h.curArena.base+ask, physPageSize) + if nBase > h.curArena.end { + // Not enough room in the current arena. Allocate more + // arena space. This may not be contiguous with the + // current arena, so we have to request the full ask. + av, asize := h.sysAlloc(ask) + if av == nil { + print("runtime: out of memory: cannot allocate ", ask, "-byte block (", memstats.heap_sys, " in use)\n") + return false + } + + if uintptr(av) == h.curArena.end { + // The new space is contiguous with the old + // space, so just extend the current space. + h.curArena.end = uintptr(av) + asize + } else { + // The new space is discontiguous. Track what + // remains of the current space and switch to + // the new space. This should be rare. + if size := h.curArena.end - h.curArena.base; size != 0 { + h.growAddSpan(unsafe.Pointer(h.curArena.base), size) + } + // Switch to the new space. + h.curArena.base = uintptr(av) + h.curArena.end = uintptr(av) + asize + } + + // The memory just allocated counts as both released + // and idle, even though it's not yet backed by spans. + // + // The allocation is always aligned to the heap arena + // size which is always > physPageSize, so its safe to + // just add directly to heap_released. Coalescing, if + // possible, will also always be correct in terms of + // accounting, because s.base() must be a physical + // page boundary. + memstats.heap_released += uint64(asize) + memstats.heap_idle += uint64(asize) + + // Recalculate nBase + nBase = round(h.curArena.base+ask, physPageSize) + } + + // Grow into the current arena. + v := h.curArena.base + h.curArena.base = nBase + h.growAddSpan(unsafe.Pointer(v), nBase-v) + return true +} + +// growAddSpan adds a free span when the heap grows into [v, v+size). +// This memory must be in the Prepared state (not Ready). +// +// h must be locked. +func (h *mheap) growAddSpan(v unsafe.Pointer, size uintptr) { + // Scavenge some pages to make up for the virtual memory space + // we just allocated, but only if we need to. + h.scavengeIfNeededLocked(size) + s := (*mspan)(h.spanalloc.alloc()) s.init(uintptr(v), size/pageSize) h.setSpans(s.base(), s.npages, s) s.state = mSpanFree - memstats.heap_idle += uint64(size) - // (*mheap).sysAlloc returns untouched/uncommitted memory. + // [v, v+size) is always in the Prepared state. The new span + // must be marked scavenged so the allocator transitions it to + // Ready when allocating from it. s.scavenged = true - // s is always aligned to the heap arena size which is always > physPageSize, - // so its totally safe to just add directly to heap_released. Coalescing, - // if possible, will also always be correct in terms of accounting, because - // s.base() must be a physical page boundary. - memstats.heap_released += uint64(size) + // This span is both released and idle, but grow already + // updated both memstats. h.coalesce(s) h.free.insert(s) - return true } // Free the span back into the heap. diff --git a/src/runtime/mstats.go b/src/runtime/mstats.go index 421580eec3..09dbb26735 100644 --- a/src/runtime/mstats.go +++ b/src/runtime/mstats.go @@ -79,6 +79,8 @@ type mstats struct { last_gc_nanotime uint64 // last gc (monotonic time) tinyallocs uint64 // number of tiny allocations that didn't cause actual allocation; not exported to go directly + last_next_gc uint64 // next_gc for the previous GC + last_heap_inuse uint64 // heap_inuse at mark termination of the previous GC // triggerRatio is the heap growth ratio that triggers marking. // diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go index 074ae0f40d..1cd0932eae 100644 --- a/src/runtime/os_windows.go +++ b/src/runtime/os_windows.go @@ -49,6 +49,7 @@ const ( //go:cgo_import_dynamic runtime._VirtualFree VirtualFree%3 "kernel32.dll" //go:cgo_import_dynamic runtime._VirtualQuery VirtualQuery%3 "kernel32.dll" //go:cgo_import_dynamic runtime._WaitForSingleObject WaitForSingleObject%2 "kernel32.dll" +//go:cgo_import_dynamic runtime._WaitForMultipleObjects WaitForMultipleObjects%4 "kernel32.dll" //go:cgo_import_dynamic runtime._WriteConsoleW WriteConsoleW%5 "kernel32.dll" //go:cgo_import_dynamic runtime._WriteFile WriteFile%5 "kernel32.dll" @@ -96,6 +97,7 @@ var ( _VirtualFree, _VirtualQuery, _WaitForSingleObject, + _WaitForMultipleObjects, _WriteConsoleW, _WriteFile, _ stdFunction @@ -139,7 +141,8 @@ func tstart_stdcall(newm *m) func ctrlhandler() type mOS struct { - waitsema uintptr // semaphore for parking on locks + waitsema uintptr // semaphore for parking on locks + resumesema uintptr // semaphore to indicate suspend/resume } //go:linkname os_sigpipe os.sigpipe @@ -258,6 +261,40 @@ func loadOptionalSyscalls() { } } +func monitorSuspendResume() { + const _DEVICE_NOTIFY_CALLBACK = 2 + type _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS struct { + callback uintptr + context uintptr + } + + powrprof := windowsLoadSystemLib([]byte("powrprof.dll\000")) + if powrprof == 0 { + return // Running on Windows 7, where we don't need it anyway. + } + powerRegisterSuspendResumeNotification := windowsFindfunc(powrprof, []byte("PowerRegisterSuspendResumeNotification\000")) + if powerRegisterSuspendResumeNotification == nil { + return // Running on Windows 7, where we don't need it anyway. + } + var fn interface{} = func(context uintptr, changeType uint32, setting uintptr) uintptr { + for mp := (*m)(atomic.Loadp(unsafe.Pointer(&allm))); mp != nil; mp = mp.alllink { + if mp.resumesema != 0 { + stdcall1(_SetEvent, mp.resumesema) + } + } + return 0 + } + params := _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS{ + callback: compileCallback(*efaceOf(&fn), true), + } + handle := uintptr(0) + if stdcall3(powerRegisterSuspendResumeNotification, _DEVICE_NOTIFY_CALLBACK, + uintptr(unsafe.Pointer(¶ms)), + uintptr(unsafe.Pointer(&handle))) != 0 { + throw("PowerRegisterSuspendResumeNotification failure") + } +} + //go:nosplit func getLoadLibrary() uintptr { return uintptr(unsafe.Pointer(_LoadLibraryW)) @@ -488,6 +525,10 @@ func goenvs() { } stdcall1(_FreeEnvironmentStringsW, uintptr(strings)) + + // We call this all the way here, late in init, so that malloc works + // for the callback function this generates. + monitorSuspendResume() } // exiting is set to non-zero when the process is exiting. @@ -606,19 +647,32 @@ func semasleep(ns int64) int32 { _WAIT_FAILED = 0xFFFFFFFF ) - // store ms in ns to save stack space + var result uintptr if ns < 0 { - ns = _INFINITE + result = stdcall2(_WaitForSingleObject, getg().m.waitsema, uintptr(_INFINITE)) } else { - ns = int64(timediv(ns, 1000000, nil)) - if ns == 0 { - ns = 1 + start := nanotime() + elapsed := int64(0) + for { + ms := int64(timediv(ns-elapsed, 1000000, nil)) + if ms == 0 { + ms = 1 + } + result = stdcall4(_WaitForMultipleObjects, 2, + uintptr(unsafe.Pointer(&[2]uintptr{getg().m.waitsema, getg().m.resumesema})), + 0, uintptr(ms)) + if result != _WAIT_OBJECT_0+1 { + // Not a suspend/resume event + break + } + elapsed = nanotime() - start + if elapsed >= ns { + return -1 + } } } - - result := stdcall2(_WaitForSingleObject, getg().m.waitsema, uintptr(ns)) switch result { - case _WAIT_OBJECT_0: //signaled + case _WAIT_OBJECT_0: // Signaled return 0 case _WAIT_TIMEOUT: @@ -667,6 +721,15 @@ func semacreate(mp *m) { throw("runtime.semacreate") }) } + mp.resumesema = stdcall4(_CreateEventA, 0, 0, 0, 0) + if mp.resumesema == 0 { + systemstack(func() { + print("runtime: createevent failed; errno=", getlasterror(), "\n") + throw("runtime.semacreate") + }) + stdcall1(_CloseHandle, mp.waitsema) + mp.waitsema = 0 + } } // May run with m.p==nil, so write barriers are not allowed. This diff --git a/src/runtime/sys_darwin.go b/src/runtime/sys_darwin.go index 376f76dbc5..a630d53a6e 100644 --- a/src/runtime/sys_darwin.go +++ b/src/runtime/sys_darwin.go @@ -60,7 +60,7 @@ func libcCall(fn, arg unsafe.Pointer) int32 { //go:nosplit //go:cgo_unsafe_args func syscall_syscall(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) { - entersyscallblock() + entersyscall() libcCall(unsafe.Pointer(funcPC(syscall)), unsafe.Pointer(&fn)) exitsyscall() return @@ -71,7 +71,7 @@ func syscall() //go:nosplit //go:cgo_unsafe_args func syscall_syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) { - entersyscallblock() + entersyscall() libcCall(unsafe.Pointer(funcPC(syscall6)), unsafe.Pointer(&fn)) exitsyscall() return @@ -82,7 +82,7 @@ func syscall6() //go:nosplit //go:cgo_unsafe_args func syscall_syscall6X(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) { - entersyscallblock() + entersyscall() libcCall(unsafe.Pointer(funcPC(syscall6X)), unsafe.Pointer(&fn)) exitsyscall() return @@ -93,7 +93,7 @@ func syscall6X() //go:nosplit //go:cgo_unsafe_args func syscall_syscallPtr(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) { - entersyscallblock() + entersyscall() libcCall(unsafe.Pointer(funcPC(syscallPtr)), unsafe.Pointer(&fn)) exitsyscall() return diff --git a/src/runtime/syscall_windows.go b/src/runtime/syscall_windows.go index 722a73d108..0e2fcfb02d 100644 --- a/src/runtime/syscall_windows.go +++ b/src/runtime/syscall_windows.go @@ -74,16 +74,18 @@ func compileCallback(fn eface, cleanstack bool) (code uintptr) { argsize += uintptrSize } - lock(&cbs.lock) - defer unlock(&cbs.lock) + lock(&cbs.lock) // We don't unlock this in a defer because this is used from the system stack. n := cbs.n for i := 0; i < n; i++ { if cbs.ctxt[i].gobody == fn.data && cbs.ctxt[i].isCleanstack() == cleanstack { - return callbackasmAddr(i) + r := callbackasmAddr(i) + unlock(&cbs.lock) + return r } } if n >= cb_max { + unlock(&cbs.lock) throw("too many callback functions") } @@ -99,7 +101,9 @@ func compileCallback(fn eface, cleanstack bool) (code uintptr) { cbs.ctxt[n] = c cbs.n++ - return callbackasmAddr(n) + r := callbackasmAddr(n) + unlock(&cbs.lock) + return r } const _LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800 diff --git a/src/syscall/mksyscall_windows.go b/src/syscall/mksyscall_windows.go index ee2123f939..d66bf7865f 100644 --- a/src/syscall/mksyscall_windows.go +++ b/src/syscall/mksyscall_windows.go @@ -4,897 +4,23 @@ // +build ignore -/* -mksyscall_windows generates windows system call bodies - -It parses all files specified on command line containing function -prototypes (like syscall_windows.go) and prints system call bodies -to standard output. - -The prototypes are marked by lines beginning with "//sys" and read -like func declarations if //sys is replaced by func, but: - -* The parameter lists must give a name for each argument. This - includes return parameters. - -* The parameter lists must give a type for each argument: - the (x, y, z int) shorthand is not allowed. - -* If the return parameter is an error number, it must be named err. - -* If go func name needs to be different from its winapi dll name, - the winapi name could be specified at the end, after "=" sign, like - //sys LoadLibrary(libname string) (handle uint32, err error) = LoadLibraryA - -* Each function that returns err needs to supply a condition, that - return value of winapi will be tested against to detect failure. - This would set err to windows "last-error", otherwise it will be nil. - The value can be provided at end of //sys declaration, like - //sys LoadLibrary(libname string) (handle uint32, err error) [failretval==-1] = LoadLibraryA - and is [failretval==0] by default. - -Usage: - mksyscall_windows [flags] [path ...] - -The flags are: - -output - Specify output file name (outputs to console if blank). - -trace - Generate print statement after every syscall. -*/ package main import ( - "bufio" - "bytes" - "errors" - "flag" - "fmt" - "go/format" - "go/parser" - "go/token" - "io" - "io/ioutil" - "log" "os" + "os/exec" "path/filepath" "runtime" - "sort" - "strconv" - "strings" - "text/template" -) - -var ( - filename = flag.String("output", "", "output file name (standard output if omitted)") - printTraceFlag = flag.Bool("trace", false, "generate print statement after every syscall") - systemDLL = flag.Bool("systemdll", true, "whether all DLLs should be loaded from the Windows system directory") ) -func trim(s string) string { - return strings.Trim(s, " \t") -} - -var packageName string - -func packagename() string { - return packageName -} - -func syscalldot() string { - if packageName == "syscall" { - return "" - } - return "syscall." -} - -// Param is function parameter -type Param struct { - Name string - Type string - fn *Fn - tmpVarIdx int -} - -// tmpVar returns temp variable name that will be used to represent p during syscall. -func (p *Param) tmpVar() string { - if p.tmpVarIdx < 0 { - p.tmpVarIdx = p.fn.curTmpVarIdx - p.fn.curTmpVarIdx++ - } - return fmt.Sprintf("_p%d", p.tmpVarIdx) -} - -// BoolTmpVarCode returns source code for bool temp variable. -func (p *Param) BoolTmpVarCode() string { - const code = `var %s uint32 - if %s { - %s = 1 - } else { - %s = 0 - }` - tmp := p.tmpVar() - return fmt.Sprintf(code, tmp, p.Name, tmp, tmp) -} - -// SliceTmpVarCode returns source code for slice temp variable. -func (p *Param) SliceTmpVarCode() string { - const code = `var %s *%s - if len(%s) > 0 { - %s = &%s[0] - }` - tmp := p.tmpVar() - return fmt.Sprintf(code, tmp, p.Type[2:], p.Name, tmp, p.Name) -} - -// StringTmpVarCode returns source code for string temp variable. -func (p *Param) StringTmpVarCode() string { - errvar := p.fn.Rets.ErrorVarName() - if errvar == "" { - errvar = "_" - } - tmp := p.tmpVar() - const code = `var %s %s - %s, %s = %s(%s)` - s := fmt.Sprintf(code, tmp, p.fn.StrconvType(), tmp, errvar, p.fn.StrconvFunc(), p.Name) - if errvar == "-" { - return s - } - const morecode = ` - if %s != nil { - return - }` - return s + fmt.Sprintf(morecode, errvar) -} - -// TmpVarCode returns source code for temp variable. -func (p *Param) TmpVarCode() string { - switch { - case p.Type == "bool": - return p.BoolTmpVarCode() - case strings.HasPrefix(p.Type, "[]"): - return p.SliceTmpVarCode() - default: - return "" - } -} - -// TmpVarHelperCode returns source code for helper's temp variable. -func (p *Param) TmpVarHelperCode() string { - if p.Type != "string" { - return "" - } - return p.StringTmpVarCode() -} - -// SyscallArgList returns source code fragments representing p parameter -// in syscall. Slices are translated into 2 syscall parameters: pointer to -// the first element and length. -func (p *Param) SyscallArgList() []string { - t := p.HelperType() - var s string - switch { - case t[0] == '*': - s = fmt.Sprintf("unsafe.Pointer(%s)", p.Name) - case t == "bool": - s = p.tmpVar() - case strings.HasPrefix(t, "[]"): - return []string{ - fmt.Sprintf("uintptr(unsafe.Pointer(%s))", p.tmpVar()), - fmt.Sprintf("uintptr(len(%s))", p.Name), - } - default: - s = p.Name - } - return []string{fmt.Sprintf("uintptr(%s)", s)} -} - -// IsError determines if p parameter is used to return error. -func (p *Param) IsError() bool { - return p.Name == "err" && p.Type == "error" -} - -// HelperType returns type of parameter p used in helper function. -func (p *Param) HelperType() string { - if p.Type == "string" { - return p.fn.StrconvType() - } - return p.Type -} - -// join concatenates parameters ps into a string with sep separator. -// Each parameter is converted into string by applying fn to it -// before conversion. -func join(ps []*Param, fn func(*Param) string, sep string) string { - if len(ps) == 0 { - return "" - } - a := make([]string, 0) - for _, p := range ps { - a = append(a, fn(p)) - } - return strings.Join(a, sep) -} - -// Rets describes function return parameters. -type Rets struct { - Name string - Type string - ReturnsError bool - FailCond string -} - -// ErrorVarName returns error variable name for r. -func (r *Rets) ErrorVarName() string { - if r.ReturnsError { - return "err" - } - if r.Type == "error" { - return r.Name - } - return "" -} - -// ToParams converts r into slice of *Param. -func (r *Rets) ToParams() []*Param { - ps := make([]*Param, 0) - if len(r.Name) > 0 { - ps = append(ps, &Param{Name: r.Name, Type: r.Type}) - } - if r.ReturnsError { - ps = append(ps, &Param{Name: "err", Type: "error"}) - } - return ps -} - -// List returns source code of syscall return parameters. -func (r *Rets) List() string { - s := join(r.ToParams(), func(p *Param) string { return p.Name + " " + p.Type }, ", ") - if len(s) > 0 { - s = "(" + s + ")" - } - return s -} - -// PrintList returns source code of trace printing part correspondent -// to syscall return values. -func (r *Rets) PrintList() string { - return join(r.ToParams(), func(p *Param) string { return fmt.Sprintf(`"%s=", %s, `, p.Name, p.Name) }, `", ", `) -} - -// SetReturnValuesCode returns source code that accepts syscall return values. -func (r *Rets) SetReturnValuesCode() string { - if r.Name == "" && !r.ReturnsError { - return "" - } - retvar := "r0" - if r.Name == "" { - retvar = "r1" - } - errvar := "_" - if r.ReturnsError { - errvar = "e1" - } - return fmt.Sprintf("%s, _, %s := ", retvar, errvar) -} - -func (r *Rets) useLongHandleErrorCode(retvar string) string { - const code = `if %s { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = %sEINVAL - } - }` - cond := retvar + " == 0" - if r.FailCond != "" { - cond = strings.Replace(r.FailCond, "failretval", retvar, 1) - } - return fmt.Sprintf(code, cond, syscalldot()) -} - -// SetErrorCode returns source code that sets return parameters. -func (r *Rets) SetErrorCode() string { - const code = `if r0 != 0 { - %s = %sErrno(r0) - }` - if r.Name == "" && !r.ReturnsError { - return "" - } - if r.Name == "" { - return r.useLongHandleErrorCode("r1") - } - if r.Type == "error" { - return fmt.Sprintf(code, r.Name, syscalldot()) - } - s := "" - switch { - case r.Type[0] == '*': - s = fmt.Sprintf("%s = (%s)(unsafe.Pointer(r0))", r.Name, r.Type) - case r.Type == "bool": - s = fmt.Sprintf("%s = r0 != 0", r.Name) - default: - s = fmt.Sprintf("%s = %s(r0)", r.Name, r.Type) - } - if !r.ReturnsError { - return s - } - return s + "\n\t" + r.useLongHandleErrorCode(r.Name) -} - -// Fn describes syscall function. -type Fn struct { - Name string - Params []*Param - Rets *Rets - PrintTrace bool - dllname string - dllfuncname string - src string - // TODO: get rid of this field and just use parameter index instead - curTmpVarIdx int // insure tmp variables have uniq names -} - -// extractParams parses s to extract function parameters. -func extractParams(s string, f *Fn) ([]*Param, error) { - s = trim(s) - if s == "" { - return nil, nil - } - a := strings.Split(s, ",") - ps := make([]*Param, len(a)) - for i := range ps { - s2 := trim(a[i]) - b := strings.Split(s2, " ") - if len(b) != 2 { - b = strings.Split(s2, "\t") - if len(b) != 2 { - return nil, errors.New("Could not extract function parameter from \"" + s2 + "\"") - } - } - ps[i] = &Param{ - Name: trim(b[0]), - Type: trim(b[1]), - fn: f, - tmpVarIdx: -1, - } - } - return ps, nil -} - -// extractSection extracts text out of string s starting after start -// and ending just before end. found return value will indicate success, -// and prefix, body and suffix will contain correspondent parts of string s. -func extractSection(s string, start, end rune) (prefix, body, suffix string, found bool) { - s = trim(s) - if strings.HasPrefix(s, string(start)) { - // no prefix - body = s[1:] - } else { - a := strings.SplitN(s, string(start), 2) - if len(a) != 2 { - return "", "", s, false - } - prefix = a[0] - body = a[1] - } - a := strings.SplitN(body, string(end), 2) - if len(a) != 2 { - return "", "", "", false - } - return prefix, a[0], a[1], true -} - -// newFn parses string s and return created function Fn. -func newFn(s string) (*Fn, error) { - s = trim(s) - f := &Fn{ - Rets: &Rets{}, - src: s, - PrintTrace: *printTraceFlag, - } - // function name and args - prefix, body, s, found := extractSection(s, '(', ')') - if !found || prefix == "" { - return nil, errors.New("Could not extract function name and parameters from \"" + f.src + "\"") - } - f.Name = prefix - var err error - f.Params, err = extractParams(body, f) - if err != nil { - return nil, err - } - // return values - _, body, s, found = extractSection(s, '(', ')') - if found { - r, err := extractParams(body, f) - if err != nil { - return nil, err - } - switch len(r) { - case 0: - case 1: - if r[0].IsError() { - f.Rets.ReturnsError = true - } else { - f.Rets.Name = r[0].Name - f.Rets.Type = r[0].Type - } - case 2: - if !r[1].IsError() { - return nil, errors.New("Only last windows error is allowed as second return value in \"" + f.src + "\"") - } - f.Rets.ReturnsError = true - f.Rets.Name = r[0].Name - f.Rets.Type = r[0].Type - default: - return nil, errors.New("Too many return values in \"" + f.src + "\"") - } - } - // fail condition - _, body, s, found = extractSection(s, '[', ']') - if found { - f.Rets.FailCond = body - } - // dll and dll function names - s = trim(s) - if s == "" { - return f, nil - } - if !strings.HasPrefix(s, "=") { - return nil, errors.New("Could not extract dll name from \"" + f.src + "\"") - } - s = trim(s[1:]) - a := strings.Split(s, ".") - switch len(a) { - case 1: - f.dllfuncname = a[0] - case 2: - f.dllname = a[0] - f.dllfuncname = a[1] - default: - return nil, errors.New("Could not extract dll name from \"" + f.src + "\"") - } - return f, nil -} - -// DLLName returns DLL name for function f. -func (f *Fn) DLLName() string { - if f.dllname == "" { - return "kernel32" - } - return f.dllname -} - -// DLLName returns DLL function name for function f. -func (f *Fn) DLLFuncName() string { - if f.dllfuncname == "" { - return f.Name - } - return f.dllfuncname -} - -// ParamList returns source code for function f parameters. -func (f *Fn) ParamList() string { - return join(f.Params, func(p *Param) string { return p.Name + " " + p.Type }, ", ") -} - -// HelperParamList returns source code for helper function f parameters. -func (f *Fn) HelperParamList() string { - return join(f.Params, func(p *Param) string { return p.Name + " " + p.HelperType() }, ", ") -} - -// ParamPrintList returns source code of trace printing part correspondent -// to syscall input parameters. -func (f *Fn) ParamPrintList() string { - return join(f.Params, func(p *Param) string { return fmt.Sprintf(`"%s=", %s, `, p.Name, p.Name) }, `", ", `) -} - -// ParamCount return number of syscall parameters for function f. -func (f *Fn) ParamCount() int { - n := 0 - for _, p := range f.Params { - n += len(p.SyscallArgList()) - } - return n -} - -// SyscallParamCount determines which version of Syscall/Syscall6/Syscall9/... -// to use. It returns parameter count for correspondent SyscallX function. -func (f *Fn) SyscallParamCount() int { - n := f.ParamCount() - switch { - case n <= 3: - return 3 - case n <= 6: - return 6 - case n <= 9: - return 9 - case n <= 12: - return 12 - case n <= 15: - return 15 - default: - panic("too many arguments to system call") - } -} - -// Syscall determines which SyscallX function to use for function f. -func (f *Fn) Syscall() string { - c := f.SyscallParamCount() - if c == 3 { - return syscalldot() + "Syscall" - } - return syscalldot() + "Syscall" + strconv.Itoa(c) -} - -// SyscallParamList returns source code for SyscallX parameters for function f. -func (f *Fn) SyscallParamList() string { - a := make([]string, 0) - for _, p := range f.Params { - a = append(a, p.SyscallArgList()...) - } - for len(a) < f.SyscallParamCount() { - a = append(a, "0") - } - return strings.Join(a, ", ") -} - -// HelperCallParamList returns source code of call into function f helper. -func (f *Fn) HelperCallParamList() string { - a := make([]string, 0, len(f.Params)) - for _, p := range f.Params { - s := p.Name - if p.Type == "string" { - s = p.tmpVar() - } - a = append(a, s) - } - return strings.Join(a, ", ") -} - -// IsUTF16 is true, if f is W (utf16) function. It is false -// for all A (ascii) functions. -func (f *Fn) IsUTF16() bool { - s := f.DLLFuncName() - return s[len(s)-1] == 'W' -} - -// StrconvFunc returns name of Go string to OS string function for f. -func (f *Fn) StrconvFunc() string { - if f.IsUTF16() { - return syscalldot() + "UTF16PtrFromString" - } - return syscalldot() + "BytePtrFromString" -} - -// StrconvType returns Go type name used for OS string for f. -func (f *Fn) StrconvType() string { - if f.IsUTF16() { - return "*uint16" - } - return "*byte" -} - -// HasStringParam is true, if f has at least one string parameter. -// Otherwise it is false. -func (f *Fn) HasStringParam() bool { - for _, p := range f.Params { - if p.Type == "string" { - return true - } - } - return false -} - -// HelperName returns name of function f helper. -func (f *Fn) HelperName() string { - if !f.HasStringParam() { - return f.Name - } - return "_" + f.Name -} - -// Source files and functions. -type Source struct { - Funcs []*Fn - Files []string - StdLibImports []string - ExternalImports []string -} - -func (src *Source) Import(pkg string) { - src.StdLibImports = append(src.StdLibImports, pkg) - sort.Strings(src.StdLibImports) -} - -func (src *Source) ExternalImport(pkg string) { - src.ExternalImports = append(src.ExternalImports, pkg) - sort.Strings(src.ExternalImports) -} - -// ParseFiles parses files listed in fs and extracts all syscall -// functions listed in sys comments. It returns source files -// and functions collection *Source if successful. -func ParseFiles(fs []string) (*Source, error) { - src := &Source{ - Funcs: make([]*Fn, 0), - Files: make([]string, 0), - StdLibImports: []string{ - "unsafe", - }, - ExternalImports: make([]string, 0), - } - for _, file := range fs { - if err := src.ParseFile(file); err != nil { - return nil, err - } - } - return src, nil -} - -// DLLs return dll names for a source set src. -func (src *Source) DLLs() []string { - uniq := make(map[string]bool) - r := make([]string, 0) - for _, f := range src.Funcs { - name := f.DLLName() - if _, found := uniq[name]; !found { - uniq[name] = true - r = append(r, name) - } - } - return r -} - -// ParseFile adds additional file path to a source set src. -func (src *Source) ParseFile(path string) error { - file, err := os.Open(path) - if err != nil { - return err - } - defer file.Close() - - s := bufio.NewScanner(file) - for s.Scan() { - t := trim(s.Text()) - if len(t) < 7 { - continue - } - if !strings.HasPrefix(t, "//sys") { - continue - } - t = t[5:] - if !(t[0] == ' ' || t[0] == '\t') { - continue - } - f, err := newFn(t[1:]) - if err != nil { - return err - } - src.Funcs = append(src.Funcs, f) - } - if err := s.Err(); err != nil { - return err - } - src.Files = append(src.Files, path) - - // get package name - fset := token.NewFileSet() - _, err = file.Seek(0, 0) - if err != nil { - return err - } - pkg, err := parser.ParseFile(fset, "", file, parser.PackageClauseOnly) - if err != nil { - return err - } - packageName = pkg.Name.Name - - return nil -} - -// IsStdRepo reports whether src is part of standard library. -func (src *Source) IsStdRepo() (bool, error) { - if len(src.Files) == 0 { - return false, errors.New("no input files provided") - } - abspath, err := filepath.Abs(src.Files[0]) - if err != nil { - return false, err - } - goroot := runtime.GOROOT() - if runtime.GOOS == "windows" { - abspath = strings.ToLower(abspath) - goroot = strings.ToLower(goroot) - } - sep := string(os.PathSeparator) - if !strings.HasSuffix(goroot, sep) { - goroot += sep - } - return strings.HasPrefix(abspath, goroot), nil -} - -// Generate output source file from a source set src. -func (src *Source) Generate(w io.Writer) error { - const ( - pkgStd = iota // any package in std library - pkgXSysWindows // x/sys/windows package - pkgOther - ) - isStdRepo, err := src.IsStdRepo() - if err != nil { - return err - } - var pkgtype int - switch { - case isStdRepo: - pkgtype = pkgStd - case packageName == "windows": - // TODO: this needs better logic than just using package name - pkgtype = pkgXSysWindows - default: - pkgtype = pkgOther - } - if *systemDLL { - switch pkgtype { - case pkgStd: - src.Import("internal/syscall/windows/sysdll") - case pkgXSysWindows: - default: - src.ExternalImport("golang.org/x/sys/windows") - } - } - if packageName != "syscall" { - src.Import("syscall") - } - funcMap := template.FuncMap{ - "packagename": packagename, - "syscalldot": syscalldot, - "newlazydll": func(dll string) string { - arg := "\"" + dll + ".dll\"" - if !*systemDLL { - return syscalldot() + "NewLazyDLL(" + arg + ")" - } - switch pkgtype { - case pkgStd: - return syscalldot() + "NewLazyDLL(sysdll.Add(" + arg + "))" - case pkgXSysWindows: - return "NewLazySystemDLL(" + arg + ")" - default: - return "windows.NewLazySystemDLL(" + arg + ")" - } - }, - } - t := template.Must(template.New("main").Funcs(funcMap).Parse(srcTemplate)) - err = t.Execute(w, src) - if err != nil { - return errors.New("Failed to execute template: " + err.Error()) - } - return nil -} - -func usage() { - fmt.Fprintf(os.Stderr, "usage: mksyscall_windows [flags] [path ...]\n") - flag.PrintDefaults() - os.Exit(1) -} - func main() { - flag.Usage = usage - flag.Parse() - if len(flag.Args()) <= 0 { - fmt.Fprintf(os.Stderr, "no files to parse provided\n") - usage() - } - - src, err := ParseFiles(flag.Args()) - if err != nil { - log.Fatal(err) - } - - var buf bytes.Buffer - if err := src.Generate(&buf); err != nil { - log.Fatal(err) - } - - data, err := format.Source(buf.Bytes()) + os.Stderr.WriteString("WARNING: Please switch from using:\n go run $GOROOT/src/syscall/mksyscall_windows.go\nto using:\n go run golang.org/x/sys/windows/mkwinsyscall\n") + args := append([]string{"run", "golang.org/x/sys/windows/mkwinsyscall"}, os.Args[1:]...) + cmd := exec.Command(filepath.Join(runtime.GOROOT(), "bin", "go"), args...) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + err := cmd.Run() if err != nil { - log.Fatal(err) - } - if *filename == "" { - _, err = os.Stdout.Write(data) - } else { - err = ioutil.WriteFile(*filename, data, 0644) - } - if err != nil { - log.Fatal(err) + os.Exit(1) } } - -// TODO: use println instead to print in the following template -const srcTemplate = ` - -{{define "main"}}// Code generated by 'go generate'; DO NOT EDIT. - -package {{packagename}} - -import ( -{{range .StdLibImports}}"{{.}}" -{{end}} - -{{range .ExternalImports}}"{{.}}" -{{end}} -) - -var _ unsafe.Pointer - -// Do the interface allocations only once for common -// Errno values. -const ( - errnoERROR_IO_PENDING = 997 -) - -var ( - errERROR_IO_PENDING error = {{syscalldot}}Errno(errnoERROR_IO_PENDING) -) - -// errnoErr returns common boxed Errno values, to prevent -// allocations at runtime. -func errnoErr(e {{syscalldot}}Errno) error { - switch e { - case 0: - return nil - case errnoERROR_IO_PENDING: - return errERROR_IO_PENDING - } - // TODO: add more here, after collecting data on the common - // error values see on Windows. (perhaps when running - // all.bat?) - return e -} - -var ( -{{template "dlls" .}} -{{template "funcnames" .}}) -{{range .Funcs}}{{if .HasStringParam}}{{template "helperbody" .}}{{end}}{{template "funcbody" .}}{{end}} -{{end}} - -{{/* help functions */}} - -{{define "dlls"}}{{range .DLLs}} mod{{.}} = {{newlazydll .}} -{{end}}{{end}} - -{{define "funcnames"}}{{range .Funcs}} proc{{.DLLFuncName}} = mod{{.DLLName}}.NewProc("{{.DLLFuncName}}") -{{end}}{{end}} - -{{define "helperbody"}} -func {{.Name}}({{.ParamList}}) {{template "results" .}}{ -{{template "helpertmpvars" .}} return {{.HelperName}}({{.HelperCallParamList}}) -} -{{end}} - -{{define "funcbody"}} -func {{.HelperName}}({{.HelperParamList}}) {{template "results" .}}{ -{{template "tmpvars" .}} {{template "syscall" .}} -{{template "seterror" .}}{{template "printtrace" .}} return -} -{{end}} - -{{define "helpertmpvars"}}{{range .Params}}{{if .TmpVarHelperCode}} {{.TmpVarHelperCode}} -{{end}}{{end}}{{end}} - -{{define "tmpvars"}}{{range .Params}}{{if .TmpVarCode}} {{.TmpVarCode}} -{{end}}{{end}}{{end}} - -{{define "results"}}{{if .Rets.List}}{{.Rets.List}} {{end}}{{end}} - -{{define "syscall"}}{{.Rets.SetReturnValuesCode}}{{.Syscall}}(proc{{.DLLFuncName}}.Addr(), {{.ParamCount}}, {{.SyscallParamList}}){{end}} - -{{define "seterror"}}{{if .Rets.SetErrorCode}} {{.Rets.SetErrorCode}} -{{end}}{{end}} - -{{define "printtrace"}}{{if .PrintTrace}} print("SYSCALL: {{.Name}}(", {{.ParamPrintList}}") (", {{.Rets.PrintList}}")\n") -{{end}}{{end}} - -` diff --git a/src/syscall/syscall.go b/src/syscall/syscall.go index e02fc502c7..980ef9d27f 100644 --- a/src/syscall/syscall.go +++ b/src/syscall/syscall.go @@ -26,7 +26,7 @@ // package syscall -//go:generate go run mksyscall_windows.go -systemdll -output zsyscall_windows.go syscall_windows.go security_windows.go +//go:generate go run golang.org/x/sys/windows/mkwinsyscall -systemdll -output zsyscall_windows.go syscall_windows.go security_windows.go // StringByteSlice converts a string to a NUL-terminated []byte, // If s contains a NUL byte this function panics instead of diff --git a/src/syscall/syscall_darwin.go b/src/syscall/syscall_darwin.go index 7d795ee4d3..2efcf3bea9 100644 --- a/src/syscall/syscall_darwin.go +++ b/src/syscall/syscall_darwin.go @@ -337,7 +337,6 @@ func Kill(pid int, signum Signal) (err error) { return kill(pid, int(signum), 1) //sysnb ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) = SYS_ioctl //sysnb execve(path *byte, argv **byte, envp **byte) (err error) //sysnb exit(res int) (err error) -//sys sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) //sys fcntlPtr(fd int, cmd int, arg unsafe.Pointer) (val int, err error) = SYS_fcntl //sys unlinkat(fd int, path string, flags int) (err error) //sys openat(fd int, path string, flags int, perm uint32) (fdret int, err error) diff --git a/src/syscall/syscall_darwin_386.go b/src/syscall/syscall_darwin_386.go index 8c5b82da55..46714bab57 100644 --- a/src/syscall/syscall_darwin_386.go +++ b/src/syscall/syscall_darwin_386.go @@ -22,6 +22,7 @@ func setTimeval(sec, usec int64) Timeval { //sys Statfs(path string, stat *Statfs_t) (err error) = SYS_statfs64 //sys fstatat(fd int, path string, stat *Stat_t, flags int) (err error) = SYS_fstatat64 //sys ptrace(request int, pid int, addr uintptr, data uintptr) (err error) +//sys sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) func SetKevent(k *Kevent_t, fd, mode, flags int) { k.Ident = uint32(fd) diff --git a/src/syscall/syscall_darwin_amd64.go b/src/syscall/syscall_darwin_amd64.go index 23a4e5f996..43506e4531 100644 --- a/src/syscall/syscall_darwin_amd64.go +++ b/src/syscall/syscall_darwin_amd64.go @@ -22,6 +22,7 @@ func setTimeval(sec, usec int64) Timeval { //sys Statfs(path string, stat *Statfs_t) (err error) = SYS_statfs64 //sys fstatat(fd int, path string, stat *Stat_t, flags int) (err error) = SYS_fstatat64 //sys ptrace(request int, pid int, addr uintptr, data uintptr) (err error) +//sys sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) func SetKevent(k *Kevent_t, fd, mode, flags int) { k.Ident = uint64(fd) diff --git a/src/syscall/syscall_darwin_arm.go b/src/syscall/syscall_darwin_arm.go index 7f39cf4003..4ca2e300e4 100644 --- a/src/syscall/syscall_darwin_arm.go +++ b/src/syscall/syscall_darwin_arm.go @@ -29,6 +29,10 @@ func ptrace(request int, pid int, addr uintptr, data uintptr) error { return ENOTSUP } +func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) error { + return ENOTSUP +} + func SetKevent(k *Kevent_t, fd, mode, flags int) { k.Ident = uint32(fd) k.Filter = int16(mode) diff --git a/src/syscall/syscall_darwin_arm64.go b/src/syscall/syscall_darwin_arm64.go index bd110f2e7f..fde48f3596 100644 --- a/src/syscall/syscall_darwin_arm64.go +++ b/src/syscall/syscall_darwin_arm64.go @@ -29,6 +29,10 @@ func ptrace(request int, pid int, addr uintptr, data uintptr) error { return ENOTSUP } +func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) error { + return ENOTSUP +} + func SetKevent(k *Kevent_t, fd, mode, flags int) { k.Ident = uint64(fd) k.Filter = int16(mode) diff --git a/src/syscall/zsyscall_darwin_386.go b/src/syscall/zsyscall_darwin_386.go index 2c3b15f5f9..0ffc692116 100644 --- a/src/syscall/zsyscall_darwin_386.go +++ b/src/syscall/zsyscall_darwin_386.go @@ -1870,27 +1870,6 @@ func libc_exit_trampoline() // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) { - var _p0 unsafe.Pointer - if len(mib) > 0 { - _p0 = unsafe.Pointer(&mib[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - _, _, e1 := syscall6(funcPC(libc_sysctl_trampoline), uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_sysctl_trampoline() - -//go:linkname libc_sysctl libc_sysctl -//go:cgo_import_dynamic libc_sysctl sysctl "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func fcntlPtr(fd int, cmd int, arg unsafe.Pointer) (val int, err error) { r0, _, e1 := syscall(funcPC(libc_fcntl_trampoline), uintptr(fd), uintptr(cmd), uintptr(arg)) val = int(r0) @@ -2081,3 +2060,24 @@ func libc_ptrace_trampoline() //go:linkname libc_ptrace libc_ptrace //go:cgo_import_dynamic libc_ptrace ptrace "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) { + var _p0 unsafe.Pointer + if len(mib) > 0 { + _p0 = unsafe.Pointer(&mib[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := syscall6(funcPC(libc_sysctl_trampoline), uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_sysctl_trampoline() + +//go:linkname libc_sysctl libc_sysctl +//go:cgo_import_dynamic libc_sysctl sysctl "/usr/lib/libSystem.B.dylib" diff --git a/src/syscall/zsyscall_darwin_386.s b/src/syscall/zsyscall_darwin_386.s index d84b46229e..0dec5baa22 100644 --- a/src/syscall/zsyscall_darwin_386.s +++ b/src/syscall/zsyscall_darwin_386.s @@ -229,8 +229,6 @@ TEXT ·libc_execve_trampoline(SB),NOSPLIT,$0-0 JMP libc_execve(SB) TEXT ·libc_exit_trampoline(SB),NOSPLIT,$0-0 JMP libc_exit(SB) -TEXT ·libc_sysctl_trampoline(SB),NOSPLIT,$0-0 - JMP libc_sysctl(SB) TEXT ·libc_unlinkat_trampoline(SB),NOSPLIT,$0-0 JMP libc_unlinkat(SB) TEXT ·libc_openat_trampoline(SB),NOSPLIT,$0-0 @@ -251,3 +249,5 @@ TEXT ·libc_fstatat64_trampoline(SB),NOSPLIT,$0-0 JMP libc_fstatat64(SB) TEXT ·libc_ptrace_trampoline(SB),NOSPLIT,$0-0 JMP libc_ptrace(SB) +TEXT ·libc_sysctl_trampoline(SB),NOSPLIT,$0-0 + JMP libc_sysctl(SB) diff --git a/src/syscall/zsyscall_darwin_amd64.go b/src/syscall/zsyscall_darwin_amd64.go index 83214de2fb..942152ae39 100644 --- a/src/syscall/zsyscall_darwin_amd64.go +++ b/src/syscall/zsyscall_darwin_amd64.go @@ -1870,27 +1870,6 @@ func libc_exit_trampoline() // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) { - var _p0 unsafe.Pointer - if len(mib) > 0 { - _p0 = unsafe.Pointer(&mib[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - _, _, e1 := syscall6(funcPC(libc_sysctl_trampoline), uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_sysctl_trampoline() - -//go:linkname libc_sysctl libc_sysctl -//go:cgo_import_dynamic libc_sysctl sysctl "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func fcntlPtr(fd int, cmd int, arg unsafe.Pointer) (val int, err error) { r0, _, e1 := syscall(funcPC(libc_fcntl_trampoline), uintptr(fd), uintptr(cmd), uintptr(arg)) val = int(r0) @@ -2081,3 +2060,24 @@ func libc_ptrace_trampoline() //go:linkname libc_ptrace libc_ptrace //go:cgo_import_dynamic libc_ptrace ptrace "/usr/lib/libSystem.B.dylib" + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) { + var _p0 unsafe.Pointer + if len(mib) > 0 { + _p0 = unsafe.Pointer(&mib[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := syscall6(funcPC(libc_sysctl_trampoline), uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +func libc_sysctl_trampoline() + +//go:linkname libc_sysctl libc_sysctl +//go:cgo_import_dynamic libc_sysctl sysctl "/usr/lib/libSystem.B.dylib" diff --git a/src/syscall/zsyscall_darwin_amd64.s b/src/syscall/zsyscall_darwin_amd64.s index 23ddbe06c0..fcb7f9c291 100644 --- a/src/syscall/zsyscall_darwin_amd64.s +++ b/src/syscall/zsyscall_darwin_amd64.s @@ -229,8 +229,6 @@ TEXT ·libc_execve_trampoline(SB),NOSPLIT,$0-0 JMP libc_execve(SB) TEXT ·libc_exit_trampoline(SB),NOSPLIT,$0-0 JMP libc_exit(SB) -TEXT ·libc_sysctl_trampoline(SB),NOSPLIT,$0-0 - JMP libc_sysctl(SB) TEXT ·libc_unlinkat_trampoline(SB),NOSPLIT,$0-0 JMP libc_unlinkat(SB) TEXT ·libc_openat_trampoline(SB),NOSPLIT,$0-0 @@ -251,3 +249,5 @@ TEXT ·libc_fstatat64_trampoline(SB),NOSPLIT,$0-0 JMP libc_fstatat64(SB) TEXT ·libc_ptrace_trampoline(SB),NOSPLIT,$0-0 JMP libc_ptrace(SB) +TEXT ·libc_sysctl_trampoline(SB),NOSPLIT,$0-0 + JMP libc_sysctl(SB) diff --git a/src/syscall/zsyscall_darwin_arm.go b/src/syscall/zsyscall_darwin_arm.go index 2a643f209f..73ee205d33 100644 --- a/src/syscall/zsyscall_darwin_arm.go +++ b/src/syscall/zsyscall_darwin_arm.go @@ -1870,27 +1870,6 @@ func libc_exit_trampoline() // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) { - var _p0 unsafe.Pointer - if len(mib) > 0 { - _p0 = unsafe.Pointer(&mib[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - _, _, e1 := syscall6(funcPC(libc_sysctl_trampoline), uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_sysctl_trampoline() - -//go:linkname libc_sysctl libc_sysctl -//go:cgo_import_dynamic libc_sysctl sysctl "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func fcntlPtr(fd int, cmd int, arg unsafe.Pointer) (val int, err error) { r0, _, e1 := syscall(funcPC(libc_fcntl_trampoline), uintptr(fd), uintptr(cmd), uintptr(arg)) val = int(r0) diff --git a/src/syscall/zsyscall_darwin_arm.s b/src/syscall/zsyscall_darwin_arm.s index c7cd83d83e..6462a198b0 100644 --- a/src/syscall/zsyscall_darwin_arm.s +++ b/src/syscall/zsyscall_darwin_arm.s @@ -229,8 +229,6 @@ TEXT ·libc_execve_trampoline(SB),NOSPLIT,$0-0 JMP libc_execve(SB) TEXT ·libc_exit_trampoline(SB),NOSPLIT,$0-0 JMP libc_exit(SB) -TEXT ·libc_sysctl_trampoline(SB),NOSPLIT,$0-0 - JMP libc_sysctl(SB) TEXT ·libc_unlinkat_trampoline(SB),NOSPLIT,$0-0 JMP libc_unlinkat(SB) TEXT ·libc_openat_trampoline(SB),NOSPLIT,$0-0 diff --git a/src/syscall/zsyscall_darwin_arm64.go b/src/syscall/zsyscall_darwin_arm64.go index 0b77839869..bbe092cd07 100644 --- a/src/syscall/zsyscall_darwin_arm64.go +++ b/src/syscall/zsyscall_darwin_arm64.go @@ -1870,27 +1870,6 @@ func libc_exit_trampoline() // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) { - var _p0 unsafe.Pointer - if len(mib) > 0 { - _p0 = unsafe.Pointer(&mib[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - _, _, e1 := syscall6(funcPC(libc_sysctl_trampoline), uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen)) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_sysctl_trampoline() - -//go:linkname libc_sysctl libc_sysctl -//go:cgo_import_dynamic libc_sysctl sysctl "/usr/lib/libSystem.B.dylib" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func fcntlPtr(fd int, cmd int, arg unsafe.Pointer) (val int, err error) { r0, _, e1 := syscall(funcPC(libc_fcntl_trampoline), uintptr(fd), uintptr(cmd), uintptr(arg)) val = int(r0) diff --git a/src/syscall/zsyscall_darwin_arm64.s b/src/syscall/zsyscall_darwin_arm64.s index 7b8b3764a8..ec2210f1df 100644 --- a/src/syscall/zsyscall_darwin_arm64.s +++ b/src/syscall/zsyscall_darwin_arm64.s @@ -229,8 +229,6 @@ TEXT ·libc_execve_trampoline(SB),NOSPLIT,$0-0 JMP libc_execve(SB) TEXT ·libc_exit_trampoline(SB),NOSPLIT,$0-0 JMP libc_exit(SB) -TEXT ·libc_sysctl_trampoline(SB),NOSPLIT,$0-0 - JMP libc_sysctl(SB) TEXT ·libc_unlinkat_trampoline(SB),NOSPLIT,$0-0 JMP libc_unlinkat(SB) TEXT ·libc_openat_trampoline(SB),NOSPLIT,$0-0 diff --git a/test/fixedbugs/issue31747.go b/test/fixedbugs/issue31747.go index dfb585c613..420fe30735 100644 --- a/test/fixedbugs/issue31747.go +++ b/test/fixedbugs/issue31747.go @@ -8,11 +8,11 @@ package p // numeric literals const ( - _ = 1_000 // ERROR "underscores in numeric literals only supported as of -lang=go1.13" - _ = 0b111 // ERROR "binary literals only supported as of -lang=go1.13" - _ = 0o567 // ERROR "0o/0O-style octal literals only supported as of -lang=go1.13" + _ = 1_000 // ERROR "underscores in numeric literals requires go1.13 or later \(-lang was set to go1.12; check go.mod\)" + _ = 0b111 // ERROR "binary literals requires go1.13 or later" + _ = 0o567 // ERROR "0o/0O-style octal literals requires go1.13 or later" _ = 0xabc // ok - _ = 0x0p1 // ERROR "hexadecimal floating-point literals only supported as of -lang=go1.13" + _ = 0x0p1 // ERROR "hexadecimal floating-point literals requires go1.13 or later" _ = 0B111 // ERROR "binary" _ = 0O567 // ERROR "octal" @@ -29,6 +29,6 @@ const ( // signed shift counts var ( s int - _ = 1 << s // ERROR "signed shift count type int, only supported as of -lang=go1.13" + _ = 1 << s // ERROR "invalid operation: 1 << s \(signed shift count type int\) requires go1.13 or later" _ = 1 >> s // ERROR "signed shift count" ) |