diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2018-06-07 18:05:45 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2018-06-07 18:05:45 +0000 |
commit | ce311a8cae4489058f8601bebdf511b7fb5fce26 (patch) | |
tree | 81494302b4f5708ad6c96bad6ecfd9c109574c38 /libgo/go | |
parent | 48ec607c1f8d1f1783850f1d2729fd23716b1b1b (diff) | |
parent | dc23fb4d72eed9ea09fbf4704b26e0e36414a57a (diff) | |
download | gcc-ce311a8cae4489058f8601bebdf511b7fb5fce26.zip gcc-ce311a8cae4489058f8601bebdf511b7fb5fce26.tar.gz gcc-ce311a8cae4489058f8601bebdf511b7fb5fce26.tar.bz2 |
Merge from trunk revision 261284.
From-SVN: r261288
Diffstat (limited to 'libgo/go')
59 files changed, 1228 insertions, 1512 deletions
diff --git a/libgo/go/archive/zip/reader.go b/libgo/go/archive/zip/reader.go index 1563e74..2444106 100644 --- a/libgo/go/archive/zip/reader.go +++ b/libgo/go/archive/zip/reader.go @@ -366,7 +366,7 @@ parseExtras: epoch := time.Date(1601, time.January, 1, 0, 0, 0, 0, time.UTC) modified = time.Unix(epoch.Unix()+secs, nsecs) } - case unixExtraID: + case unixExtraID, infoZipUnixExtraID: if len(fieldBuf) < 8 { continue parseExtras } @@ -379,12 +379,6 @@ parseExtras: } ts := int64(fieldBuf.uint32()) // ModTime since Unix epoch modified = time.Unix(ts, 0) - case infoZipUnixExtraID: - if len(fieldBuf) < 4 { - continue parseExtras - } - ts := int64(fieldBuf.uint32()) // ModTime since Unix epoch - modified = time.Unix(ts, 0) } } diff --git a/libgo/go/archive/zip/reader_test.go b/libgo/go/archive/zip/reader_test.go index 0d9040f..1e58b26 100644 --- a/libgo/go/archive/zip/reader_test.go +++ b/libgo/go/archive/zip/reader_test.go @@ -414,7 +414,7 @@ var tests = []ZipTest{ Name: "test.txt", Content: []byte{}, Size: 1<<32 - 1, - Modified: time.Date(2017, 10, 31, 21, 17, 27, 0, timeZone(-7*time.Hour)), + Modified: time.Date(2017, 10, 31, 21, 11, 57, 0, timeZone(-7*time.Hour)), Mode: 0644, }, }, diff --git a/libgo/go/cmd/cgo/main.go b/libgo/go/cmd/cgo/main.go index 6baabfd..890a365 100644 --- a/libgo/go/cmd/cgo/main.go +++ b/libgo/go/cmd/cgo/main.go @@ -165,6 +165,7 @@ var ptrSizeMap = map[string]int64{ "mips64le": 8, "mips64p32": 4, "mips64p32le": 4, + "nios2": 4, "ppc": 4, "ppc64": 8, "ppc64le": 8, @@ -190,6 +191,7 @@ var intSizeMap = map[string]int64{ "mips64le": 8, "mips64p32": 8, "mips64p32le": 8, + "nios2": 4, "ppc": 4, "ppc64": 8, "ppc64le": 8, diff --git a/libgo/go/cmd/go/alldocs.go b/libgo/go/cmd/go/alldocs.go index 5e1ac5a..aadf97c 100644 --- a/libgo/go/cmd/go/alldocs.go +++ b/libgo/go/cmd/go/alldocs.go @@ -1266,6 +1266,9 @@ // // Special-purpose environment variables: // +// GCCGOTOOLDIR +// If set, where to find gccgo tools, such as cgo. +// The default is based on how gccgo was configured. // GOROOT_FINAL // The root of the installed Go tree, when it is // installed in a location other than where it is built. @@ -1279,9 +1282,6 @@ // Defined by Git. A colon-separated list of schemes that are allowed to be used // with git fetch/clone. If set, any scheme not explicitly mentioned will be // considered insecure by 'go get'. -// GCCGOTOOLDIR -// If set, where to find gccgo tools, such as cgo. -// The default is based on how gccgo was configured. // // // Import path syntax diff --git a/libgo/go/cmd/go/go_test.go b/libgo/go/cmd/go/go_test.go index c5a3d7b..f6d6f42 100644 --- a/libgo/go/cmd/go/go_test.go +++ b/libgo/go/cmd/go/go_test.go @@ -1034,7 +1034,6 @@ func TestGoInstallRebuildsStalePackagesInOtherGOPATH(t *testing.T) { } func TestGoInstallDetectsRemovedFiles(t *testing.T) { - skipIfGccgo(t, "gccgo does not yet support package build IDs") tg := testgo(t) defer tg.cleanup() tg.parallel() @@ -1104,7 +1103,6 @@ func TestGoInstallErrorOnCrossCompileToBin(t *testing.T) { } func TestGoInstallDetectsRemovedFilesInPackageMain(t *testing.T) { - skipIfGccgo(t, "gccgo does not yet support package build IDs") tooSlow(t) tg := testgo(t) defer tg.cleanup() @@ -3223,7 +3221,6 @@ func TestGoGetInternalWildcard(t *testing.T) { } func TestGoVetWithExternalTests(t *testing.T) { - skipIfGccgo(t, "gccgo does not have vet") tg := testgo(t) defer tg.cleanup() tg.makeTempdir() @@ -3233,7 +3230,6 @@ func TestGoVetWithExternalTests(t *testing.T) { } func TestGoVetWithTags(t *testing.T) { - skipIfGccgo(t, "gccgo does not have vet") tg := testgo(t) defer tg.cleanup() tg.makeTempdir() @@ -3243,7 +3239,6 @@ func TestGoVetWithTags(t *testing.T) { } func TestGoVetWithFlagsOn(t *testing.T) { - skipIfGccgo(t, "gccgo does not have vet") tg := testgo(t) defer tg.cleanup() tg.makeTempdir() @@ -3253,7 +3248,6 @@ func TestGoVetWithFlagsOn(t *testing.T) { } func TestGoVetWithFlagsOff(t *testing.T) { - skipIfGccgo(t, "gccgo does not have vet") tg := testgo(t) defer tg.cleanup() tg.makeTempdir() @@ -3271,6 +3265,20 @@ func TestGoVetWithOnlyTestFiles(t *testing.T) { tg.run("vet", "p") } +// Issue 24193. +func TestVetWithOnlyCgoFiles(t *testing.T) { + if !canCgo { + t.Skip("skipping because cgo not enabled") + } + + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempFile("src/p/p.go", "package p; import \"C\"; func F() {}") + tg.setenv("GOPATH", tg.path(".")) + tg.run("vet", "p") +} + // Issue 9767, 19769. func TestGoGetDotSlashDownload(t *testing.T) { testenv.MustHaveExternalNetwork(t) @@ -5105,6 +5113,28 @@ func TestCacheOutput(t *testing.T) { } } +func TestCacheListStale(t *testing.T) { + tooSlow(t) + if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") { + t.Skip("GODEBUG gocacheverify") + } + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.makeTempdir() + tg.setenv("GOCACHE", tg.path("cache")) + tg.tempFile("gopath/src/p/p.go", "package p; import _ \"q\"; func F(){}\n") + tg.tempFile("gopath/src/q/q.go", "package q; func F(){}\n") + tg.tempFile("gopath/src/m/m.go", "package main; import _ \"q\"; func main(){}\n") + + tg.setenv("GOPATH", tg.path("gopath")) + tg.run("install", "p", "m") + tg.run("list", "-f={{.ImportPath}} {{.Stale}}", "m", "q", "p") + tg.grepStdout("^m false", "m should not be stale") + tg.grepStdout("^q true", "q should be stale") + tg.grepStdout("^p false", "p should not be stale") +} + func TestCacheCoverage(t *testing.T) { tooSlow(t) @@ -5798,6 +5828,22 @@ func TestAtomicCoverpkgAll(t *testing.T) { } } +// Issue 23882. +func TestCoverpkgAllRuntime(t *testing.T) { + skipIfGccgo(t, "gccgo has no cover tool") + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + + tg.tempFile("src/x/x.go", `package x; import _ "runtime"; func F() {}`) + tg.tempFile("src/x/x_test.go", `package x; import "testing"; func TestF(t *testing.T) { F() }`) + tg.setenv("GOPATH", tg.path(".")) + tg.run("test", "-coverpkg=all", "x") + if canRace { + tg.run("test", "-coverpkg=all", "-race", "x") + } +} + func TestBadCommandLines(t *testing.T) { tg := testgo(t) defer tg.cleanup() @@ -5955,3 +6001,36 @@ func TestBadCgoDirectives(t *testing.T) { tg.run("build", "-n", "x") tg.grepStderr("-D@foo", "did not find -D@foo in commands") } + +func TestTwoPkgConfigs(t *testing.T) { + if !canCgo { + t.Skip("no cgo") + } + if runtime.GOOS == "windows" || runtime.GOOS == "plan9" { + t.Skipf("no shell scripts on %s", runtime.GOOS) + } + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempFile("src/x/a.go", `package x + // #cgo pkg-config: --static a + import "C" + `) + tg.tempFile("src/x/b.go", `package x + // #cgo pkg-config: --static a + import "C" + `) + tg.tempFile("pkg-config.sh", `#!/bin/sh +echo $* >>`+tg.path("pkg-config.out")) + tg.must(os.Chmod(tg.path("pkg-config.sh"), 0755)) + tg.setenv("GOPATH", tg.path(".")) + tg.setenv("PKG_CONFIG", tg.path("pkg-config.sh")) + tg.run("build", "x") + out, err := ioutil.ReadFile(tg.path("pkg-config.out")) + tg.must(err) + out = bytes.TrimSpace(out) + want := "--cflags --static --static -- a a\n--libs --static --static -- a a" + if !bytes.Equal(out, []byte(want)) { + t.Errorf("got %q want %q", out, want) + } +} diff --git a/libgo/go/cmd/go/internal/cfg/cfg.go b/libgo/go/cmd/go/internal/cfg/cfg.go index bfdd67e..f0a2277 100644 --- a/libgo/go/cmd/go/internal/cfg/cfg.go +++ b/libgo/go/cmd/go/internal/cfg/cfg.go @@ -92,11 +92,12 @@ var ( // Update build context to use our computed GOROOT. func init() { BuildContext.GOROOT = GOROOT - // Note that we must use runtime.GOOS and runtime.GOARCH here, - // as the tool directory does not move based on environment variables. - // This matches the initialization of ToolDir in go/build, - // except for using GOROOT rather than runtime.GOROOT(). if runtime.Compiler != "gccgo" { + // Note that we must use runtime.GOOS and runtime.GOARCH here, + // as the tool directory does not move based on environment + // variables. This matches the initialization of ToolDir in + // go/build, except for using GOROOT rather than + // runtime.GOROOT. build.ToolDir = filepath.Join(GOROOT, "pkg/tool/"+runtime.GOOS+"_"+runtime.GOARCH) } } @@ -107,6 +108,8 @@ func findGOROOT() string { } def := filepath.Clean(runtime.GOROOT()) if runtime.Compiler == "gccgo" { + // gccgo has no real GOROOT, and it certainly doesn't + // depend on the executable's location. return def } exe, err := os.Executable() diff --git a/libgo/go/cmd/go/internal/get/vcs.go b/libgo/go/cmd/go/internal/get/vcs.go index 26693b1..0b2a04e 100644 --- a/libgo/go/cmd/go/internal/get/vcs.go +++ b/libgo/go/cmd/go/internal/get/vcs.go @@ -809,8 +809,8 @@ func repoRootForImportDynamic(importPath string, security web.SecurityMode) (*re } } - if !strings.Contains(mmi.RepoRoot, "://") { - return nil, fmt.Errorf("%s: invalid repo root %q; no scheme", urlStr, mmi.RepoRoot) + if err := validateRepoRootScheme(mmi.RepoRoot); err != nil { + return nil, fmt.Errorf("%s: invalid repo root %q: %v", urlStr, mmi.RepoRoot, err) } rr := &repoRoot{ vcs: vcsByCmd(mmi.VCS), @@ -824,6 +824,36 @@ func repoRootForImportDynamic(importPath string, security web.SecurityMode) (*re return rr, nil } +// validateRepoRootScheme returns an error if repoRoot does not seem +// to have a valid URL scheme. At this point we permit things that +// aren't valid URLs, although later, if not using -insecure, we will +// restrict repoRoots to be valid URLs. This is only because we've +// historically permitted them, and people may depend on that. +func validateRepoRootScheme(repoRoot string) error { + end := strings.Index(repoRoot, "://") + if end <= 0 { + return errors.New("no scheme") + } + + // RFC 3986 section 3.1. + for i := 0; i < end; i++ { + c := repoRoot[i] + switch { + case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z': + // OK. + case '0' <= c && c <= '9' || c == '+' || c == '-' || c == '.': + // OK except at start. + if i == 0 { + return errors.New("invalid scheme") + } + default: + return errors.New("invalid scheme") + } + } + + return nil +} + var fetchGroup singleflight.Group var ( fetchCacheMu sync.Mutex diff --git a/libgo/go/cmd/go/internal/get/vcs_test.go b/libgo/go/cmd/go/internal/get/vcs_test.go index e29338a..a6f8642 100644 --- a/libgo/go/cmd/go/internal/get/vcs_test.go +++ b/libgo/go/cmd/go/internal/get/vcs_test.go @@ -408,3 +408,46 @@ func TestMatchGoImport(t *testing.T) { } } } + +func TestValidateRepoRootScheme(t *testing.T) { + tests := []struct { + root string + err string + }{ + { + root: "", + err: "no scheme", + }, + { + root: "http://", + err: "", + }, + { + root: "a://", + err: "", + }, + { + root: "a#://", + err: "invalid scheme", + }, + { + root: "-config://", + err: "invalid scheme", + }, + } + + for _, test := range tests { + err := validateRepoRootScheme(test.root) + if err == nil { + if test.err != "" { + t.Errorf("validateRepoRootScheme(%q) = nil, want %q", test.root, test.err) + } + } else if test.err == "" { + if err != nil { + t.Errorf("validateRepoRootScheme(%q) = %q, want nil", test.root, test.err) + } + } else if err.Error() != test.err { + t.Errorf("validateRepoRootScheme(%q) = %q, want %q", test.root, err, test.err) + } + } +} diff --git a/libgo/go/cmd/go/internal/help/helpdoc.go b/libgo/go/cmd/go/internal/help/helpdoc.go index 9a9fc4e..6aa449a 100644 --- a/libgo/go/cmd/go/internal/help/helpdoc.go +++ b/libgo/go/cmd/go/internal/help/helpdoc.go @@ -526,6 +526,9 @@ Architecture-specific environment variables: Special-purpose environment variables: + GCCGOTOOLDIR + If set, where to find gccgo tools, such as cgo. + The default is based on how gccgo was configured. GOROOT_FINAL The root of the installed Go tree, when it is installed in a location other than where it is built. @@ -539,9 +542,6 @@ Special-purpose environment variables: Defined by Git. A colon-separated list of schemes that are allowed to be used with git fetch/clone. If set, any scheme not explicitly mentioned will be considered insecure by 'go get'. - GCCGOTOOLDIR - If set, where to find gccgo tools, such as cgo. - The default is based on how gccgo was configured. `, } diff --git a/libgo/go/cmd/go/internal/load/pkg.go b/libgo/go/cmd/go/internal/load/pkg.go index ac764b4..882b86d 100644 --- a/libgo/go/cmd/go/internal/load/pkg.go +++ b/libgo/go/cmd/go/internal/load/pkg.go @@ -13,7 +13,6 @@ import ( "os" pathpkg "path" "path/filepath" - "runtime" "sort" "strings" "unicode" @@ -224,9 +223,6 @@ func (p *Package) copyBuild(pp *build.Package) { // TODO? Target p.Goroot = pp.Goroot p.Standard = p.Goroot && p.ImportPath != "" && isStandardImportPath(p.ImportPath) - if cfg.BuildToolchainName == "gccgo" { - p.Standard = stdpkg[p.ImportPath] - } p.GoFiles = pp.GoFiles p.CgoFiles = pp.CgoFiles p.IgnoredGoFiles = pp.IgnoredGoFiles @@ -895,13 +891,6 @@ var foldPath = make(map[string]string) func (p *Package) load(stk *ImportStack, bp *build.Package, err error) { p.copyBuild(bp) - // When using gccgo the go/build package will not be able to - // find a standard package. It would be nicer to not get that - // error, but go/build doesn't know stdpkg. - if cfg.BuildToolchainName == "gccgo" && err != nil && p.Standard { - err = nil - } - // Decide whether p was listed on the command line. // Given that load is called while processing the command line, // you might think we could simply pass a flag down into load @@ -976,7 +965,7 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) { // This is for 'go tool'. // Override all the usual logic and force it into the tool directory. if cfg.BuildToolchainName == "gccgo" { - p.Target = filepath.Join(runtime.GCCGOTOOLDIR, elem) + p.Target = filepath.Join(base.ToolDir, elem) } else { p.Target = filepath.Join(cfg.GOROOTpkg, "tool", full) } @@ -1021,7 +1010,7 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) { // Cgo translation adds imports of "runtime/cgo" and "syscall", // except for certain packages, to avoid circular dependencies. - if p.UsesCgo() && (!p.Standard || !cgoExclude[p.ImportPath]) { + if p.UsesCgo() && (!p.Standard || !cgoExclude[p.ImportPath]) && cfg.BuildContext.Compiler != "gccgo" { addImport("runtime/cgo") } if p.UsesCgo() && (!p.Standard || !cgoSyscallExclude[p.ImportPath]) { @@ -1030,7 +1019,9 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) { // SWIG adds imports of some standard packages. if p.UsesSwig() { - addImport("runtime/cgo") + if cfg.BuildContext.Compiler != "gccgo" { + addImport("runtime/cgo") + } addImport("syscall") addImport("sync") @@ -1097,9 +1088,6 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) { continue } p1 := LoadImport(path, p.Dir, p, stk, p.Internal.Build.ImportPos[path], UseVendor) - if cfg.BuildToolchainName == "gccgo" && p1.Standard { - continue - } if p.Standard && p.Error == nil && !p1.Standard && p1.Error == nil { p.Error = &PackageError{ ImportStack: stk.Copy(), @@ -1224,6 +1212,7 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) { // GNU binutils flagfile specifiers, sometimes called "response files"). // To be conservative, we reject almost any arg beginning with non-alphanumeric ASCII. // We accept leading . _ and / as likely in file system paths. +// There is a copy of this function in cmd/compile/internal/gc/noder.go. func SafeArg(name string) bool { if name == "" { return false @@ -1238,7 +1227,7 @@ func LinkerDeps(p *Package) []string { deps := []string{"runtime"} // External linking mode forces an import of runtime/cgo. - if externalLinkingForced(p) { + if externalLinkingForced(p) && cfg.BuildContext.Compiler != "gccgo" { deps = append(deps, "runtime/cgo") } // On ARM with GOARM=5, it forces an import of math, for soft floating point. @@ -1610,9 +1599,6 @@ func GetTestPackagesFor(p *Package, forceTest bool) (ptest, pxtest *Package, err rawTestImports := str.StringList(p.TestImports) for i, path := range p.TestImports { p1 := LoadImport(path, p.Dir, p, &stk, p.Internal.Build.TestImportPos[path], UseVendor) - if cfg.BuildToolchainName == "gccgo" && p1.Standard { - continue - } if p1.Error != nil { return nil, nil, p1.Error } @@ -1641,9 +1627,6 @@ func GetTestPackagesFor(p *Package, forceTest bool) (ptest, pxtest *Package, err rawXTestImports := str.StringList(p.XTestImports) for i, path := range p.XTestImports { p1 := LoadImport(path, p.Dir, p, &stk, p.Internal.Build.XTestImportPos[path], UseVendor) - if cfg.BuildToolchainName == "gccgo" && p1.Standard { - continue - } if p1.Error != nil { return nil, nil, p1.Error } diff --git a/libgo/go/cmd/go/internal/test/test.go b/libgo/go/cmd/go/internal/test/test.go index 9785470..72415cc 100644 --- a/libgo/go/cmd/go/internal/test/test.go +++ b/libgo/go/cmd/go/internal/test/test.go @@ -633,6 +633,8 @@ func runTest(cmd *base.Command, args []string) { a := &work.Action{Mode: "go test -i"} for _, p := range load.PackagesForBuild(all) { if cfg.BuildToolchainName == "gccgo" && p.Standard { + // gccgo's standard library packages + // can not be reinstalled. continue } a.Deps = append(a.Deps, b.CompileAction(work.ModeInstall, work.ModeInstall, p)) @@ -671,6 +673,14 @@ func runTest(cmd *base.Command, args []string) { continue } + // If using the race detector, silently ignore + // attempts to run coverage on the runtime + // packages. It will cause the race detector + // to be invoked before it has been initialized. + if cfg.BuildRace && p.Standard && (p.ImportPath == "runtime" || strings.HasPrefix(p.ImportPath, "runtime/internal")) { + continue + } + if haveMatch { testCoverPkgs = append(testCoverPkgs, p) } @@ -862,9 +872,6 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin pmain.Internal.Imports = append(pmain.Internal.Imports, ptest) } else { p1 := load.LoadImport(dep, "", nil, &stk, nil, 0) - if cfg.BuildToolchainName == "gccgo" && p1.Standard { - continue - } if p1.Error != nil { return nil, nil, nil, p1.Error } diff --git a/libgo/go/cmd/go/internal/vet/vet.go b/libgo/go/cmd/go/internal/vet/vet.go index 07eed89..a737ebd 100644 --- a/libgo/go/cmd/go/internal/vet/vet.go +++ b/libgo/go/cmd/go/internal/vet/vet.go @@ -62,11 +62,11 @@ func runVet(cmd *base.Command, args []string) { base.Errorf("%v", err) continue } - if len(ptest.GoFiles) == 0 && pxtest == nil { + if len(ptest.GoFiles) == 0 && len(ptest.CgoFiles) == 0 && pxtest == nil { base.Errorf("go vet %s: no Go files in %s", p.ImportPath, p.Dir) continue } - if len(ptest.GoFiles) > 0 { + if len(ptest.GoFiles) > 0 || len(ptest.CgoFiles) > 0 { root.Deps = append(root.Deps, b.VetAction(work.ModeBuild, work.ModeBuild, ptest)) } if pxtest != nil { diff --git a/libgo/go/cmd/go/internal/vet/vetflag.go b/libgo/go/cmd/go/internal/vet/vetflag.go index d4664cc..03770ea 100644 --- a/libgo/go/cmd/go/internal/vet/vetflag.go +++ b/libgo/go/cmd/go/internal/vet/vetflag.go @@ -90,7 +90,7 @@ func vetFlags(args []string) (passToVet, packageNames []string) { } switch f.Name { // Flags known to the build but not to vet, so must be dropped. - case "x", "n", "vettool": + case "x", "n", "vettool", "compiler": if extraWord { args = append(args[:i], args[i+2:]...) extraWord = false diff --git a/libgo/go/cmd/go/internal/work/buildid.go b/libgo/go/cmd/go/internal/work/buildid.go index e2ae850..733938e 100644 --- a/libgo/go/cmd/go/internal/work/buildid.go +++ b/libgo/go/cmd/go/internal/work/buildid.go @@ -235,6 +235,8 @@ func (b *Builder) gccgoToolID(name, language string) (string, error) { cmdline := str.StringList(cfg.BuildToolexec, name, "-###", "-x", language, "-c", "-") cmd := exec.Command(cmdline[0], cmdline[1:]...) cmd.Env = base.EnvForDir(cmd.Dir, os.Environ()) + // Force untranslated output so that we see the string "version". + cmd.Env = append(cmd.Env, "LC_ALL=C") out, err := cmd.CombinedOutput() if err != nil { return "", fmt.Errorf("%s: %v; output: %q", name, err, out) @@ -292,13 +294,36 @@ func (b *Builder) gccgoToolID(name, language string) (string, error) { return id, nil } +// Check if assembler used by gccgo is GNU as. +func assemblerIsGas() bool { + cmd := exec.Command(BuildToolchain.compiler(), "-print-prog-name=as") + assembler, err := cmd.Output() + if err == nil { + cmd := exec.Command(strings.TrimSpace(string(assembler)), "--version") + out, err := cmd.Output() + if err == nil && strings.Contains(string(out), "GNU") { + return true + } else { + return false + } + } else { + return false + } +} + // gccgoBuildIDELFFile creates an assembler file that records the // action's build ID in an SHF_EXCLUDE section. func (b *Builder) gccgoBuildIDELFFile(a *Action) (string, error) { sfile := a.Objdir + "_buildid.s" var buf bytes.Buffer - fmt.Fprintf(&buf, "\t"+`.section .go.buildid,"e"`+"\n") + if cfg.Goos != "solaris" || assemblerIsGas() { + fmt.Fprintf(&buf, "\t"+`.section .go.buildid,"e"`+"\n") + } else if cfg.Goarch == "sparc" || cfg.Goarch == "sparc64" { + fmt.Fprintf(&buf, "\t"+`.section ".go.buildid",#exclude`+"\n") + } else { // cfg.Goarch == "386" || cfg.Goarch == "amd64" + fmt.Fprintf(&buf, "\t"+`.section .go.buildid,#exclude`+"\n") + } fmt.Fprintf(&buf, "\t.byte ") for i := 0; i < len(a.buildID); i++ { if i > 0 { @@ -311,8 +336,10 @@ func (b *Builder) gccgoBuildIDELFFile(a *Action) (string, error) { fmt.Fprintf(&buf, "%#02x", a.buildID[i]) } fmt.Fprintf(&buf, "\n") - fmt.Fprintf(&buf, "\t"+`.section .note.GNU-stack,"",@progbits`+"\n") - fmt.Fprintf(&buf, "\t"+`.section .note.GNU-split-stack,"",@progbits`+"\n") + if cfg.Goos != "solaris" { + fmt.Fprintf(&buf, "\t"+`.section .note.GNU-stack,"",@progbits`+"\n") + fmt.Fprintf(&buf, "\t"+`.section .note.GNU-split-stack,"",@progbits`+"\n") + } if cfg.BuildN || cfg.BuildX { for _, line := range bytes.Split(buf.Bytes(), []byte("\n")) { @@ -434,15 +461,7 @@ func (b *Builder) useCache(a *Action, p *load.Package, actionHash cache.ActionID // If so, it's up to date and we can reuse it instead of rebuilding it. var buildID string if target != "" && !cfg.BuildA { - var err error - buildID, err = buildid.ReadFile(target) - if err != nil && b.ComputeStaleOnly { - if p != nil && !p.Stale { - p.Stale = true - p.StaleReason = "target missing" - } - return true - } + buildID, _ = buildid.ReadFile(target) if strings.HasPrefix(buildID, actionID+buildIDSeparator) { a.buildID = buildID a.built = target @@ -519,7 +538,10 @@ func (b *Builder) useCache(a *Action, p *load.Package, actionHash cache.ActionID } } } - return true + + // Fall through to update a.buildID from the build artifact cache, + // which will affect the computation of buildIDs for targets + // higher up in the dependency graph. } // Check the build artifact cache. @@ -547,6 +569,10 @@ func (b *Builder) useCache(a *Action, p *load.Package, actionHash cache.ActionID a.built = file a.Target = "DO NOT USE - using cache" a.buildID = buildID + if p := a.Package; p != nil { + // Clearer than explaining that something else is stale. + p.StaleReason = "not installed but available in build cache" + } return true } } @@ -557,6 +583,10 @@ func (b *Builder) useCache(a *Action, p *load.Package, actionHash cache.ActionID a.output = []byte{} } + if b.ComputeStaleOnly { + return true + } + return false } diff --git a/libgo/go/cmd/go/internal/work/exec.go b/libgo/go/cmd/go/internal/work/exec.go index 5527e90..5994dbc 100644 --- a/libgo/go/cmd/go/internal/work/exec.go +++ b/libgo/go/cmd/go/internal/work/exec.go @@ -512,6 +512,7 @@ func (b *Builder) build(a *Action) (err error) { ImportPath: a.Package.ImportPath, ImportMap: make(map[string]string), PackageFile: make(map[string]string), + Standard: make(map[string]bool), } a.vetCfg = vcfg for i, raw := range a.Package.Internal.RawImports { @@ -548,17 +549,24 @@ func (b *Builder) build(a *Action) (err error) { for _, a1 := range a.Deps { p1 := a1.Package - if p1 == nil || p1.ImportPath == "" || a1.built == "" { + if p1 == nil || p1.ImportPath == "" { continue } - fmt.Fprintf(&icfg, "packagefile %s=%s\n", p1.ImportPath, a1.built) + if a1.built != "" { + fmt.Fprintf(&icfg, "packagefile %s=%s\n", p1.ImportPath, a1.built) + } if vcfg != nil { // Add import mapping if needed // (for imports like "runtime/cgo" that appear only in generated code). if !vcfgMapped[p1.ImportPath] { vcfg.ImportMap[p1.ImportPath] = p1.ImportPath } - vcfg.PackageFile[p1.ImportPath] = a1.built + if a1.built != "" { + vcfg.PackageFile[p1.ImportPath] = a1.built + } + if p1.Standard { + vcfg.Standard[p1.ImportPath] = true + } } } @@ -693,6 +701,7 @@ type vetConfig struct { GoFiles []string ImportMap map[string]string PackageFile map[string]string + Standard map[string]bool ImportPath string SucceedOnTypecheckFailure bool @@ -722,7 +731,10 @@ func (b *Builder) vet(a *Action) error { if vcfg.ImportMap["fmt"] == "" { a1 := a.Deps[1] vcfg.ImportMap["fmt"] = "fmt" - vcfg.PackageFile["fmt"] = a1.built + if a1.built != "" { + vcfg.PackageFile["fmt"] = a1.built + } + vcfg.Standard["fmt"] = true } // During go test, ignore type-checking failures during vet. @@ -944,16 +956,29 @@ func splitPkgConfigOutput(out []byte) []string { // Calls pkg-config if needed and returns the cflags/ldflags needed to build the package. func (b *Builder) getPkgConfigFlags(p *load.Package) (cflags, ldflags []string, err error) { - if pkgs := p.CgoPkgConfig; len(pkgs) > 0 { + if pcargs := p.CgoPkgConfig; len(pcargs) > 0 { + // pkg-config permits arguments to appear anywhere in + // the command line. Move them all to the front, before --. + var pcflags []string + var pkgs []string + for _, pcarg := range pcargs { + if pcarg == "--" { + // We're going to add our own "--" argument. + } else if strings.HasPrefix(pcarg, "--") { + pcflags = append(pcflags, pcarg) + } else { + pkgs = append(pkgs, pcarg) + } + } for _, pkg := range pkgs { if !load.SafeArg(pkg) { return nil, nil, fmt.Errorf("invalid pkg-config package name: %s", pkg) } } var out []byte - out, err = b.runOut(p.Dir, p.ImportPath, nil, b.PkgconfigCmd(), "--cflags", "--", pkgs) + out, err = b.runOut(p.Dir, p.ImportPath, nil, b.PkgconfigCmd(), "--cflags", pcflags, "--", pkgs) if err != nil { - b.showOutput(nil, p.Dir, b.PkgconfigCmd()+" --cflags "+strings.Join(pkgs, " "), string(out)) + b.showOutput(nil, p.Dir, b.PkgconfigCmd()+" --cflags "+strings.Join(pcflags, " ")+strings.Join(pkgs, " "), string(out)) b.Print(err.Error() + "\n") return nil, nil, errPrintedOutput } @@ -963,15 +988,15 @@ func (b *Builder) getPkgConfigFlags(p *load.Package) (cflags, ldflags []string, return nil, nil, err } } - out, err = b.runOut(p.Dir, p.ImportPath, nil, b.PkgconfigCmd(), "--libs", "--", pkgs) + out, err = b.runOut(p.Dir, p.ImportPath, nil, b.PkgconfigCmd(), "--libs", pcflags, "--", pkgs) if err != nil { - b.showOutput(nil, p.Dir, b.PkgconfigCmd()+" --libs "+strings.Join(pkgs, " "), string(out)) + b.showOutput(nil, p.Dir, b.PkgconfigCmd()+" --libs "+strings.Join(pcflags, " ")+strings.Join(pkgs, " "), string(out)) b.Print(err.Error() + "\n") return nil, nil, errPrintedOutput } if len(out) > 0 { ldflags = strings.Fields(string(out)) - if err := checkLinkerFlags("CFLAGS", "pkg-config --cflags", ldflags); err != nil { + if err := checkLinkerFlags("LDFLAGS", "pkg-config --libs", ldflags); err != nil { return nil, nil, err } } @@ -1090,7 +1115,7 @@ func BuildInstallFunc(b *Builder, a *Action) (err error) { // We want to hide that awful detail as much as possible, so don't // advertise it by touching the mtimes (usually the libraries are up // to date). - if !a.buggyInstall { + if !a.buggyInstall && !b.ComputeStaleOnly { now := time.Now() os.Chtimes(a.Target, now, now) } @@ -1540,6 +1565,8 @@ func joinUnambiguously(a []string) string { buf.WriteByte(' ') } q := strconv.Quote(s) + // A gccgo command line can contain -( and -). + // Make sure we quote them since they are special to the shell. if s == "" || strings.ContainsAny(s, " ()") || len(q) > len(s)+2 { buf.WriteString(q) } else { @@ -1580,13 +1607,17 @@ func (b *Builder) Mkdir(dir string) error { // symlink creates a symlink newname -> oldname. func (b *Builder) Symlink(oldname, newname string) error { + // It's not an error to try to recreate an existing symlink. + if link, err := os.Readlink(newname); err == nil && link == oldname { + return nil + } + if cfg.BuildN || cfg.BuildX { - b.Showcmd("", "ln -sf %s %s", oldname, newname) + b.Showcmd("", "ln -s %s %s", oldname, newname) if cfg.BuildN { return nil } } - os.Remove(newname) return os.Symlink(oldname, newname) } diff --git a/libgo/go/cmd/go/internal/work/gccgo.go b/libgo/go/cmd/go/internal/work/gccgo.go index 72d4d9d..e8dab19 100644 --- a/libgo/go/cmd/go/internal/work/gccgo.go +++ b/libgo/go/cmd/go/internal/work/gccgo.go @@ -190,15 +190,15 @@ func (gccgoToolchain) pack(b *Builder, a *Action, afile string, ofiles []string) } absAfile := mkAbs(objdir, afile) // Try with D modifier first, then without if that fails. - if b.run(a, p.Dir, p.ImportPath, nil, "ar", "rcD", absAfile, absOfiles) != nil { + if cfg.Goos == "aix" || b.run(a, p.Dir, p.ImportPath, nil, "ar", "rcD", absAfile, absOfiles) != nil { + var arArgs []string if cfg.Goos == "aix" && cfg.Goarch == "ppc64" { // AIX puts both 32-bit and 64-bit objects in the same archive. // Tell the AIX "ar" command to only care about 64-bit objects. // AIX "ar" command does not know D option. - return b.run(a, p.Dir, p.ImportPath, nil, "ar", "-X64", "rc", absAfile, absOfiles) - } else { - return b.run(a, p.Dir, p.ImportPath, nil, "ar", "rc", absAfile, absOfiles) + arArgs = append(arArgs, "-X64") } + return b.run(a, p.Dir, p.ImportPath, nil, "ar", arArgs, "rc", absAfile, absOfiles) } return nil } @@ -466,7 +466,10 @@ func (tools gccgoToolchain) link(b *Builder, root *Action, out, importcfg string ldflags = append(ldflags, goLibBegin...) ldflags = append(ldflags, "-lgo", "-lgcc_s", "-lgcc", "-lc", "-lgcc") case "shared": - ldflags = append(ldflags, "-zdefs", "-shared", "-nostdlib", "-lgo", "-lgcc_s", "-lgcc", "-lc") + if cfg.Goos != "aix" { + ldflags = append(ldflags, "-zdefs") + } + ldflags = append(ldflags, "-shared", "-nostdlib", "-lgo", "-lgcc_s", "-lgcc", "-lc") case "pie": ldflags = append(ldflags, "-pie") diff --git a/libgo/go/cmd/go/internal/work/security.go b/libgo/go/cmd/go/internal/work/security.go index fee5bee..5c67aa9 100644 --- a/libgo/go/cmd/go/internal/work/security.go +++ b/libgo/go/cmd/go/internal/work/security.go @@ -34,6 +34,7 @@ import ( "fmt" "os" "regexp" + "strings" ) var re = regexp.MustCompile @@ -45,27 +46,65 @@ var validCompilerFlags = []*regexp.Regexp{ re(`-O([^@\-].*)`), re(`-W`), re(`-W([^@,]+)`), // -Wall but not -Wa,-foo. + re(`-Wa,-mbig-obj`), + re(`-ansi`), + re(`-f(no-)?blocks`), + re(`-f(no-)?common`), + re(`-f(no-)?constant-cfstrings`), + re(`-fdiagnostics-show-note-include-stack`), + re(`-f(no-)?exceptions`), + re(`-f(no-)?inline-functions`), + re(`-finput-charset=([^@\-].*)`), + re(`-f(no-)?fat-lto-objects`), + re(`-f(no-)?lto`), + re(`-fmacro-backtrace-limit=(.+)`), + re(`-fmessage-length=(.+)`), + re(`-f(no-)?modules`), re(`-f(no-)?objc-arc`), re(`-f(no-)?omit-frame-pointer`), + re(`-f(no-)?openmp(-simd)?`), + re(`-f(no-)?permissive`), re(`-f(no-)?(pic|PIC|pie|PIE)`), + re(`-f(no-)?rtti`), re(`-f(no-)?split-stack`), re(`-f(no-)?stack-(.+)`), re(`-f(no-)?strict-aliasing`), + re(`-f(un)signed-char`), + re(`-f(no-)?use-linker-plugin`), // safe if -B is not used; we don't permit -B re(`-fsanitize=(.+)`), + re(`-ftemplate-depth-(.+)`), + re(`-fvisibility=(.+)`), re(`-g([^@\-].*)?`), + re(`-m32`), + re(`-m64`), re(`-m(arch|cpu|fpu|tune)=([^@\-].*)`), + re(`-m(no-)?avx[0-9a-z.]*`), + re(`-m(no-)?ms-bitfields`), re(`-m(no-)?stack-(.+)`), re(`-mmacosx-(.+)`), + re(`-mios-simulator-version-min=(.+)`), + re(`-miphoneos-version-min=(.+)`), re(`-mnop-fun-dllimport`), + re(`-m(no-)?sse[0-9.]*`), + re(`-mwindows`), + re(`-pedantic(-errors)?`), + re(`-pipe`), re(`-pthread`), - re(`-std=([^@\-].*)`), + re(`-?-std=([^@\-].*)`), + re(`-?-stdlib=([^@\-].*)`), + re(`-w`), re(`-x([^@\-].*)`), } var validCompilerFlagsWithNextArg = []string{ + "-arch", "-D", "-I", "-framework", + "-isysroot", + "-isystem", + "--sysroot", + "-target", "-x", } @@ -73,29 +112,65 @@ var validLinkerFlags = []*regexp.Regexp{ re(`-F([^@\-].*)`), re(`-l([^@\-].*)`), re(`-L([^@\-].*)`), + re(`-O`), + re(`-O([^@\-].*)`), re(`-f(no-)?(pic|PIC|pie|PIE)`), re(`-fsanitize=([^@\-].*)`), re(`-g([^@\-].*)?`), re(`-m(arch|cpu|fpu|tune)=([^@\-].*)`), + re(`-mmacosx-(.+)`), + re(`-mios-simulator-version-min=(.+)`), + re(`-miphoneos-version-min=(.+)`), + re(`-mwindows`), re(`-(pic|PIC|pie|PIE)`), re(`-pthread`), + re(`-shared`), + re(`-?-static([-a-z0-9+]*)`), + re(`-?-stdlib=([^@\-].*)`), // Note that any wildcards in -Wl need to exclude comma, // since -Wl splits its argument at commas and passes // them all to the linker uninterpreted. Allowing comma // in a wildcard would allow tunnelling arbitrary additional // linker arguments through one of these. - re(`-Wl,-rpath,([^,@\-][^,]+)`), + re(`-Wl,--(no-)?allow-multiple-definition`), + re(`-Wl,--(no-)?as-needed`), + re(`-Wl,-Bdynamic`), + re(`-Wl,-Bstatic`), + re(`-Wl,-d[ny]`), + re(`-Wl,--disable-new-dtags`), + re(`-Wl,--enable-new-dtags`), + re(`-Wl,--end-group`), + re(`-Wl,-framework,[^,@\-][^,]+`), + re(`-Wl,-headerpad_max_install_names`), + re(`-Wl,--no-undefined`), + re(`-Wl,-rpath[=,]([^,@\-][^,]+)`), + re(`-Wl,-search_paths_first`), + re(`-Wl,-sectcreate,([^,@\-][^,]+),([^,@\-][^,]+),([^,@\-][^,]+)`), + re(`-Wl,--start-group`), + re(`-Wl,-?-static`), + re(`-Wl,--subsystem,(native|windows|console|posix|xbox)`), + re(`-Wl,-undefined[=,]([^,@\-][^,]+)`), + re(`-Wl,-?-unresolved-symbols=[^,]+`), re(`-Wl,--(no-)?warn-([^,]+)`), + re(`-Wl,-z,(no)?execstack`), + re(`-Wl,-z,relro`), - re(`[a-zA-Z0-9_].*\.(o|obj|dll|dylib|so)`), // direct linker inputs: x.o or libfoo.so (but not -foo.o or @foo.o) + re(`[a-zA-Z0-9_/].*\.(a|o|obj|dll|dylib|so)`), // direct linker inputs: x.o or libfoo.so (but not -foo.o or @foo.o) } var validLinkerFlagsWithNextArg = []string{ + "-arch", "-F", "-l", "-L", "-framework", + "-isysroot", + "--sysroot", + "-target", + "-Wl,-framework", + "-Wl,-rpath", + "-Wl,-undefined", } func checkCompilerFlags(name, source string, list []string) error { @@ -147,10 +222,21 @@ Args: i++ continue Args } + + // Permit -Wl,-framework -Wl,name. + if i+1 < len(list) && + strings.HasPrefix(arg, "-Wl,") && + strings.HasPrefix(list[i+1], "-Wl,") && + load.SafeArg(list[i+1][4:]) && + !strings.Contains(list[i+1][4:], ",") { + i++ + continue Args + } + if i+1 < len(list) { - return fmt.Errorf("invalid flag in %s: %s %s", source, arg, list[i+1]) + return fmt.Errorf("invalid flag in %s: %s %s (see https://golang.org/s/invalidflag)", source, arg, list[i+1]) } - return fmt.Errorf("invalid flag in %s: %s without argument", source, arg) + return fmt.Errorf("invalid flag in %s: %s without argument (see https://golang.org/s/invalidflag)", source, arg) } } Bad: diff --git a/libgo/go/cmd/go/internal/work/security_test.go b/libgo/go/cmd/go/internal/work/security_test.go index 739ab5a..bd898c9 100644 --- a/libgo/go/cmd/go/internal/work/security_test.go +++ b/libgo/go/cmd/go/internal/work/security_test.go @@ -132,14 +132,14 @@ var goodLinkerFlags = [][]string{ {"-l", "世界"}, {"-L", "framework"}, {"-framework", "Chocolate"}, + {"-Wl,-framework", "-Wl,Chocolate"}, + {"-Wl,-framework,Chocolate"}, + {"-Wl,-unresolved-symbols=ignore-all"}, } var badLinkerFlags = [][]string{ {"-DFOO"}, {"-Dfoo=bar"}, - {"-O"}, - {"-O2"}, - {"-Osmall"}, {"-W"}, {"-Wall"}, {"-fobjc-arc"}, @@ -152,7 +152,6 @@ var badLinkerFlags = [][]string{ {"-fno-stack-xxx"}, {"-mstack-overflow"}, {"-mno-stack-overflow"}, - {"-mmacosx-version"}, {"-mnop-fun-dllimport"}, {"-std=c99"}, {"-xc"}, @@ -185,6 +184,10 @@ var badLinkerFlags = [][]string{ {"-l", "-foo"}, {"-framework", "-Caffeine"}, {"-framework", "@Home"}, + {"-Wl,-framework,-Caffeine"}, + {"-Wl,-framework", "-Wl,@Home"}, + {"-Wl,-framework", "@Home"}, + {"-Wl,-framework,Chocolate,@Home"}, {"-x", "--c"}, {"-x", "@obj"}, {"-Wl,-rpath,@foo"}, diff --git a/libgo/go/cmd/go/mkalldocs.sh b/libgo/go/cmd/go/mkalldocs.sh new file mode 100755 index 0000000..72886db --- /dev/null +++ b/libgo/go/cmd/go/mkalldocs.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# Copyright 2012 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. + +set -e + +go build -o go.latest +./go.latest help documentation >alldocs.go +gofmt -w alldocs.go +rm go.latest diff --git a/libgo/go/cmd/go/mkdoc.sh b/libgo/go/cmd/go/mkdoc.sh deleted file mode 100644 index 12fd7ba..0000000 --- a/libgo/go/cmd/go/mkdoc.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh -# Copyright 2012 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. - -go install # So the next line will produce updated documentation. -go help documentation > doc.go -gofmt -w doc.go - diff --git a/libgo/go/cmd/internal/objabi/funcid.go b/libgo/go/cmd/internal/objabi/funcid.go new file mode 100644 index 0000000..55f1328 --- /dev/null +++ b/libgo/go/cmd/internal/objabi/funcid.go @@ -0,0 +1,34 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package objabi + +// A FuncID identifies particular functions that need to be treated +// specially by the runtime. +// Note that in some situations involving plugins, there may be multiple +// copies of a particular special runtime function. +// Note: this list must match the list in runtime/symtab.go. +type FuncID uint32 + +const ( + FuncID_normal FuncID = iota // not a special function + FuncID_goexit + FuncID_jmpdefer + FuncID_mcall + FuncID_morestack + FuncID_mstart + FuncID_rt0_go + FuncID_asmcgocall + FuncID_sigpanic + FuncID_runfinq + FuncID_bgsweep + FuncID_forcegchelper + FuncID_timerproc + FuncID_gcBgMarkWorker + FuncID_systemstack_switch + FuncID_systemstack + FuncID_cgocallback_gofunc + FuncID_gogo + FuncID_externalthreadhandler +) diff --git a/libgo/go/cmd/vet/main.go b/libgo/go/cmd/vet/main.go index 9d28ebd..49c1d32 100644 --- a/libgo/go/cmd/vet/main.go +++ b/libgo/go/cmd/vet/main.go @@ -292,6 +292,7 @@ type vetConfig struct { GoFiles []string ImportMap map[string]string PackageFile map[string]string + Standard map[string]bool SucceedOnTypecheckFailure bool @@ -309,7 +310,12 @@ func (v *vetConfig) Import(path string) (*types.Package, error) { if p == "" { return nil, fmt.Errorf("unknown import path %q", path) } - if v.PackageFile[p] == "" && v.Compiler != "gccgo" { + if v.PackageFile[p] == "" { + if v.Compiler == "gccgo" && v.Standard[path] { + // gccgo doesn't have sources for standard library packages, + // but the importer will do the right thing. + return v.imp.Import(path) + } return nil, fmt.Errorf("unknown package file for import %q", path) } return v.imp.Import(p) @@ -318,6 +324,10 @@ func (v *vetConfig) Import(path string) (*types.Package, error) { func (v *vetConfig) openPackageFile(path string) (io.ReadCloser, error) { file := v.PackageFile[path] if file == "" { + if v.Compiler == "gccgo" && v.Standard[path] { + // The importer knows how to handle this. + return nil, nil + } // Note that path here has been translated via v.ImportMap, // unlike in the error in Import above. We prefer the error in // Import, but it's worth diagnosing this one too, just in case. diff --git a/libgo/go/crypto/x509/name_constraints_test.go b/libgo/go/crypto/x509/name_constraints_test.go index 10cc348..bad488f 100644 --- a/libgo/go/crypto/x509/name_constraints_test.go +++ b/libgo/go/crypto/x509/name_constraints_test.go @@ -11,6 +11,7 @@ import ( "crypto/rand" "crypto/x509/pkix" "encoding/asn1" + "encoding/hex" "encoding/pem" "fmt" "io/ioutil" @@ -42,6 +43,7 @@ type nameConstraintsTest struct { roots []constraintsSpec intermediates [][]constraintsSpec leaf leafSpec + requestedEKUs []ExtKeyUsage expectedError string noOpenSSL bool } @@ -1444,6 +1446,118 @@ var nameConstraintsTests = []nameConstraintsTest{ }, expectedError: "\"https://example.com/test\" is excluded", }, + + // #75: While serverAuth in a CA certificate permits clientAuth in a leaf, + // serverAuth in a leaf shouldn't permit clientAuth when requested in + // VerifyOptions. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{}, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:example.com"}, + ekus: []string{"serverAuth"}, + }, + requestedEKUs: []ExtKeyUsage{ExtKeyUsageClientAuth}, + expectedError: "incompatible key usage", + }, + + // #76: However, MSSGC in a leaf should match a request for serverAuth. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{}, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:example.com"}, + ekus: []string{"msSGC"}, + }, + requestedEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}, + }, + + // An invalid DNS SAN should be detected only at validation time so + // that we can process CA certificates in the wild that have invalid SANs. + // See https://github.com/golang/go/issues/23995 + + // #77: an invalid DNS or mail SAN will not be detected if name constaint + // checking is not triggered. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{}, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:this is invalid", "email:this @ is invalid"}, + }, + }, + + // #78: an invalid DNS SAN will be detected if any name constraint checking + // is triggered. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + bad: []string{"uri:"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:this is invalid"}, + }, + expectedError: "cannot parse dnsName", + }, + + // #79: an invalid email SAN will be detected if any name constraint + // checking is triggered. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{ + bad: []string{"uri:"}, + }, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"email:this @ is invalid"}, + }, + expectedError: "cannot parse rfc822Name", + }, + + // #80: if several EKUs are requested, satisfying any of them is sufficient. + nameConstraintsTest{ + roots: []constraintsSpec{ + constraintsSpec{}, + }, + intermediates: [][]constraintsSpec{ + []constraintsSpec{ + constraintsSpec{}, + }, + }, + leaf: leafSpec{ + sans: []string{"dns:example.com"}, + ekus: []string{"email"}, + }, + requestedEKUs: []ExtKeyUsage{ExtKeyUsageClientAuth, ExtKeyUsageEmailProtection}, + }, } func makeConstraintsCACert(constraints constraintsSpec, name string, key *ecdsa.PrivateKey, parent *Certificate, parentKey *ecdsa.PrivateKey) (*Certificate, error) { @@ -1459,7 +1573,7 @@ func makeConstraintsCACert(constraints constraintsSpec, name string, key *ecdsa. NotAfter: time.Unix(2000, 0), KeyUsage: KeyUsageCertSign, BasicConstraintsValid: true, - IsCA: true, + IsCA: true, } if err := addConstraintsToTemplate(constraints, template); err != nil { @@ -1497,7 +1611,7 @@ func makeConstraintsLeafCert(leaf leafSpec, key *ecdsa.PrivateKey, parent *Certi NotAfter: time.Unix(2000, 0), KeyUsage: KeyUsageDigitalSignature, BasicConstraintsValid: true, - IsCA: false, + IsCA: false, } for _, name := range leaf.sans { @@ -1512,6 +1626,13 @@ func makeConstraintsLeafCert(leaf leafSpec, key *ecdsa.PrivateKey, parent *Certi } template.IPAddresses = append(template.IPAddresses, ip) + case strings.HasPrefix(name, "invalidip:"): + ipBytes, err := hex.DecodeString(name[10:]) + if err != nil { + return nil, fmt.Errorf("cannot parse invalid IP: %s", err) + } + template.IPAddresses = append(template.IPAddresses, net.IP(ipBytes)) + case strings.HasPrefix(name, "email:"): template.EmailAddresses = append(template.EmailAddresses, name[6:]) @@ -1781,6 +1902,7 @@ func TestConstraintCases(t *testing.T) { Roots: rootPool, Intermediates: intermediatePool, CurrentTime: time.Unix(1500, 0), + KeyUsages: test.requestedEKUs, } _, err = leafCert.Verify(verifyOpts) @@ -1972,12 +2094,13 @@ func TestBadNamesInConstraints(t *testing.T) { } func TestBadNamesInSANs(t *testing.T) { - // Bad names in SANs should not parse. + // Bad names in URI and IP SANs should not parse. Bad DNS and email SANs + // will parse and are tested in name constraint tests at the top of this + // file. badNames := []string{ - "dns:foo.com.", - "email:abc@foo.com.", - "email:foo.com.", "uri:https://example.com./dsf", + "invalidip:0102", + "invalidip:0102030405", } priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) diff --git a/libgo/go/crypto/x509/root_aix.go b/libgo/go/crypto/x509/root_aix.go index de5702d..4e7e9dd 100644 --- a/libgo/go/crypto/x509/root_aix.go +++ b/libgo/go/crypto/x509/root_aix.go @@ -5,4 +5,6 @@ package x509 // Possible certificate files; stop after finding one. -var certFiles []string +var certFiles = []string{ + "/var/ssl/certs/ca-bundle.crt", +} diff --git a/libgo/go/crypto/x509/verify.go b/libgo/go/crypto/x509/verify.go index 9477e85..0ea214b 100644 --- a/libgo/go/crypto/x509/verify.go +++ b/libgo/go/crypto/x509/verify.go @@ -6,12 +6,14 @@ package x509 import ( "bytes" + "encoding/asn1" "errors" "fmt" "net" "net/url" "reflect" "runtime" + "strconv" "strings" "time" "unicode/utf8" @@ -178,10 +180,14 @@ type VerifyOptions struct { Intermediates *CertPool Roots *CertPool // if nil, the system roots are used CurrentTime time.Time // if zero, the current time is used - // KeyUsage specifies which Extended Key Usage values are acceptable. - // An empty list means ExtKeyUsageServerAuth. Key usage is considered a - // constraint down the chain which mirrors Windows CryptoAPI behavior, - // but not the spec. To accept any key usage, include ExtKeyUsageAny. + // KeyUsage specifies which Extended Key Usage values are acceptable. A leaf + // certificate is accepted if it contains any of the listed values. An empty + // list means ExtKeyUsageServerAuth. To accept any key usage, include + // ExtKeyUsageAny. + // + // Certificate chains are required to nest extended key usage values, + // irrespective of this value. This matches the Windows CryptoAPI behavior, + // but not the spec. KeyUsages []ExtKeyUsage // MaxConstraintComparisions is the maximum number of comparisons to // perform when checking a given certificate's name constraints. If @@ -543,11 +549,16 @@ func (c *Certificate) checkNameConstraints(count *int, return nil } +const ( + checkingAgainstIssuerCert = iota + checkingAgainstLeafCert +) + // ekuPermittedBy returns true iff the given extended key usage is permitted by // the given EKU from a certificate. Normally, this would be a simple // comparison plus a special case for the “any” EKU. But, in order to support // existing certificates, some exceptions are made. -func ekuPermittedBy(eku, certEKU ExtKeyUsage) bool { +func ekuPermittedBy(eku, certEKU ExtKeyUsage, context int) bool { if certEKU == ExtKeyUsageAny || eku == certEKU { return true } @@ -564,18 +575,23 @@ func ekuPermittedBy(eku, certEKU ExtKeyUsage) bool { eku = mapServerAuthEKUs(eku) certEKU = mapServerAuthEKUs(certEKU) - if eku == certEKU || - // ServerAuth in a CA permits ClientAuth in the leaf. - (eku == ExtKeyUsageClientAuth && certEKU == ExtKeyUsageServerAuth) || + if eku == certEKU { + return true + } + + // If checking a requested EKU against the list in a leaf certificate there + // are fewer exceptions. + if context == checkingAgainstLeafCert { + return false + } + + // ServerAuth in a CA permits ClientAuth in the leaf. + return (eku == ExtKeyUsageClientAuth && certEKU == ExtKeyUsageServerAuth) || // Any CA may issue an OCSP responder certificate. eku == ExtKeyUsageOCSPSigning || // Code-signing CAs can use Microsoft's commercial and // kernel-mode EKUs. - ((eku == ExtKeyUsageMicrosoftCommercialCodeSigning || eku == ExtKeyUsageMicrosoftKernelCodeSigning) && certEKU == ExtKeyUsageCodeSigning) { - return true - } - - return false + (eku == ExtKeyUsageMicrosoftCommercialCodeSigning || eku == ExtKeyUsageMicrosoftKernelCodeSigning) && certEKU == ExtKeyUsageCodeSigning } // isValid performs validity checks on c given that it is a candidate to append @@ -630,8 +646,7 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V name := string(data) mailbox, ok := parseRFC2821Mailbox(name) if !ok { - // This certificate should not have parsed. - return errors.New("x509: internal error: rfc822Name SAN failed to parse") + return fmt.Errorf("x509: cannot parse rfc822Name %q", mailbox) } if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "email address", name, mailbox, @@ -643,6 +658,10 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V case nameTypeDNS: name := string(data) + if _, ok := domainToReverseLabels(name); !ok { + return fmt.Errorf("x509: cannot parse dnsName %q", name) + } + if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "DNS name", name, name, func(parsedName, constraint interface{}) (bool, error) { return matchDomainConstraint(parsedName.(string), constraint.(string)) @@ -716,7 +735,7 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V for _, caEKU := range c.ExtKeyUsage { comparisonCount++ - if ekuPermittedBy(eku, caEKU) { + if ekuPermittedBy(eku, caEKU, checkingAgainstIssuerCert) { continue NextEKU } } @@ -773,6 +792,18 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V return nil } +// formatOID formats an ASN.1 OBJECT IDENTIFER in the common, dotted style. +func formatOID(oid asn1.ObjectIdentifier) string { + ret := "" + for i, v := range oid { + if i > 0 { + ret += "." + } + ret += strconv.Itoa(v) + } + return ret +} + // Verify attempts to verify c by building one or more chains from c to a // certificate in opts.Roots, using certificates in opts.Intermediates if // needed. If successful, it returns one or more chains where the first @@ -847,16 +878,33 @@ func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err e } if checkEKU { + foundMatch := false NextUsage: for _, eku := range requestedKeyUsages { for _, leafEKU := range c.ExtKeyUsage { - if ekuPermittedBy(eku, leafEKU) { - continue NextUsage + if ekuPermittedBy(eku, leafEKU, checkingAgainstLeafCert) { + foundMatch = true + break NextUsage } } + } - oid, _ := oidFromExtKeyUsage(eku) - return nil, CertificateInvalidError{c, IncompatibleUsage, fmt.Sprintf("%#v", oid)} + if !foundMatch { + msg := "leaf contains the following, recognized EKUs: " + + for i, leafEKU := range c.ExtKeyUsage { + oid, ok := oidFromExtKeyUsage(leafEKU) + if !ok { + continue + } + + if i > 0 { + msg += ", " + } + msg += formatOID(oid) + } + + return nil, CertificateInvalidError{c, IncompatibleUsage, msg} } } diff --git a/libgo/go/crypto/x509/x509.go b/libgo/go/crypto/x509/x509.go index 86d9e82..ee08dd9 100644 --- a/libgo/go/crypto/x509/x509.go +++ b/libgo/go/crypto/x509/x509.go @@ -706,7 +706,9 @@ type Certificate struct { OCSPServer []string IssuingCertificateURL []string - // Subject Alternate Name values + // Subject Alternate Name values. (Note that these values may not be valid + // if invalid values were contained within a parsed certificate. For + // example, an element of DNSNames may not be a valid DNS domain name.) DNSNames []string EmailAddresses []string IPAddresses []net.IP @@ -1126,17 +1128,9 @@ func parseSANExtension(value []byte) (dnsNames, emailAddresses []string, ipAddre err = forEachSAN(value, func(tag int, data []byte) error { switch tag { case nameTypeEmail: - mailbox := string(data) - if _, ok := parseRFC2821Mailbox(mailbox); !ok { - return fmt.Errorf("x509: cannot parse rfc822Name %q", mailbox) - } - emailAddresses = append(emailAddresses, mailbox) + emailAddresses = append(emailAddresses, string(data)) case nameTypeDNS: - domain := string(data) - if _, ok := domainToReverseLabels(domain); !ok { - return fmt.Errorf("x509: cannot parse dnsName %q", string(data)) - } - dnsNames = append(dnsNames, domain) + dnsNames = append(dnsNames, string(data)) case nameTypeURI: uri, err := url.Parse(string(data)) if err != nil { @@ -1153,7 +1147,7 @@ func parseSANExtension(value []byte) (dnsNames, emailAddresses []string, ipAddre case net.IPv4len, net.IPv6len: ipAddresses = append(ipAddresses, data) default: - return errors.New("x509: certificate contained IP address of length " + strconv.Itoa(len(data))) + return errors.New("x509: cannot parse IP address of length " + strconv.Itoa(len(data))) } } @@ -2543,7 +2537,7 @@ func ParseCertificateRequest(asn1Data []byte) (*CertificateRequest, error) { func parseCertificateRequest(in *certificateRequest) (*CertificateRequest, error) { out := &CertificateRequest{ - Raw: in.Raw, + Raw: in.Raw, RawTBSCertificateRequest: in.TBSCSR.Raw, RawSubjectPublicKeyInfo: in.TBSCSR.PublicKey.Raw, RawSubject: in.TBSCSR.Subject.FullBytes, diff --git a/libgo/go/encoding/json/decode.go b/libgo/go/encoding/json/decode.go index 536f25d..730fb92 100644 --- a/libgo/go/encoding/json/decode.go +++ b/libgo/go/encoding/json/decode.go @@ -443,10 +443,25 @@ func (d *decodeState) valueQuoted() interface{} { // if it encounters an Unmarshaler, indirect stops and returns that. // if decodingNull is true, indirect stops at the last pointer so it can be set to nil. func (d *decodeState) indirect(v reflect.Value, decodingNull bool) (Unmarshaler, encoding.TextUnmarshaler, reflect.Value) { + // Issue #24153 indicates that it is generally not a guaranteed property + // that you may round-trip a reflect.Value by calling Value.Addr().Elem() + // and expect the value to still be settable for values derived from + // unexported embedded struct fields. + // + // The logic below effectively does this when it first addresses the value + // (to satisfy possible pointer methods) and continues to dereference + // subsequent pointers as necessary. + // + // After the first round-trip, we set v back to the original value to + // preserve the original RW flags contained in reflect.Value. + v0 := v + haveAddr := false + // If v is a named type and is addressable, // start with its address, so that if the type has pointer methods, // we find them. if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() { + haveAddr = true v = v.Addr() } for { @@ -455,6 +470,7 @@ func (d *decodeState) indirect(v reflect.Value, decodingNull bool) (Unmarshaler, if v.Kind() == reflect.Interface && !v.IsNil() { e := v.Elem() if e.Kind() == reflect.Ptr && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Ptr) { + haveAddr = false v = e continue } @@ -480,7 +496,13 @@ func (d *decodeState) indirect(v reflect.Value, decodingNull bool) (Unmarshaler, } } } - v = v.Elem() + + if haveAddr { + v = v0 // restore original value after round-trip Value.Addr().Elem() + haveAddr = false + } else { + v = v.Elem() + } } return nil, nil, v } diff --git a/libgo/go/encoding/json/decode_test.go b/libgo/go/encoding/json/decode_test.go index 34b7ec6..fa1531f 100644 --- a/libgo/go/encoding/json/decode_test.go +++ b/libgo/go/encoding/json/decode_test.go @@ -615,9 +615,9 @@ var unmarshalTests = []unmarshalTest{ out: S5{S8: S8{S9: S9{Y: 2}}}, }, { - in: `{"X": 1,"Y":2}`, - ptr: new(S5), - err: fmt.Errorf("json: unknown field \"X\""), + in: `{"X": 1,"Y":2}`, + ptr: new(S5), + err: fmt.Errorf("json: unknown field \"X\""), disallowUnknownFields: true, }, { @@ -626,9 +626,9 @@ var unmarshalTests = []unmarshalTest{ out: S10{S13: S13{S8: S8{S9: S9{Y: 2}}}}, }, { - in: `{"X": 1,"Y":2}`, - ptr: new(S10), - err: fmt.Errorf("json: unknown field \"X\""), + in: `{"X": 1,"Y":2}`, + ptr: new(S10), + err: fmt.Errorf("json: unknown field \"X\""), disallowUnknownFields: true, }, @@ -835,8 +835,8 @@ var unmarshalTests = []unmarshalTest{ "Q": 18, "extra": true }`, - ptr: new(Top), - err: fmt.Errorf("json: unknown field \"extra\""), + ptr: new(Top), + err: fmt.Errorf("json: unknown field \"extra\""), disallowUnknownFields: true, }, { @@ -862,8 +862,8 @@ var unmarshalTests = []unmarshalTest{ "Z": 17, "Q": 18 }`, - ptr: new(Top), - err: fmt.Errorf("json: unknown field \"extra\""), + ptr: new(Top), + err: fmt.Errorf("json: unknown field \"extra\""), disallowUnknownFields: true, }, } @@ -2089,10 +2089,14 @@ func TestInvalidStringOption(t *testing.T) { } } -// Test unmarshal behavior with regards to embedded pointers to unexported structs. -// If unallocated, this returns an error because unmarshal cannot set the field. -// Issue 21357. -func TestUnmarshalEmbeddedPointerUnexported(t *testing.T) { +// Test unmarshal behavior with regards to embedded unexported structs. +// +// (Issue 21357) If the embedded struct is a pointer and is unallocated, +// this returns an error because unmarshal cannot set the field. +// +// (Issue 24152) If the embedded struct is given an explicit name, +// ensure that the normal unmarshal logic does not panic in reflect. +func TestUnmarshalEmbeddedUnexported(t *testing.T) { type ( embed1 struct{ Q int } embed2 struct{ Q int } @@ -2119,6 +2123,18 @@ func TestUnmarshalEmbeddedPointerUnexported(t *testing.T) { *embed3 R int } + S6 struct { + embed1 `json:"embed1"` + } + S7 struct { + embed1 `json:"embed1"` + embed2 + } + S8 struct { + embed1 `json:"embed1"` + embed2 `json:"embed2"` + Q int + } ) tests := []struct { @@ -2154,6 +2170,32 @@ func TestUnmarshalEmbeddedPointerUnexported(t *testing.T) { ptr: new(S5), out: &S5{R: 2}, err: fmt.Errorf("json: cannot set embedded pointer to unexported struct: json.embed3"), + }, { + // Issue 24152, ensure decodeState.indirect does not panic. + in: `{"embed1": {"Q": 1}}`, + ptr: new(S6), + out: &S6{embed1{1}}, + }, { + // Issue 24153, check that we can still set forwarded fields even in + // the presence of a name conflict. + // + // This relies on obscure behavior of reflect where it is possible + // to set a forwarded exported field on an unexported embedded struct + // even though there is a name conflict, even when it would have been + // impossible to do so according to Go visibility rules. + // Go forbids this because it is ambiguous whether S7.Q refers to + // S7.embed1.Q or S7.embed2.Q. Since embed1 and embed2 are unexported, + // it should be impossible for an external package to set either Q. + // + // It is probably okay for a future reflect change to break this. + in: `{"embed1": {"Q": 1}, "Q": 2}`, + ptr: new(S7), + out: &S7{embed1{1}, embed2{2}}, + }, { + // Issue 24153, similar to the S7 case. + in: `{"embed1": {"Q": 1}, "embed2": {"Q": 2}, "Q": 3}`, + ptr: new(S8), + out: &S8{embed1{1}, embed2{2}, 3}, }} for i, tt := range tests { diff --git a/libgo/go/go/build/build.go b/libgo/go/go/build/build.go index 7902404..9df4930 100644 --- a/libgo/go/go/build/build.go +++ b/libgo/go/go/build/build.go @@ -238,7 +238,7 @@ func (ctxt *Context) gopath() []string { // that do not exist. func (ctxt *Context) SrcDirs() []string { var all []string - if ctxt.GOROOT != "" { + if ctxt.GOROOT != "" && ctxt.Compiler != "gccgo" { dir := ctxt.joinPath(ctxt.GOROOT, "src") if ctxt.isDir(dir) { all = append(all, dir) @@ -540,7 +540,7 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa inTestdata := func(sub string) bool { return strings.Contains(sub, "/testdata/") || strings.HasSuffix(sub, "/testdata") || strings.HasPrefix(sub, "testdata/") || sub == "testdata" } - if ctxt.GOROOT != "" { + if ctxt.GOROOT != "" && ctxt.Compiler != "gccgo" { root := ctxt.joinPath(ctxt.GOROOT, "src") if sub, ok := ctxt.hasSubdir(root, p.Dir); ok && !inTestdata(sub) { p.Goroot = true @@ -557,7 +557,7 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa // We found a potential import path for dir, // but check that using it wouldn't find something // else first. - if ctxt.GOROOT != "" { + if ctxt.GOROOT != "" && ctxt.Compiler != "gccgo" { if dir := ctxt.joinPath(ctxt.GOROOT, "src", sub); ctxt.isDir(dir) { p.ConflictDir = dir goto Found @@ -622,7 +622,7 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa } return false } - if searchVendor(ctxt.GOROOT, true) { + if ctxt.Compiler != "gccgo" && searchVendor(ctxt.GOROOT, true) { goto Found } for _, root := range gopath { @@ -635,16 +635,24 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa // Determine directory from import path. if ctxt.GOROOT != "" { dir := ctxt.joinPath(ctxt.GOROOT, "src", path) - isDir := ctxt.isDir(dir) - binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && ctxt.isFile(ctxt.joinPath(ctxt.GOROOT, pkga)) - if isDir || binaryOnly { - p.Dir = dir - p.Goroot = true - p.Root = ctxt.GOROOT - goto Found + if ctxt.Compiler != "gccgo" { + isDir := ctxt.isDir(dir) + binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && ctxt.isFile(ctxt.joinPath(ctxt.GOROOT, pkga)) + if isDir || binaryOnly { + p.Dir = dir + p.Goroot = true + p.Root = ctxt.GOROOT + goto Found + } } tried.goroot = dir } + if ctxt.Compiler == "gccgo" && isStandardPackage(path) { + p.Dir = ctxt.joinPath(ctxt.GOROOT, "src", path) + p.Goroot = true + p.Root = ctxt.GOROOT + goto Found + } for _, root := range gopath { dir := ctxt.joinPath(root, "src", path) isDir := ctxt.isDir(dir) @@ -708,6 +716,11 @@ Found: return p, pkgerr } + if ctxt.Compiler == "gccgo" && p.Goroot { + // gccgo has no sources for GOROOT packages. + return p, nil + } + dirs, err := ctxt.readDir(p.Dir) if err != nil { return p, err @@ -1595,14 +1608,7 @@ func init() { } } -func getToolDir() string { - if runtime.Compiler == "gccgo" { - return envOr("GCCGOTOOLDIR", runtime.GCCGOTOOLDIR) - } else { - return filepath.Join(runtime.GOROOT(), "pkg/tool/"+runtime.GOOS+"_"+runtime.GOARCH) - } -} - +// ToolDir is the directory containing build tools. var ToolDir = getToolDir() // IsLocalImport reports whether the import path is diff --git a/libgo/go/go/build/gc.go b/libgo/go/go/build/gc.go new file mode 100644 index 0000000..e2be2cb --- /dev/null +++ b/libgo/go/go/build/gc.go @@ -0,0 +1,137 @@ +// Copyright 2018 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 gc + +package build + +import ( + "os" + "os/exec" + "path/filepath" + "runtime" + "strings" + "sync" +) + +// getToolDir returns the default value of ToolDir. +func getToolDir() string { + return filepath.Join(runtime.GOROOT(), "pkg/tool/"+runtime.GOOS+"_"+runtime.GOARCH) +} + +// isStandardPackage is not used for the gc toolchain. +// However, this function may be called when using `go build -compiler=gccgo`. +func isStandardPackage(path string) bool { + return gccgoSearch.isStandard(path) +} + +// gccgoSearch holds the gccgo search directories. +type gccgoDirs struct { + once sync.Once + dirs []string +} + +// gccgoSearch is used to check whether a gccgo package exists in the +// standard library. +var gccgoSearch gccgoDirs + +// init finds the gccgo search directories. If this fails it leaves dirs == nil. +func (gd *gccgoDirs) init() { + gccgo := os.Getenv("GCCGO") + if gccgo == "" { + gccgo = "gccgo" + } + bin, err := exec.LookPath(gccgo) + if err != nil { + return + } + + allDirs, err := exec.Command(bin, "-print-search-dirs").Output() + if err != nil { + return + } + versionB, err := exec.Command(bin, "-dumpversion").Output() + if err != nil { + return + } + version := strings.TrimSpace(string(versionB)) + machineB, err := exec.Command(bin, "-dumpmachine").Output() + if err != nil { + return + } + machine := strings.TrimSpace(string(machineB)) + + dirsEntries := strings.Split(string(allDirs), "\n") + const prefix = "libraries: =" + var dirs []string + for _, dirEntry := range dirsEntries { + if strings.HasPrefix(dirEntry, prefix) { + dirs = filepath.SplitList(strings.TrimPrefix(dirEntry, prefix)) + break + } + } + if len(dirs) == 0 { + return + } + + var lastDirs []string + for _, dir := range dirs { + goDir := filepath.Join(dir, "go", version) + if fi, err := os.Stat(goDir); err == nil && fi.IsDir() { + gd.dirs = append(gd.dirs, goDir) + goDir = filepath.Join(goDir, machine) + if fi, err = os.Stat(goDir); err == nil && fi.IsDir() { + gd.dirs = append(gd.dirs, goDir) + } + } + if fi, err := os.Stat(dir); err == nil && fi.IsDir() { + lastDirs = append(lastDirs, dir) + } + } + gd.dirs = append(gd.dirs, lastDirs...) +} + +// isStandard returns whether path is a standard library for gccgo. +func (gd *gccgoDirs) isStandard(path string) bool { + // Quick check: if the first path component has a '.', it's not + // in the standard library. This skips most GOPATH directories. + i := strings.Index(path, "/") + if i < 0 { + i = len(path) + } + if strings.Contains(path[:i], ".") { + return false + } + + if path == "unsafe" { + // Special case. + return true + } + + gd.once.Do(gd.init) + if gd.dirs == nil { + // We couldn't find the gccgo search directories. + // Best guess, since the first component did not contain + // '.', is that this is a standard library package. + return true + } + + for _, dir := range gd.dirs { + full := filepath.Join(dir, path) + pkgdir, pkg := filepath.Split(full) + for _, p := range [...]string{ + full, + full + ".gox", + pkgdir + "lib" + pkg + ".so", + pkgdir + "lib" + pkg + ".a", + full + ".o", + } { + if fi, err := os.Stat(p); err == nil && !fi.IsDir() { + return true + } + } + } + + return false +} diff --git a/libgo/go/go/build/gccgo.go b/libgo/go/go/build/gccgo.go new file mode 100644 index 0000000..59e089d --- /dev/null +++ b/libgo/go/go/build/gccgo.go @@ -0,0 +1,20 @@ +// Copyright 2018 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 gccgo + +package build + +import "runtime" + +// getToolDir returns the default value of ToolDir. +func getToolDir() string { + return envOr("GCCGOTOOLDIR", runtime.GCCGOTOOLDIR) +} + +// isStandardPackage returns whether path names a standard library package. +// This uses a list generated at build time. +func isStandardPackage(path string) bool { + return stdpkg[path] +} diff --git a/libgo/go/go/build/syslist.go b/libgo/go/go/build/syslist.go index 679d195..0c39634 100644 --- a/libgo/go/go/build/syslist.go +++ b/libgo/go/go/build/syslist.go @@ -5,4 +5,4 @@ package build const goosList = "aix android darwin dragonfly freebsd linux nacl netbsd openbsd plan9 solaris windows zos " -const goarchList = "386 amd64 amd64p32 arm armbe arm64 arm64be alpha m68k ppc64 ppc64le mips mipsle mips64 mips64le mips64p32 mips64p32le ppc riscv64 s390 s390x sh shbe sparc sparc64" +const goarchList = "386 amd64 amd64p32 arm armbe arm64 arm64be alpha m68k ppc64 ppc64le mips mipsle mips64 mips64le mips64p32 mips64p32le nios2 ppc riscv64 s390 s390x sh shbe sparc sparc64" diff --git a/libgo/go/go/internal/gccgoimporter/importer.go b/libgo/go/go/internal/gccgoimporter/importer.go index 843d196..ddaed40 100644 --- a/libgo/go/go/internal/gccgoimporter/importer.go +++ b/libgo/go/go/internal/gccgoimporter/importer.go @@ -176,7 +176,7 @@ func GetImporter(searchpaths []string, initmap map[*types.Package]InitData) Impo return p, nil } rc, err := lookup(pkgpath) - if err == nil { + if err == nil && rc != nil { defer rc.Close() rs, ok := rc.(io.ReadSeeker) if !ok { diff --git a/libgo/go/go/internal/srcimporter/srcimporter.go b/libgo/go/go/internal/srcimporter/srcimporter.go index b0dc8ab..9ed7e5e 100644 --- a/libgo/go/go/internal/srcimporter/srcimporter.go +++ b/libgo/go/go/internal/srcimporter/srcimporter.go @@ -44,9 +44,9 @@ func New(ctxt *build.Context, fset *token.FileSet, packages map[string]*types.Pa // for a package that is in the process of being imported. var importing types.Package -// Import(path) is a shortcut for ImportFrom(path, "", 0). +// Import(path) is a shortcut for ImportFrom(path, ".", 0). func (p *Importer) Import(path string) (*types.Package, error) { - return p.ImportFrom(path, "", 0) + return p.ImportFrom(path, ".", 0) // use "." rather than "" (see issue #24441) } // ImportFrom imports the package with the given import path resolved from the given srcDir, @@ -60,23 +60,10 @@ func (p *Importer) ImportFrom(path, srcDir string, mode types.ImportMode) (*type panic("non-zero import mode") } - // determine package path (do vendor resolution) - var bp *build.Package - var err error - switch { - default: - if abs, err := p.absPath(srcDir); err == nil { // see issue #14282 - srcDir = abs - } - bp, err = p.ctxt.Import(path, srcDir, build.FindOnly) - - case build.IsLocalImport(path): - // "./x" -> "srcDir/x" - bp, err = p.ctxt.ImportDir(filepath.Join(srcDir, path), build.FindOnly) - - case p.isAbsPath(path): - return nil, fmt.Errorf("invalid absolute import path %q", path) + if abs, err := p.absPath(srcDir); err == nil { // see issue #14282 + srcDir = abs } + bp, err := p.ctxt.Import(path, srcDir, 0) if err != nil { return nil, err // err may be *build.NoGoError - return as is } @@ -113,11 +100,6 @@ func (p *Importer) ImportFrom(path, srcDir string, mode types.ImportMode) (*type } }() - // collect package files - bp, err = p.ctxt.ImportDir(bp.Dir, 0) - if err != nil { - return nil, err // err may be *build.NoGoError - return as is - } var filenames []string filenames = append(filenames, bp.GoFiles...) filenames = append(filenames, bp.CgoFiles...) diff --git a/libgo/go/go/internal/srcimporter/srcimporter_test.go b/libgo/go/go/internal/srcimporter/srcimporter_test.go index 356e71d..dd4d56a 100644 --- a/libgo/go/go/internal/srcimporter/srcimporter_test.go +++ b/libgo/go/go/internal/srcimporter/srcimporter_test.go @@ -10,6 +10,7 @@ import ( "go/types" "internal/testenv" "io/ioutil" + "path" "path/filepath" "runtime" "strings" @@ -162,3 +163,34 @@ func TestIssue20855(t *testing.T) { t.Error("got no package despite no hard errors") } } + +func testImportPath(t *testing.T, pkgPath string) { + if !testenv.HasSrc() { + t.Skip("no source code available") + } + + pkgName := path.Base(pkgPath) + + pkg, err := importer.Import(pkgPath) + if err != nil { + t.Fatal(err) + } + + if pkg.Name() != pkgName { + t.Errorf("got %q; want %q", pkg.Name(), pkgName) + } + + if pkg.Path() != pkgPath { + t.Errorf("got %q; want %q", pkg.Path(), pkgPath) + } +} + +// TestIssue23092 tests relative imports. +func TestIssue23092(t *testing.T) { + testImportPath(t, "./testdata/issue23092") +} + +// TestIssue24392 tests imports against a path containing 'testdata'. +func TestIssue24392(t *testing.T) { + testImportPath(t, "go/internal/srcimporter/testdata/issue24392") +} diff --git a/libgo/go/go/internal/srcimporter/testdata/issue23092/issue23092.go b/libgo/go/go/internal/srcimporter/testdata/issue23092/issue23092.go new file mode 100644 index 0000000..608698b --- /dev/null +++ b/libgo/go/go/internal/srcimporter/testdata/issue23092/issue23092.go @@ -0,0 +1,5 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package issue23092 diff --git a/libgo/go/go/internal/srcimporter/testdata/issue24392/issue24392.go b/libgo/go/go/internal/srcimporter/testdata/issue24392/issue24392.go new file mode 100644 index 0000000..8ad5221 --- /dev/null +++ b/libgo/go/go/internal/srcimporter/testdata/issue24392/issue24392.go @@ -0,0 +1,5 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package issue24392 diff --git a/libgo/go/internal/singleflight/singleflight.go b/libgo/go/internal/singleflight/singleflight.go index 1e9960d..b2d82e2 100644 --- a/libgo/go/internal/singleflight/singleflight.go +++ b/libgo/go/internal/singleflight/singleflight.go @@ -103,11 +103,21 @@ func (g *Group) doCall(c *call, key string, fn func() (interface{}, error)) { g.mu.Unlock() } -// Forget tells the singleflight to forget about a key. Future calls -// to Do for this key will call the function rather than waiting for -// an earlier call to complete. -func (g *Group) Forget(key string) { +// ForgetUnshared tells the singleflight to forget about a key if it is not +// shared with any other goroutines. Future calls to Do for a forgotten key +// will call the function rather than waiting for an earlier call to complete. +// Returns whether the key was forgotten or unknown--that is, whether no +// other goroutines are waiting for the result. +func (g *Group) ForgetUnshared(key string) bool { g.mu.Lock() - delete(g.m, key) - g.mu.Unlock() + defer g.mu.Unlock() + c, ok := g.m[key] + if !ok { + return true + } + if c.dups == 0 { + delete(g.m, key) + return true + } + return false } diff --git a/libgo/go/internal/syscall/unix/getrandom_linux_generic.go b/libgo/go/internal/syscall/unix/getrandom_linux_generic.go index d6af3de..2d513df 100644 --- a/libgo/go/internal/syscall/unix/getrandom_linux_generic.go +++ b/libgo/go/internal/syscall/unix/getrandom_linux_generic.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build arm64 riscv64 +// +build arm64 nios2 riscv64 package unix diff --git a/libgo/go/net/http/pprof/pprof.go b/libgo/go/net/http/pprof/pprof.go index 21992d6..77e0bcd 100644 --- a/libgo/go/net/http/pprof/pprof.go +++ b/libgo/go/net/http/pprof/pprof.go @@ -80,6 +80,7 @@ func init() { // command line, with arguments separated by NUL bytes. // The package initialization registers it as /debug/pprof/cmdline. func Cmdline(w http.ResponseWriter, r *http.Request) { + w.Header().Set("X-Content-Type-Options", "nosniff") w.Header().Set("Content-Type", "text/plain; charset=utf-8") fmt.Fprintf(w, strings.Join(os.Args, "\x00")) } @@ -100,33 +101,36 @@ func durationExceedsWriteTimeout(r *http.Request, seconds float64) bool { return ok && srv.WriteTimeout != 0 && seconds >= srv.WriteTimeout.Seconds() } +func serveError(w http.ResponseWriter, status int, txt string) { + w.Header().Set("Content-Type", "text/plain; charset=utf-8") + w.Header().Set("X-Go-Pprof", "1") + w.Header().Del("Content-Disposition") + w.WriteHeader(status) + fmt.Fprintln(w, txt) +} + // Profile responds with the pprof-formatted cpu profile. // The package initialization registers it as /debug/pprof/profile. func Profile(w http.ResponseWriter, r *http.Request) { + w.Header().Set("X-Content-Type-Options", "nosniff") sec, _ := strconv.ParseInt(r.FormValue("seconds"), 10, 64) if sec == 0 { sec = 30 } if durationExceedsWriteTimeout(r, float64(sec)) { - w.Header().Set("Content-Type", "text/plain; charset=utf-8") - w.Header().Set("X-Go-Pprof", "1") - w.WriteHeader(http.StatusBadRequest) - fmt.Fprintln(w, "profile duration exceeds server's WriteTimeout") + serveError(w, http.StatusBadRequest, "profile duration exceeds server's WriteTimeout") return } // Set Content Type assuming StartCPUProfile will work, // because if it does it starts writing. w.Header().Set("Content-Type", "application/octet-stream") + w.Header().Set("Content-Disposition", `attachment; filename="profile"`) if err := pprof.StartCPUProfile(w); err != nil { // StartCPUProfile failed, so no writes yet. - // Can change header back to text content - // and send error code. - w.Header().Set("Content-Type", "text/plain; charset=utf-8") - w.Header().Set("X-Go-Pprof", "1") - w.WriteHeader(http.StatusInternalServerError) - fmt.Fprintf(w, "Could not enable CPU profiling: %s\n", err) + serveError(w, http.StatusInternalServerError, + fmt.Sprintf("Could not enable CPU profiling: %s", err)) return } sleep(w, time.Duration(sec)*time.Second) @@ -137,29 +141,25 @@ func Profile(w http.ResponseWriter, r *http.Request) { // Tracing lasts for duration specified in seconds GET parameter, or for 1 second if not specified. // The package initialization registers it as /debug/pprof/trace. func Trace(w http.ResponseWriter, r *http.Request) { + w.Header().Set("X-Content-Type-Options", "nosniff") sec, err := strconv.ParseFloat(r.FormValue("seconds"), 64) if sec <= 0 || err != nil { sec = 1 } if durationExceedsWriteTimeout(r, sec) { - w.Header().Set("Content-Type", "text/plain; charset=utf-8") - w.Header().Set("X-Go-Pprof", "1") - w.WriteHeader(http.StatusBadRequest) - fmt.Fprintln(w, "profile duration exceeds server's WriteTimeout") + serveError(w, http.StatusBadRequest, "profile duration exceeds server's WriteTimeout") return } // Set Content Type assuming trace.Start will work, // because if it does it starts writing. w.Header().Set("Content-Type", "application/octet-stream") + w.Header().Set("Content-Disposition", `attachment; filename="trace"`) if err := trace.Start(w); err != nil { // trace.Start failed, so no writes yet. - // Can change header back to text content and send error code. - w.Header().Set("Content-Type", "text/plain; charset=utf-8") - w.Header().Set("X-Go-Pprof", "1") - w.WriteHeader(http.StatusInternalServerError) - fmt.Fprintf(w, "Could not enable tracing: %s\n", err) + serveError(w, http.StatusInternalServerError, + fmt.Sprintf("Could not enable tracing: %s", err)) return } sleep(w, time.Duration(sec*float64(time.Second))) @@ -170,6 +170,7 @@ func Trace(w http.ResponseWriter, r *http.Request) { // responding with a table mapping program counters to function names. // The package initialization registers it as /debug/pprof/symbol. func Symbol(w http.ResponseWriter, r *http.Request) { + w.Header().Set("X-Content-Type-Options", "nosniff") w.Header().Set("Content-Type", "text/plain; charset=utf-8") // We have to read the whole POST body before @@ -222,18 +223,23 @@ func Handler(name string) http.Handler { type handler string func (name handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "text/plain; charset=utf-8") - debug, _ := strconv.Atoi(r.FormValue("debug")) + w.Header().Set("X-Content-Type-Options", "nosniff") p := pprof.Lookup(string(name)) if p == nil { - w.WriteHeader(404) - fmt.Fprintf(w, "Unknown profile: %s\n", name) + serveError(w, http.StatusNotFound, "Unknown profile") return } gc, _ := strconv.Atoi(r.FormValue("gc")) if name == "heap" && gc > 0 { runtime.GC() } + debug, _ := strconv.Atoi(r.FormValue("debug")) + if debug != 0 { + w.Header().Set("Content-Type", "text/plain; charset=utf-8") + } else { + w.Header().Set("Content-Type", "application/octet-stream") + w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, name)) + } p.WriteTo(w, debug) } diff --git a/libgo/go/net/http/pprof/pprof_test.go b/libgo/go/net/http/pprof/pprof_test.go new file mode 100644 index 0000000..47dd35b --- /dev/null +++ b/libgo/go/net/http/pprof/pprof_test.go @@ -0,0 +1,69 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package pprof + +import ( + "bytes" + "io/ioutil" + "net/http" + "net/http/httptest" + "testing" +) + +func TestHandlers(t *testing.T) { + testCases := []struct { + path string + handler http.HandlerFunc + statusCode int + contentType string + contentDisposition string + resp []byte + }{ + {"/debug/pprof/<script>scripty<script>", Index, http.StatusNotFound, "text/plain; charset=utf-8", "", []byte("Unknown profile\n")}, + {"/debug/pprof/heap", Index, http.StatusOK, "application/octet-stream", `attachment; filename="heap"`, nil}, + {"/debug/pprof/heap?debug=1", Index, http.StatusOK, "text/plain; charset=utf-8", "", nil}, + {"/debug/pprof/cmdline", Cmdline, http.StatusOK, "text/plain; charset=utf-8", "", nil}, + {"/debug/pprof/profile?seconds=1", Profile, http.StatusOK, "application/octet-stream", `attachment; filename="profile"`, nil}, + {"/debug/pprof/symbol", Symbol, http.StatusOK, "text/plain; charset=utf-8", "", nil}, + {"/debug/pprof/trace", Trace, http.StatusOK, "application/octet-stream", `attachment; filename="trace"`, nil}, + } + for _, tc := range testCases { + t.Run(tc.path, func(t *testing.T) { + req := httptest.NewRequest("GET", "http://example.com"+tc.path, nil) + w := httptest.NewRecorder() + tc.handler(w, req) + + resp := w.Result() + if got, want := resp.StatusCode, tc.statusCode; got != want { + t.Errorf("status code: got %d; want %d", got, want) + } + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Errorf("when reading response body, expected non-nil err; got %v", err) + } + if got, want := resp.Header.Get("X-Content-Type-Options"), "nosniff"; got != want { + t.Errorf("X-Content-Type-Options: got %q; want %q", got, want) + } + if got, want := resp.Header.Get("Content-Type"), tc.contentType; got != want { + t.Errorf("Content-Type: got %q; want %q", got, want) + } + if got, want := resp.Header.Get("Content-Disposition"), tc.contentDisposition; got != want { + t.Errorf("Content-Disposition: got %q; want %q", got, want) + } + + if resp.StatusCode == http.StatusOK { + return + } + if got, want := resp.Header.Get("X-Go-Pprof"), "1"; got != want { + t.Errorf("X-Go-Pprof: got %q; want %q", got, want) + } + if !bytes.Equal(body, tc.resp) { + t.Errorf("response: got %q; want %q", body, tc.resp) + } + }) + } + +} diff --git a/libgo/go/net/lookup.go b/libgo/go/net/lookup.go index 85e4729..a65b735 100644 --- a/libgo/go/net/lookup.go +++ b/libgo/go/net/lookup.go @@ -194,10 +194,16 @@ func (r *Resolver) LookupIPAddr(ctx context.Context, host string) ([]IPAddr, err resolverFunc = alt } + // We don't want a cancelation of ctx to affect the + // lookupGroup operation. Otherwise if our context gets + // canceled it might cause an error to be returned to a lookup + // using a completely different context. + lookupGroupCtx, lookupGroupCancel := context.WithCancel(context.Background()) + dnsWaitGroup.Add(1) ch, called := lookupGroup.DoChan(host, func() (interface{}, error) { defer dnsWaitGroup.Done() - return testHookLookupIP(ctx, resolverFunc, host) + return testHookLookupIP(lookupGroupCtx, resolverFunc, host) }) if !called { dnsWaitGroup.Done() @@ -205,20 +211,28 @@ func (r *Resolver) LookupIPAddr(ctx context.Context, host string) ([]IPAddr, err select { case <-ctx.Done(): - // If the DNS lookup timed out for some reason, force - // future requests to start the DNS lookup again - // rather than waiting for the current lookup to - // complete. See issue 8602. - ctxErr := ctx.Err() - if ctxErr == context.DeadlineExceeded { - lookupGroup.Forget(host) + // Our context was canceled. If we are the only + // goroutine looking up this key, then drop the key + // from the lookupGroup and cancel the lookup. + // If there are other goroutines looking up this key, + // let the lookup continue uncanceled, and let later + // lookups with the same key share the result. + // See issues 8602, 20703, 22724. + if lookupGroup.ForgetUnshared(host) { + lookupGroupCancel() + } else { + go func() { + <-ch + lookupGroupCancel() + }() } - err := mapErr(ctxErr) + err := mapErr(ctx.Err()) if trace != nil && trace.DNSDone != nil { trace.DNSDone(nil, false, err) } return nil, err case r := <-ch: + lookupGroupCancel() if trace != nil && trace.DNSDone != nil { addrs, _ := r.Val.([]IPAddr) trace.DNSDone(ipAddrsEface(addrs), r.Shared, r.Err) diff --git a/libgo/go/net/lookup_test.go b/libgo/go/net/lookup_test.go index bfb8725..24787cc 100644 --- a/libgo/go/net/lookup_test.go +++ b/libgo/go/net/lookup_test.go @@ -791,3 +791,28 @@ func TestLookupNonLDH(t *testing.T) { t.Fatalf("lookup error = %v, want %v", err, errNoSuchHost) } } + +func TestLookupContextCancel(t *testing.T) { + if testenv.Builder() == "" { + testenv.MustHaveExternalNetwork(t) + } + if runtime.GOOS == "nacl" { + t.Skip("skip on nacl") + } + + defer dnsWaitGroup.Wait() + + ctx, ctxCancel := context.WithCancel(context.Background()) + ctxCancel() + _, err := DefaultResolver.LookupIPAddr(ctx, "google.com") + if err != errCanceled { + testenv.SkipFlakyNet(t) + t.Fatal(err) + } + ctx = context.Background() + _, err = DefaultResolver.LookupIPAddr(ctx, "google.com") + if err != nil { + testenv.SkipFlakyNet(t) + t.Fatal(err) + } +} diff --git a/libgo/go/net/tcpsock_unix_test.go b/libgo/go/net/tcpsock_unix_test.go index 3af1834..95c02d2 100644 --- a/libgo/go/net/tcpsock_unix_test.go +++ b/libgo/go/net/tcpsock_unix_test.go @@ -87,6 +87,7 @@ func TestTCPSpuriousConnSetupCompletionWithCancel(t *testing.T) { if testenv.Builder() == "" { testenv.MustHaveExternalNetwork(t) } + defer dnsWaitGroup.Wait() t.Parallel() const tries = 10000 var wg sync.WaitGroup diff --git a/libgo/go/os/signal/signal_cgo_test.go b/libgo/go/os/signal/signal_cgo_test.go index 84a2a08..16aeea8 100644 --- a/libgo/go/os/signal/signal_cgo_test.go +++ b/libgo/go/os/signal/signal_cgo_test.go @@ -89,6 +89,8 @@ func TestTerminalSignal(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() cmd := exec.CommandContext(ctx, bash, "--norc", "--noprofile", "-i") + // Clear HISTFILE so that we don't read or clobber the user's bash history. + cmd.Env = append(os.Environ(), "HISTFILE=") cmd.Stdin = slave cmd.Stdout = slave cmd.Stderr = slave diff --git a/libgo/go/reflect/all_test.go b/libgo/go/reflect/all_test.go index 3070aac..96b57ef 100644 --- a/libgo/go/reflect/all_test.go +++ b/libgo/go/reflect/all_test.go @@ -3928,8 +3928,8 @@ func TestOverflow(t *testing.T) { } } -func checkSameType(t *testing.T, x, y interface{}) { - if TypeOf(x) != TypeOf(y) { +func checkSameType(t *testing.T, x Type, y interface{}) { + if x != TypeOf(y) || TypeOf(Zero(x).Interface()) != TypeOf(y) { t.Errorf("did not find preexisting type for %s (vs %s)", TypeOf(x), TypeOf(y)) } } @@ -4058,7 +4058,7 @@ func TestArrayOf(t *testing.T) { // check that type already in binary is found type T int - checkSameType(t, Zero(ArrayOf(5, TypeOf(T(1)))).Interface(), [5]T{}) + checkSameType(t, ArrayOf(5, TypeOf(T(1))), [5]T{}) } func TestArrayOfGC(t *testing.T) { @@ -4195,7 +4195,7 @@ func TestSliceOf(t *testing.T) { // check that type already in binary is found type T1 int - checkSameType(t, Zero(SliceOf(TypeOf(T1(1)))).Interface(), []T1{}) + checkSameType(t, SliceOf(TypeOf(T1(1))), []T1{}) } func TestSliceOverflow(t *testing.T) { @@ -4410,7 +4410,18 @@ func TestStructOf(t *testing.T) { }) }) // check that type already in binary is found - checkSameType(t, Zero(StructOf(fields[2:3])).Interface(), struct{ Y uint64 }{}) + checkSameType(t, StructOf(fields[2:3]), struct{ Y uint64 }{}) + + // gccgo used to fail this test. + type structFieldType interface{} + checkSameType(t, + StructOf([]StructField{ + StructField{ + Name: "F", + Type: TypeOf((*structFieldType)(nil)).Elem(), + }, + }), + struct{ F structFieldType }{}) } func TestStructOfExportRules(t *testing.T) { @@ -4963,7 +4974,7 @@ func TestChanOf(t *testing.T) { // check that type already in binary is found type T1 int - checkSameType(t, Zero(ChanOf(BothDir, TypeOf(T1(1)))).Interface(), (chan T1)(nil)) + checkSameType(t, ChanOf(BothDir, TypeOf(T1(1))), (chan T1)(nil)) } func TestChanOfDir(t *testing.T) { @@ -4974,8 +4985,8 @@ func TestChanOfDir(t *testing.T) { // check that type already in binary is found type T1 int - checkSameType(t, Zero(ChanOf(RecvDir, TypeOf(T1(1)))).Interface(), (<-chan T1)(nil)) - checkSameType(t, Zero(ChanOf(SendDir, TypeOf(T1(1)))).Interface(), (chan<- T1)(nil)) + checkSameType(t, ChanOf(RecvDir, TypeOf(T1(1))), (<-chan T1)(nil)) + checkSameType(t, ChanOf(SendDir, TypeOf(T1(1))), (chan<- T1)(nil)) // check String form of ChanDir if crt.ChanDir().String() != "<-chan" { @@ -5051,7 +5062,7 @@ func TestMapOf(t *testing.T) { } // check that type already in binary is found - checkSameType(t, Zero(MapOf(TypeOf(V(0)), TypeOf(K("")))).Interface(), map[V]K(nil)) + checkSameType(t, MapOf(TypeOf(V(0)), TypeOf(K(""))), map[V]K(nil)) // check that invalid key type panics shouldPanic(func() { MapOf(TypeOf((func())(nil)), TypeOf(false)) }) @@ -5181,7 +5192,7 @@ func TestFuncOf(t *testing.T) { {in: []Type{TypeOf(int(0))}, out: []Type{TypeOf(false), TypeOf("")}, want: (func(int) (bool, string))(nil)}, } for _, tt := range testCases { - checkSameType(t, Zero(FuncOf(tt.in, tt.out, tt.variadic)).Interface(), tt.want) + checkSameType(t, FuncOf(tt.in, tt.out, tt.variadic), tt.want) } // check that variadic requires last element be a slice. diff --git a/libgo/go/reflect/type.go b/libgo/go/reflect/type.go index 6b082c1..07fe4d0 100644 --- a/libgo/go/reflect/type.go +++ b/libgo/go/reflect/type.go @@ -1475,8 +1475,10 @@ func ChanOf(dir ChanDir, t Type) Type { ch.uncommonType = nil ch.ptrToThis = nil - ti, _ := lookupCache.LoadOrStore(ckey, &ch.rtype) - return ti.(Type) + // Canonicalize before storing in lookupCache + ti := toType(&ch.rtype) + lookupCache.Store(ckey, ti.(*rtype)) + return ti } func ismapkey(*rtype) bool // implemented in runtime @@ -1537,8 +1539,10 @@ func MapOf(key, elem Type) Type { mt.reflexivekey = isReflexive(ktyp) mt.needkeyupdate = needKeyUpdate(ktyp) - ti, _ := lookupCache.LoadOrStore(ckey, &mt.rtype) - return ti.(Type) + // Canonicalize before storing in lookupCache + ti := toType(&mt.rtype) + lookupCache.Store(ckey, ti.(*rtype)) + return ti } // FuncOf returns the function type with the given argument and result types. @@ -1621,7 +1625,10 @@ func FuncOf(in, out []Type, variadic bool) Type { ft.string = &str ft.uncommonType = nil ft.ptrToThis = nil - return addToCache(&ft.rtype) + + // Canonicalize before storing in funcLookupCache + tc := toType(&ft.rtype) + return addToCache(tc.(*rtype)) } // funcStr builds a string representation of a funcType. @@ -1855,8 +1862,10 @@ func SliceOf(t Type) Type { slice.uncommonType = nil slice.ptrToThis = nil - ti, _ := lookupCache.LoadOrStore(ckey, &slice.rtype) - return ti.(Type) + // Canonicalize before storing in lookupCache + ti := toType(&slice.rtype) + lookupCache.Store(ckey, ti.(*rtype)) + return ti } // The structLookupCache caches StructOf lookups. @@ -1903,7 +1912,7 @@ func isValidFieldName(fieldName string) bool { // This limitation may be lifted in a future version. func StructOf(fields []StructField) Type { var ( - hash = uint32(0) + hash = uint32(12) size uintptr typalign int8 comparable = true @@ -1988,7 +1997,7 @@ func StructOf(fields []StructField) Type { } fset[name] = struct{}{} - repr = append(repr, (" " + ft.String())...) + repr = append(repr, (" " + *ft.string)...) if f.tag != nil { repr = append(repr, (" " + strconv.Quote(*f.tag))...) } @@ -2172,7 +2181,9 @@ func StructOf(fields []StructField) Type { typ.uncommonType = nil typ.ptrToThis = nil - return addToCache(&typ.rtype) + // Canonicalize before storing in structLookupCache + ti := toType(&typ.rtype) + return addToCache(ti.(*rtype)) } func runtimeStructField(field StructField) structField { @@ -2400,8 +2411,10 @@ func ArrayOf(count int, elem Type) Type { } } - ti, _ := lookupCache.LoadOrStore(ckey, &array.rtype) - return ti.(Type) + // Canonicalize before storing in lookupCache + ti := toType(&array.rtype) + lookupCache.Store(ckey, ti.(*rtype)) + return ti } func appendVarint(x []byte, v uintptr) []byte { diff --git a/libgo/go/runtime/crash_test.go b/libgo/go/runtime/crash_test.go index 7a099be..602630d 100644 --- a/libgo/go/runtime/crash_test.go +++ b/libgo/go/runtime/crash_test.go @@ -150,6 +150,9 @@ var ( func checkStaleRuntime(t *testing.T) { staleRuntimeOnce.Do(func() { + if runtime.Compiler == "gccgo" { + return + } // 'go run' uses the installed copy of runtime.a, which may be out of date. out, err := testenv.CleanCmdEnv(exec.Command(testenv.GoToolPath(t), "list", "-gcflags=all="+os.Getenv("GO_GCFLAGS"), "-f", "{{.Stale}}", "runtime")).CombinedOutput() if err != nil { diff --git a/libgo/go/runtime/error.go b/libgo/go/runtime/error.go index 34b7d37..1a038cf 100644 --- a/libgo/go/runtime/error.go +++ b/libgo/go/runtime/error.go @@ -139,14 +139,12 @@ func typestring(x interface{}) string { } // printany prints an argument passed to panic. +// If panic is called with a value that has a String or Error method, +// it has already been converted into a string by preprintpanics. func printany(i interface{}) { switch v := i.(type) { case nil: print("nil") - case stringer: - print(v.String()) - case error: - print(v.Error()) case bool: print(v) case int: diff --git a/libgo/go/runtime/hash32.go b/libgo/go/runtime/hash32.go index 22daec5..3449127 100644 --- a/libgo/go/runtime/hash32.go +++ b/libgo/go/runtime/hash32.go @@ -6,7 +6,7 @@ // xxhash: https://code.google.com/p/xxhash/ // cityhash: https://code.google.com/p/cityhash/ -// +build 386 arm armbe m68k mips mipsle ppc s390 sh shbe sparc +// +build 386 arm armbe m68k mips mipsle nios2 ppc s390 sh shbe sparc package runtime diff --git a/libgo/go/runtime/lfstack_32bit.go b/libgo/go/runtime/lfstack_32bit.go index bbc421a..1288c1a 100644 --- a/libgo/go/runtime/lfstack_32bit.go +++ b/libgo/go/runtime/lfstack_32bit.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build 386 arm nacl armbe m68k mips mipsle mips64p32 mips64p32le ppc s390 sh shbe sparc +// +build 386 arm nacl armbe m68k mips mipsle mips64p32 mips64p32le nios2 ppc s390 sh shbe sparc package runtime diff --git a/libgo/go/runtime/malloc.go b/libgo/go/runtime/malloc.go index c27aa48..c8d5284 100644 --- a/libgo/go/runtime/malloc.go +++ b/libgo/go/runtime/malloc.go @@ -296,8 +296,8 @@ func mallocinit() { // allocation at 0x40 << 32 because when using 4k pages with 3-level // translation buffers, the user address space is limited to 39 bits // On darwin/arm64, the address space is even smaller. - // On AIX, mmap adresses range start at 0x07000000_00000000 for 64 bits - // processes. + // On AIX, mmap adresses range starts at 0x0700000000000000 for 64-bit + // processes. The new address space allocator starts at 0x0A00000000000000. arenaSize := round(_MaxMem, _PageSize) pSize = bitmapSize + spansSize + arenaSize + _PageSize for i := 0; i <= 0x7f; i++ { @@ -307,13 +307,16 @@ func mallocinit() { case GOARCH == "arm64": p = uintptr(i)<<40 | uintptrMask&(0x0040<<32) case GOOS == "aix": - i = 1 - p = uintptr(i)<<32 | uintptrMask&(0x70<<52) + if i == 0 { + p = uintptrMask&(1<<42) | uintptrMask&(0xa0<<52) + } else { + p = uintptr(i)<<42 | uintptrMask&(0x70<<52) + } default: p = uintptr(i)<<40 | uintptrMask&(0x00c0<<32) } p = uintptr(sysReserve(unsafe.Pointer(p), pSize, &reserved)) - if p != 0 || GOOS == "aix" { // Useless to loop on AIX, as i is forced to 1 + if p != 0 { break } } diff --git a/libgo/go/runtime/panic.go b/libgo/go/runtime/panic.go index fbdb17e..6b490b7 100644 --- a/libgo/go/runtime/panic.go +++ b/libgo/go/runtime/panic.go @@ -384,7 +384,6 @@ func Goexit() { // Call all Error and String methods before freezing the world. // Used when crashing with panicking. -// This must match types handled by printany. func preprintpanics(p *_panic) { defer func() { if recover() != nil { @@ -410,8 +409,6 @@ func printpanics(p *_panic) { print("\t") } print("panic: ") - // Because of preprintpanics, p.arg cannot be an error or - // stringer, so this won't call into user code. printany(p.arg) if p.recovered { print(" [recovered]") diff --git a/libgo/go/runtime/proc.go b/libgo/go/runtime/proc.go index 20fa0ad..a6746c9 100644 --- a/libgo/go/runtime/proc.go +++ b/libgo/go/runtime/proc.go @@ -423,6 +423,12 @@ func releaseSudog(s *sudog) { // funcPC returns the entry PC of the function f. // It assumes that f is a func value. Otherwise the behavior is undefined. +// CAREFUL: In programs with plugins, funcPC can return different values +// for the same function (because there are actually multiple copies of +// the same function in the address space). To be safe, don't use the +// results of this function in any == expression. It is only safe to +// use the result as an address at which to start executing code. +// // For gccgo note that this differs from the gc implementation; the gc // implementation adds sys.PtrSize to the address of the interface // value, but GCC's alias analysis decides that that can not be a diff --git a/libgo/go/runtime/stack.go b/libgo/go/runtime/stack.go deleted file mode 100644 index fd99e4d..0000000 --- a/libgo/go/runtime/stack.go +++ /dev/null @@ -1,1229 +0,0 @@ -// Copyright 2013 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 ignore - -package runtime - -import ( - "runtime/internal/atomic" - "runtime/internal/sys" - "unsafe" -) - -/* -Stack layout parameters. -Included both by runtime (compiled via 6c) and linkers (compiled via gcc). - -The per-goroutine g->stackguard is set to point StackGuard bytes -above the bottom of the stack. Each function compares its stack -pointer against g->stackguard to check for overflow. To cut one -instruction from the check sequence for functions with tiny frames, -the stack is allowed to protrude StackSmall bytes below the stack -guard. Functions with large frames don't bother with the check and -always call morestack. The sequences are (for amd64, others are -similar): - - guard = g->stackguard - frame = function's stack frame size - argsize = size of function arguments (call + return) - - stack frame size <= StackSmall: - CMPQ guard, SP - JHI 3(PC) - MOVQ m->morearg, $(argsize << 32) - CALL morestack(SB) - - stack frame size > StackSmall but < StackBig - LEAQ (frame-StackSmall)(SP), R0 - CMPQ guard, R0 - JHI 3(PC) - MOVQ m->morearg, $(argsize << 32) - CALL morestack(SB) - - stack frame size >= StackBig: - MOVQ m->morearg, $((argsize << 32) | frame) - CALL morestack(SB) - -The bottom StackGuard - StackSmall bytes are important: there has -to be enough room to execute functions that refuse to check for -stack overflow, either because they need to be adjacent to the -actual caller's frame (deferproc) or because they handle the imminent -stack overflow (morestack). - -For example, deferproc might call malloc, which does one of the -above checks (without allocating a full frame), which might trigger -a call to morestack. This sequence needs to fit in the bottom -section of the stack. On amd64, morestack's frame is 40 bytes, and -deferproc's frame is 56 bytes. That fits well within the -StackGuard - StackSmall bytes at the bottom. -The linkers explore all possible call traces involving non-splitting -functions to make sure that this limit cannot be violated. -*/ - -const ( - // StackSystem is a number of additional bytes to add - // to each stack below the usual guard area for OS-specific - // purposes like signal handling. Used on Windows, Plan 9, - // and Darwin/ARM because they do not use a separate stack. - _StackSystem = sys.GoosWindows*512*sys.PtrSize + sys.GoosPlan9*512 + sys.GoosDarwin*sys.GoarchArm*1024 - - // The minimum size of stack used by Go code - _StackMin = 2048 - - // The minimum stack size to allocate. - // The hackery here rounds FixedStack0 up to a power of 2. - _FixedStack0 = _StackMin + _StackSystem - _FixedStack1 = _FixedStack0 - 1 - _FixedStack2 = _FixedStack1 | (_FixedStack1 >> 1) - _FixedStack3 = _FixedStack2 | (_FixedStack2 >> 2) - _FixedStack4 = _FixedStack3 | (_FixedStack3 >> 4) - _FixedStack5 = _FixedStack4 | (_FixedStack4 >> 8) - _FixedStack6 = _FixedStack5 | (_FixedStack5 >> 16) - _FixedStack = _FixedStack6 + 1 - - // Functions that need frames bigger than this use an extra - // instruction to do the stack split check, to avoid overflow - // in case SP - framesize wraps below zero. - // This value can be no bigger than the size of the unmapped - // space at zero. - _StackBig = 4096 - - // The stack guard is a pointer this many bytes above the - // bottom of the stack. - _StackGuard = 880*sys.StackGuardMultiplier + _StackSystem - - // After a stack split check the SP is allowed to be this - // many bytes below the stack guard. This saves an instruction - // in the checking sequence for tiny frames. - _StackSmall = 128 - - // The maximum number of bytes that a chain of NOSPLIT - // functions can use. - _StackLimit = _StackGuard - _StackSystem - _StackSmall -) - -// Goroutine preemption request. -// Stored into g->stackguard0 to cause split stack check failure. -// Must be greater than any real sp. -// 0xfffffade in hex. -const ( - _StackPreempt = uintptrMask & -1314 - _StackFork = uintptrMask & -1234 -) - -const ( - // stackDebug == 0: no logging - // == 1: logging of per-stack operations - // == 2: logging of per-frame operations - // == 3: logging of per-word updates - // == 4: logging of per-word reads - stackDebug = 0 - stackFromSystem = 0 // allocate stacks from system memory instead of the heap - stackFaultOnFree = 0 // old stacks are mapped noaccess to detect use after free - stackPoisonCopy = 0 // fill stack that should not be accessed with garbage, to detect bad dereferences during copy - - stackCache = 1 - - // check the BP links during traceback. - debugCheckBP = false -) - -const ( - uintptrMask = 1<<(8*sys.PtrSize) - 1 - - // Goroutine preemption request. - // Stored into g->stackguard0 to cause split stack check failure. - // Must be greater than any real sp. - // 0xfffffade in hex. - stackPreempt = uintptrMask & -1314 - - // Thread is forking. - // Stored into g->stackguard0 to cause split stack check failure. - // Must be greater than any real sp. - stackFork = uintptrMask & -1234 -) - -// Global pool of spans that have free stacks. -// Stacks are assigned an order according to size. -// order = log_2(size/FixedStack) -// There is a free list for each order. -// TODO: one lock per order? -var stackpool [_NumStackOrders]mSpanList -var stackpoolmu mutex - -// Global pool of large stack spans. -var stackLarge struct { - lock mutex - free [_MHeapMap_Bits]mSpanList // free lists by log_2(s.npages) -} - -func stackinit() { - if _StackCacheSize&_PageMask != 0 { - throw("cache size must be a multiple of page size") - } - for i := range stackpool { - stackpool[i].init() - } - for i := range stackLarge.free { - stackLarge.free[i].init() - } -} - -// stacklog2 returns ⌊log_2(n)⌋. -func stacklog2(n uintptr) int { - log2 := 0 - for n > 1 { - n >>= 1 - log2++ - } - return log2 -} - -// Allocates a stack from the free pool. Must be called with -// stackpoolmu held. -func stackpoolalloc(order uint8) gclinkptr { - list := &stackpool[order] - s := list.first - if s == nil { - // no free stacks. Allocate another span worth. - s = mheap_.allocStack(_StackCacheSize >> _PageShift) - if s == nil { - throw("out of memory") - } - if s.allocCount != 0 { - throw("bad allocCount") - } - if s.stackfreelist.ptr() != nil { - throw("bad stackfreelist") - } - for i := uintptr(0); i < _StackCacheSize; i += _FixedStack << order { - x := gclinkptr(s.base() + i) - x.ptr().next = s.stackfreelist - s.stackfreelist = x - } - list.insert(s) - } - x := s.stackfreelist - if x.ptr() == nil { - throw("span has no free stacks") - } - s.stackfreelist = x.ptr().next - s.allocCount++ - if s.stackfreelist.ptr() == nil { - // all stacks in s are allocated. - list.remove(s) - } - return x -} - -// Adds stack x to the free pool. Must be called with stackpoolmu held. -func stackpoolfree(x gclinkptr, order uint8) { - s := mheap_.lookup(unsafe.Pointer(x)) - if s.state != _MSpanStack { - throw("freeing stack not in a stack span") - } - if s.stackfreelist.ptr() == nil { - // s will now have a free stack - stackpool[order].insert(s) - } - x.ptr().next = s.stackfreelist - s.stackfreelist = x - s.allocCount-- - if gcphase == _GCoff && s.allocCount == 0 { - // Span is completely free. Return it to the heap - // immediately if we're sweeping. - // - // If GC is active, we delay the free until the end of - // GC to avoid the following type of situation: - // - // 1) GC starts, scans a SudoG but does not yet mark the SudoG.elem pointer - // 2) The stack that pointer points to is copied - // 3) The old stack is freed - // 4) The containing span is marked free - // 5) GC attempts to mark the SudoG.elem pointer. The - // marking fails because the pointer looks like a - // pointer into a free span. - // - // By not freeing, we prevent step #4 until GC is done. - stackpool[order].remove(s) - s.stackfreelist = 0 - mheap_.freeStack(s) - } -} - -// stackcacherefill/stackcacherelease implement a global pool of stack segments. -// The pool is required to prevent unlimited growth of per-thread caches. -// -//go:systemstack -func stackcacherefill(c *mcache, order uint8) { - if stackDebug >= 1 { - print("stackcacherefill order=", order, "\n") - } - - // Grab some stacks from the global cache. - // Grab half of the allowed capacity (to prevent thrashing). - var list gclinkptr - var size uintptr - lock(&stackpoolmu) - for size < _StackCacheSize/2 { - x := stackpoolalloc(order) - x.ptr().next = list - list = x - size += _FixedStack << order - } - unlock(&stackpoolmu) - c.stackcache[order].list = list - c.stackcache[order].size = size -} - -//go:systemstack -func stackcacherelease(c *mcache, order uint8) { - if stackDebug >= 1 { - print("stackcacherelease order=", order, "\n") - } - x := c.stackcache[order].list - size := c.stackcache[order].size - lock(&stackpoolmu) - for size > _StackCacheSize/2 { - y := x.ptr().next - stackpoolfree(x, order) - x = y - size -= _FixedStack << order - } - unlock(&stackpoolmu) - c.stackcache[order].list = x - c.stackcache[order].size = size -} - -//go:systemstack -func stackcache_clear(c *mcache) { - if stackDebug >= 1 { - print("stackcache clear\n") - } - lock(&stackpoolmu) - for order := uint8(0); order < _NumStackOrders; order++ { - x := c.stackcache[order].list - for x.ptr() != nil { - y := x.ptr().next - stackpoolfree(x, order) - x = y - } - c.stackcache[order].list = 0 - c.stackcache[order].size = 0 - } - unlock(&stackpoolmu) -} - -// stackalloc allocates an n byte stack. -// -// stackalloc must run on the system stack because it uses per-P -// resources and must not split the stack. -// -//go:systemstack -func stackalloc(n uint32) (stack, []stkbar) { - // Stackalloc must be called on scheduler stack, so that we - // never try to grow the stack during the code that stackalloc runs. - // Doing so would cause a deadlock (issue 1547). - thisg := getg() - if thisg != thisg.m.g0 { - throw("stackalloc not on scheduler stack") - } - if n&(n-1) != 0 { - throw("stack size not a power of 2") - } - if stackDebug >= 1 { - print("stackalloc ", n, "\n") - } - - // Compute the size of stack barrier array. - maxstkbar := gcMaxStackBarriers(int(n)) - nstkbar := unsafe.Sizeof(stkbar{}) * uintptr(maxstkbar) - var stkbarSlice slice - - if debug.efence != 0 || stackFromSystem != 0 { - v := sysAlloc(round(uintptr(n), _PageSize), &memstats.stacks_sys) - if v == nil { - throw("out of memory (stackalloc)") - } - top := uintptr(n) - nstkbar - if maxstkbar != 0 { - stkbarSlice = slice{add(v, top), 0, maxstkbar} - } - return stack{uintptr(v), uintptr(v) + top}, *(*[]stkbar)(unsafe.Pointer(&stkbarSlice)) - } - - // Small stacks are allocated with a fixed-size free-list allocator. - // If we need a stack of a bigger size, we fall back on allocating - // a dedicated span. - var v unsafe.Pointer - if stackCache != 0 && n < _FixedStack<<_NumStackOrders && n < _StackCacheSize { - order := uint8(0) - n2 := n - for n2 > _FixedStack { - order++ - n2 >>= 1 - } - var x gclinkptr - c := thisg.m.mcache - if c == nil || thisg.m.preemptoff != "" || thisg.m.helpgc != 0 { - // c == nil can happen in the guts of exitsyscall or - // procresize. Just get a stack from the global pool. - // Also don't touch stackcache during gc - // as it's flushed concurrently. - lock(&stackpoolmu) - x = stackpoolalloc(order) - unlock(&stackpoolmu) - } else { - x = c.stackcache[order].list - if x.ptr() == nil { - stackcacherefill(c, order) - x = c.stackcache[order].list - } - c.stackcache[order].list = x.ptr().next - c.stackcache[order].size -= uintptr(n) - } - v = unsafe.Pointer(x) - } else { - var s *mspan - npage := uintptr(n) >> _PageShift - log2npage := stacklog2(npage) - - // Try to get a stack from the large stack cache. - lock(&stackLarge.lock) - if !stackLarge.free[log2npage].isEmpty() { - s = stackLarge.free[log2npage].first - stackLarge.free[log2npage].remove(s) - } - unlock(&stackLarge.lock) - - if s == nil { - // Allocate a new stack from the heap. - s = mheap_.allocStack(npage) - if s == nil { - throw("out of memory") - } - } - v = unsafe.Pointer(s.base()) - } - - if raceenabled { - racemalloc(v, uintptr(n)) - } - if msanenabled { - msanmalloc(v, uintptr(n)) - } - if stackDebug >= 1 { - print(" allocated ", v, "\n") - } - top := uintptr(n) - nstkbar - if maxstkbar != 0 { - stkbarSlice = slice{add(v, top), 0, maxstkbar} - } - return stack{uintptr(v), uintptr(v) + top}, *(*[]stkbar)(unsafe.Pointer(&stkbarSlice)) -} - -// stackfree frees an n byte stack allocation at stk. -// -// stackfree must run on the system stack because it uses per-P -// resources and must not split the stack. -// -//go:systemstack -func stackfree(stk stack, n uintptr) { - gp := getg() - v := unsafe.Pointer(stk.lo) - if n&(n-1) != 0 { - throw("stack not a power of 2") - } - if stk.lo+n < stk.hi { - throw("bad stack size") - } - if stackDebug >= 1 { - println("stackfree", v, n) - memclrNoHeapPointers(v, n) // for testing, clobber stack data - } - if debug.efence != 0 || stackFromSystem != 0 { - if debug.efence != 0 || stackFaultOnFree != 0 { - sysFault(v, n) - } else { - sysFree(v, n, &memstats.stacks_sys) - } - return - } - if msanenabled { - msanfree(v, n) - } - if stackCache != 0 && n < _FixedStack<<_NumStackOrders && n < _StackCacheSize { - order := uint8(0) - n2 := n - for n2 > _FixedStack { - order++ - n2 >>= 1 - } - x := gclinkptr(v) - c := gp.m.mcache - if c == nil || gp.m.preemptoff != "" || gp.m.helpgc != 0 { - lock(&stackpoolmu) - stackpoolfree(x, order) - unlock(&stackpoolmu) - } else { - if c.stackcache[order].size >= _StackCacheSize { - stackcacherelease(c, order) - } - x.ptr().next = c.stackcache[order].list - c.stackcache[order].list = x - c.stackcache[order].size += n - } - } else { - s := mheap_.lookup(v) - if s.state != _MSpanStack { - println(hex(s.base()), v) - throw("bad span state") - } - if gcphase == _GCoff { - // Free the stack immediately if we're - // sweeping. - mheap_.freeStack(s) - } else { - // If the GC is running, we can't return a - // stack span to the heap because it could be - // reused as a heap span, and this state - // change would race with GC. Add it to the - // large stack cache instead. - log2npage := stacklog2(s.npages) - lock(&stackLarge.lock) - stackLarge.free[log2npage].insert(s) - unlock(&stackLarge.lock) - } - } -} - -var maxstacksize uintptr = 1 << 20 // enough until runtime.main sets it for real - -var ptrnames = []string{ - 0: "scalar", - 1: "ptr", -} - -// Stack frame layout -// -// (x86) -// +------------------+ -// | args from caller | -// +------------------+ <- frame->argp -// | return address | -// +------------------+ -// | caller's BP (*) | (*) if framepointer_enabled && varp < sp -// +------------------+ <- frame->varp -// | locals | -// +------------------+ -// | args to callee | -// +------------------+ <- frame->sp -// -// (arm) -// +------------------+ -// | args from caller | -// +------------------+ <- frame->argp -// | caller's retaddr | -// +------------------+ <- frame->varp -// | locals | -// +------------------+ -// | args to callee | -// +------------------+ -// | return address | -// +------------------+ <- frame->sp - -type adjustinfo struct { - old stack - delta uintptr // ptr distance from old to new stack (newbase - oldbase) - cache pcvalueCache - - // sghi is the highest sudog.elem on the stack. - sghi uintptr -} - -// Adjustpointer checks whether *vpp is in the old stack described by adjinfo. -// If so, it rewrites *vpp to point into the new stack. -func adjustpointer(adjinfo *adjustinfo, vpp unsafe.Pointer) { - pp := (*uintptr)(vpp) - p := *pp - if stackDebug >= 4 { - print(" ", pp, ":", hex(p), "\n") - } - if adjinfo.old.lo <= p && p < adjinfo.old.hi { - *pp = p + adjinfo.delta - if stackDebug >= 3 { - print(" adjust ptr ", pp, ":", hex(p), " -> ", hex(*pp), "\n") - } - } -} - -// Information from the compiler about the layout of stack frames. -type bitvector struct { - n int32 // # of bits - bytedata *uint8 -} - -type gobitvector struct { - n uintptr - bytedata []uint8 -} - -func gobv(bv bitvector) gobitvector { - return gobitvector{ - uintptr(bv.n), - (*[1 << 30]byte)(unsafe.Pointer(bv.bytedata))[:(bv.n+7)/8], - } -} - -func ptrbit(bv *gobitvector, i uintptr) uint8 { - return (bv.bytedata[i/8] >> (i % 8)) & 1 -} - -// bv describes the memory starting at address scanp. -// Adjust any pointers contained therein. -func adjustpointers(scanp unsafe.Pointer, cbv *bitvector, adjinfo *adjustinfo, f *_func) { - bv := gobv(*cbv) - minp := adjinfo.old.lo - maxp := adjinfo.old.hi - delta := adjinfo.delta - num := bv.n - // If this frame might contain channel receive slots, use CAS - // to adjust pointers. If the slot hasn't been received into - // yet, it may contain stack pointers and a concurrent send - // could race with adjusting those pointers. (The sent value - // itself can never contain stack pointers.) - useCAS := uintptr(scanp) < adjinfo.sghi - for i := uintptr(0); i < num; i++ { - if stackDebug >= 4 { - print(" ", add(scanp, i*sys.PtrSize), ":", ptrnames[ptrbit(&bv, i)], ":", hex(*(*uintptr)(add(scanp, i*sys.PtrSize))), " # ", i, " ", bv.bytedata[i/8], "\n") - } - if ptrbit(&bv, i) == 1 { - pp := (*uintptr)(add(scanp, i*sys.PtrSize)) - retry: - p := *pp - if f != nil && 0 < p && p < minLegalPointer && debug.invalidptr != 0 { - // Looks like a junk value in a pointer slot. - // Live analysis wrong? - getg().m.traceback = 2 - print("runtime: bad pointer in frame ", funcname(f), " at ", pp, ": ", hex(p), "\n") - throw("invalid pointer found on stack") - } - if minp <= p && p < maxp { - if stackDebug >= 3 { - print("adjust ptr ", hex(p), " ", funcname(f), "\n") - } - if useCAS { - ppu := (*unsafe.Pointer)(unsafe.Pointer(pp)) - if !atomic.Casp1(ppu, unsafe.Pointer(p), unsafe.Pointer(p+delta)) { - goto retry - } - } else { - *pp = p + delta - } - } - } - } -} - -// Note: the argument/return area is adjusted by the callee. -func adjustframe(frame *stkframe, arg unsafe.Pointer) bool { - adjinfo := (*adjustinfo)(arg) - targetpc := frame.continpc - if targetpc == 0 { - // Frame is dead. - return true - } - f := frame.fn - if stackDebug >= 2 { - print(" adjusting ", funcname(f), " frame=[", hex(frame.sp), ",", hex(frame.fp), "] pc=", hex(frame.pc), " continpc=", hex(frame.continpc), "\n") - } - if f.entry == systemstack_switchPC { - // A special routine at the bottom of stack of a goroutine that does an systemstack call. - // We will allow it to be copied even though we don't - // have full GC info for it (because it is written in asm). - return true - } - if targetpc != f.entry { - targetpc-- - } - pcdata := pcdatavalue(f, _PCDATA_StackMapIndex, targetpc, &adjinfo.cache) - if pcdata == -1 { - pcdata = 0 // in prologue - } - - // Adjust local variables if stack frame has been allocated. - size := frame.varp - frame.sp - var minsize uintptr - switch sys.ArchFamily { - case sys.ARM64: - minsize = sys.SpAlign - default: - minsize = sys.MinFrameSize - } - if size > minsize { - var bv bitvector - stackmap := (*stackmap)(funcdata(f, _FUNCDATA_LocalsPointerMaps)) - if stackmap == nil || stackmap.n <= 0 { - print("runtime: frame ", funcname(f), " untyped locals ", hex(frame.varp-size), "+", hex(size), "\n") - throw("missing stackmap") - } - // Locals bitmap information, scan just the pointers in locals. - if pcdata < 0 || pcdata >= stackmap.n { - // don't know where we are - print("runtime: pcdata is ", pcdata, " and ", stackmap.n, " locals stack map entries for ", funcname(f), " (targetpc=", targetpc, ")\n") - throw("bad symbol table") - } - bv = stackmapdata(stackmap, pcdata) - size = uintptr(bv.n) * sys.PtrSize - if stackDebug >= 3 { - print(" locals ", pcdata, "/", stackmap.n, " ", size/sys.PtrSize, " words ", bv.bytedata, "\n") - } - adjustpointers(unsafe.Pointer(frame.varp-size), &bv, adjinfo, f) - } - - // Adjust saved base pointer if there is one. - if sys.ArchFamily == sys.AMD64 && frame.argp-frame.varp == 2*sys.RegSize { - if !framepointer_enabled { - print("runtime: found space for saved base pointer, but no framepointer experiment\n") - print("argp=", hex(frame.argp), " varp=", hex(frame.varp), "\n") - throw("bad frame layout") - } - if stackDebug >= 3 { - print(" saved bp\n") - } - if debugCheckBP { - // Frame pointers should always point to the next higher frame on - // the Go stack (or be nil, for the top frame on the stack). - bp := *(*uintptr)(unsafe.Pointer(frame.varp)) - if bp != 0 && (bp < adjinfo.old.lo || bp >= adjinfo.old.hi) { - println("runtime: found invalid frame pointer") - print("bp=", hex(bp), " min=", hex(adjinfo.old.lo), " max=", hex(adjinfo.old.hi), "\n") - throw("bad frame pointer") - } - } - adjustpointer(adjinfo, unsafe.Pointer(frame.varp)) - } - - // Adjust arguments. - if frame.arglen > 0 { - var bv bitvector - if frame.argmap != nil { - bv = *frame.argmap - } else { - stackmap := (*stackmap)(funcdata(f, _FUNCDATA_ArgsPointerMaps)) - if stackmap == nil || stackmap.n <= 0 { - print("runtime: frame ", funcname(f), " untyped args ", frame.argp, "+", frame.arglen, "\n") - throw("missing stackmap") - } - if pcdata < 0 || pcdata >= stackmap.n { - // don't know where we are - print("runtime: pcdata is ", pcdata, " and ", stackmap.n, " args stack map entries for ", funcname(f), " (targetpc=", targetpc, ")\n") - throw("bad symbol table") - } - bv = stackmapdata(stackmap, pcdata) - } - if stackDebug >= 3 { - print(" args\n") - } - adjustpointers(unsafe.Pointer(frame.argp), &bv, adjinfo, nil) - } - return true -} - -func adjustctxt(gp *g, adjinfo *adjustinfo) { - adjustpointer(adjinfo, unsafe.Pointer(&gp.sched.ctxt)) - if !framepointer_enabled { - return - } - if debugCheckBP { - bp := gp.sched.bp - if bp != 0 && (bp < adjinfo.old.lo || bp >= adjinfo.old.hi) { - println("runtime: found invalid top frame pointer") - print("bp=", hex(bp), " min=", hex(adjinfo.old.lo), " max=", hex(adjinfo.old.hi), "\n") - throw("bad top frame pointer") - } - } - adjustpointer(adjinfo, unsafe.Pointer(&gp.sched.bp)) -} - -func adjustdefers(gp *g, adjinfo *adjustinfo) { - // Adjust defer argument blocks the same way we adjust active stack frames. - tracebackdefers(gp, adjustframe, noescape(unsafe.Pointer(adjinfo))) - - // Adjust pointers in the Defer structs. - // Defer structs themselves are never on the stack. - for d := gp._defer; d != nil; d = d.link { - adjustpointer(adjinfo, unsafe.Pointer(&d.fn)) - adjustpointer(adjinfo, unsafe.Pointer(&d.sp)) - adjustpointer(adjinfo, unsafe.Pointer(&d._panic)) - } -} - -func adjustpanics(gp *g, adjinfo *adjustinfo) { - // Panics are on stack and already adjusted. - // Update pointer to head of list in G. - adjustpointer(adjinfo, unsafe.Pointer(&gp._panic)) -} - -func adjustsudogs(gp *g, adjinfo *adjustinfo) { - // the data elements pointed to by a SudoG structure - // might be in the stack. - for s := gp.waiting; s != nil; s = s.waitlink { - adjustpointer(adjinfo, unsafe.Pointer(&s.elem)) - adjustpointer(adjinfo, unsafe.Pointer(&s.selectdone)) - } -} - -func adjuststkbar(gp *g, adjinfo *adjustinfo) { - for i := int(gp.stkbarPos); i < len(gp.stkbar); i++ { - adjustpointer(adjinfo, unsafe.Pointer(&gp.stkbar[i].savedLRPtr)) - } -} - -func fillstack(stk stack, b byte) { - for p := stk.lo; p < stk.hi; p++ { - *(*byte)(unsafe.Pointer(p)) = b - } -} - -func findsghi(gp *g, stk stack) uintptr { - var sghi uintptr - for sg := gp.waiting; sg != nil; sg = sg.waitlink { - p := uintptr(sg.elem) + uintptr(sg.c.elemsize) - if stk.lo <= p && p < stk.hi && p > sghi { - sghi = p - } - p = uintptr(unsafe.Pointer(sg.selectdone)) + unsafe.Sizeof(sg.selectdone) - if stk.lo <= p && p < stk.hi && p > sghi { - sghi = p - } - } - return sghi -} - -// syncadjustsudogs adjusts gp's sudogs and copies the part of gp's -// stack they refer to while synchronizing with concurrent channel -// operations. It returns the number of bytes of stack copied. -func syncadjustsudogs(gp *g, used uintptr, adjinfo *adjustinfo) uintptr { - if gp.waiting == nil { - return 0 - } - - // Lock channels to prevent concurrent send/receive. - // It's important that we *only* do this for async - // copystack; otherwise, gp may be in the middle of - // putting itself on wait queues and this would - // self-deadlock. - var lastc *hchan - for sg := gp.waiting; sg != nil; sg = sg.waitlink { - if sg.c != lastc { - lock(&sg.c.lock) - } - lastc = sg.c - } - - // Adjust sudogs. - adjustsudogs(gp, adjinfo) - - // Copy the part of the stack the sudogs point in to - // while holding the lock to prevent races on - // send/receive slots. - var sgsize uintptr - if adjinfo.sghi != 0 { - oldBot := adjinfo.old.hi - used - newBot := oldBot + adjinfo.delta - sgsize = adjinfo.sghi - oldBot - memmove(unsafe.Pointer(newBot), unsafe.Pointer(oldBot), sgsize) - } - - // Unlock channels. - lastc = nil - for sg := gp.waiting; sg != nil; sg = sg.waitlink { - if sg.c != lastc { - unlock(&sg.c.lock) - } - lastc = sg.c - } - - return sgsize -} - -// Copies gp's stack to a new stack of a different size. -// Caller must have changed gp status to Gcopystack. -// -// If sync is true, this is a self-triggered stack growth and, in -// particular, no other G may be writing to gp's stack (e.g., via a -// channel operation). If sync is false, copystack protects against -// concurrent channel operations. -func copystack(gp *g, newsize uintptr, sync bool) { - if gp.syscallsp != 0 { - throw("stack growth not allowed in system call") - } - old := gp.stack - if old.lo == 0 { - throw("nil stackbase") - } - used := old.hi - gp.sched.sp - - // allocate new stack - new, newstkbar := stackalloc(uint32(newsize)) - if stackPoisonCopy != 0 { - fillstack(new, 0xfd) - } - if stackDebug >= 1 { - print("copystack gp=", gp, " [", hex(old.lo), " ", hex(old.hi-used), " ", hex(old.hi), "]/", gp.stackAlloc, " -> [", hex(new.lo), " ", hex(new.hi-used), " ", hex(new.hi), "]/", newsize, "\n") - } - - // Compute adjustment. - var adjinfo adjustinfo - adjinfo.old = old - adjinfo.delta = new.hi - old.hi - - // Adjust sudogs, synchronizing with channel ops if necessary. - ncopy := used - if sync { - adjustsudogs(gp, &adjinfo) - } else { - // sudogs can point in to the stack. During concurrent - // shrinking, these areas may be written to. Find the - // highest such pointer so we can handle everything - // there and below carefully. (This shouldn't be far - // from the bottom of the stack, so there's little - // cost in handling everything below it carefully.) - adjinfo.sghi = findsghi(gp, old) - - // Synchronize with channel ops and copy the part of - // the stack they may interact with. - ncopy -= syncadjustsudogs(gp, used, &adjinfo) - } - - // Copy the stack (or the rest of it) to the new location - memmove(unsafe.Pointer(new.hi-ncopy), unsafe.Pointer(old.hi-ncopy), ncopy) - - // Disallow sigprof scans of this stack and block if there's - // one in progress. - gcLockStackBarriers(gp) - - // Adjust remaining structures that have pointers into stacks. - // We have to do most of these before we traceback the new - // stack because gentraceback uses them. - adjustctxt(gp, &adjinfo) - adjustdefers(gp, &adjinfo) - adjustpanics(gp, &adjinfo) - adjuststkbar(gp, &adjinfo) - if adjinfo.sghi != 0 { - adjinfo.sghi += adjinfo.delta - } - - // copy old stack barriers to new stack barrier array - newstkbar = newstkbar[:len(gp.stkbar)] - copy(newstkbar, gp.stkbar) - - // Swap out old stack for new one - gp.stack = new - gp.stackguard0 = new.lo + _StackGuard // NOTE: might clobber a preempt request - gp.sched.sp = new.hi - used - oldsize := gp.stackAlloc - gp.stackAlloc = newsize - gp.stkbar = newstkbar - gp.stktopsp += adjinfo.delta - - // Adjust pointers in the new stack. - gentraceback(^uintptr(0), ^uintptr(0), 0, gp, 0, nil, 0x7fffffff, adjustframe, noescape(unsafe.Pointer(&adjinfo)), 0) - - gcUnlockStackBarriers(gp) - - // free old stack - if stackPoisonCopy != 0 { - fillstack(old, 0xfc) - } - stackfree(old, oldsize) -} - -// round x up to a power of 2. -func round2(x int32) int32 { - s := uint(0) - for 1<<s < x { - s++ - } - return 1 << s -} - -// Called from runtime·morestack when more stack is needed. -// Allocate larger stack and relocate to new stack. -// Stack growth is multiplicative, for constant amortized cost. -// -// g->atomicstatus will be Grunning or Gscanrunning upon entry. -// If the GC is trying to stop this g then it will set preemptscan to true. -// -// ctxt is the value of the context register on morestack. newstack -// will write it to g.sched.ctxt. -func newstack(ctxt unsafe.Pointer) { - thisg := getg() - // TODO: double check all gp. shouldn't be getg(). - if thisg.m.morebuf.g.ptr().stackguard0 == stackFork { - throw("stack growth after fork") - } - if thisg.m.morebuf.g.ptr() != thisg.m.curg { - print("runtime: newstack called from g=", hex(thisg.m.morebuf.g), "\n"+"\tm=", thisg.m, " m->curg=", thisg.m.curg, " m->g0=", thisg.m.g0, " m->gsignal=", thisg.m.gsignal, "\n") - morebuf := thisg.m.morebuf - traceback(morebuf.pc, morebuf.sp, morebuf.lr, morebuf.g.ptr()) - throw("runtime: wrong goroutine in newstack") - } - - gp := thisg.m.curg - // Write ctxt to gp.sched. We do this here instead of in - // morestack so it has the necessary write barrier. - gp.sched.ctxt = ctxt - - if thisg.m.curg.throwsplit { - // Update syscallsp, syscallpc in case traceback uses them. - morebuf := thisg.m.morebuf - gp.syscallsp = morebuf.sp - gp.syscallpc = morebuf.pc - print("runtime: newstack sp=", hex(gp.sched.sp), " stack=[", hex(gp.stack.lo), ", ", hex(gp.stack.hi), "]\n", - "\tmorebuf={pc:", hex(morebuf.pc), " sp:", hex(morebuf.sp), " lr:", hex(morebuf.lr), "}\n", - "\tsched={pc:", hex(gp.sched.pc), " sp:", hex(gp.sched.sp), " lr:", hex(gp.sched.lr), " ctxt:", gp.sched.ctxt, "}\n") - - traceback(morebuf.pc, morebuf.sp, morebuf.lr, gp) - throw("runtime: stack split at bad time") - } - - morebuf := thisg.m.morebuf - thisg.m.morebuf.pc = 0 - thisg.m.morebuf.lr = 0 - thisg.m.morebuf.sp = 0 - thisg.m.morebuf.g = 0 - - // NOTE: stackguard0 may change underfoot, if another thread - // is about to try to preempt gp. Read it just once and use that same - // value now and below. - preempt := atomic.Loaduintptr(&gp.stackguard0) == stackPreempt - - // Be conservative about where we preempt. - // We are interested in preempting user Go code, not runtime code. - // If we're holding locks, mallocing, or preemption is disabled, don't - // preempt. - // This check is very early in newstack so that even the status change - // from Grunning to Gwaiting and back doesn't happen in this case. - // That status change by itself can be viewed as a small preemption, - // because the GC might change Gwaiting to Gscanwaiting, and then - // this goroutine has to wait for the GC to finish before continuing. - // If the GC is in some way dependent on this goroutine (for example, - // it needs a lock held by the goroutine), that small preemption turns - // into a real deadlock. - if preempt { - if thisg.m.locks != 0 || thisg.m.mallocing != 0 || thisg.m.preemptoff != "" || thisg.m.p.ptr().status != _Prunning { - // Let the goroutine keep running for now. - // gp->preempt is set, so it will be preempted next time. - gp.stackguard0 = gp.stack.lo + _StackGuard - gogo(&gp.sched) // never return - } - } - - if gp.stack.lo == 0 { - throw("missing stack in newstack") - } - sp := gp.sched.sp - if sys.ArchFamily == sys.AMD64 || sys.ArchFamily == sys.I386 { - // The call to morestack cost a word. - sp -= sys.PtrSize - } - if stackDebug >= 1 || sp < gp.stack.lo { - print("runtime: newstack sp=", hex(sp), " stack=[", hex(gp.stack.lo), ", ", hex(gp.stack.hi), "]\n", - "\tmorebuf={pc:", hex(morebuf.pc), " sp:", hex(morebuf.sp), " lr:", hex(morebuf.lr), "}\n", - "\tsched={pc:", hex(gp.sched.pc), " sp:", hex(gp.sched.sp), " lr:", hex(gp.sched.lr), " ctxt:", gp.sched.ctxt, "}\n") - } - if sp < gp.stack.lo { - print("runtime: gp=", gp, ", gp->status=", hex(readgstatus(gp)), "\n ") - print("runtime: split stack overflow: ", hex(sp), " < ", hex(gp.stack.lo), "\n") - throw("runtime: split stack overflow") - } - - if preempt { - if gp == thisg.m.g0 { - throw("runtime: preempt g0") - } - if thisg.m.p == 0 && thisg.m.locks == 0 { - throw("runtime: g is running but p is not") - } - // Synchronize with scang. - casgstatus(gp, _Grunning, _Gwaiting) - if gp.preemptscan { - for !castogscanstatus(gp, _Gwaiting, _Gscanwaiting) { - // Likely to be racing with the GC as - // it sees a _Gwaiting and does the - // stack scan. If so, gcworkdone will - // be set and gcphasework will simply - // return. - } - if !gp.gcscandone { - // gcw is safe because we're on the - // system stack. - gcw := &gp.m.p.ptr().gcw - scanstack(gp, gcw) - if gcBlackenPromptly { - gcw.dispose() - } - gp.gcscandone = true - } - gp.preemptscan = false - gp.preempt = false - casfrom_Gscanstatus(gp, _Gscanwaiting, _Gwaiting) - // This clears gcscanvalid. - casgstatus(gp, _Gwaiting, _Grunning) - gp.stackguard0 = gp.stack.lo + _StackGuard - gogo(&gp.sched) // never return - } - - // Act like goroutine called runtime.Gosched. - casgstatus(gp, _Gwaiting, _Grunning) - gopreempt_m(gp) // never return - } - - // Allocate a bigger segment and move the stack. - oldsize := int(gp.stackAlloc) - newsize := oldsize * 2 - if uintptr(newsize) > maxstacksize { - print("runtime: goroutine stack exceeds ", maxstacksize, "-byte limit\n") - throw("stack overflow") - } - - // The goroutine must be executing in order to call newstack, - // so it must be Grunning (or Gscanrunning). - casgstatus(gp, _Grunning, _Gcopystack) - - // The concurrent GC will not scan the stack while we are doing the copy since - // the gp is in a Gcopystack status. - copystack(gp, uintptr(newsize), true) - if stackDebug >= 1 { - print("stack grow done\n") - } - casgstatus(gp, _Gcopystack, _Grunning) - gogo(&gp.sched) -} - -//go:nosplit -func nilfunc() { - *(*uint8)(nil) = 0 -} - -// adjust Gobuf as if it executed a call to fn -// and then did an immediate gosave. -func gostartcallfn(gobuf *gobuf, fv *funcval) { - var fn unsafe.Pointer - if fv != nil { - fn = unsafe.Pointer(fv.fn) - } else { - fn = unsafe.Pointer(funcPC(nilfunc)) - } - gostartcall(gobuf, fn, unsafe.Pointer(fv)) -} - -// Maybe shrink the stack being used by gp. -// Called at garbage collection time. -// gp must be stopped, but the world need not be. -func shrinkstack(gp *g) { - gstatus := readgstatus(gp) - if gstatus&^_Gscan == _Gdead { - if gp.stack.lo != 0 { - // Free whole stack - it will get reallocated - // if G is used again. - stackfree(gp.stack, gp.stackAlloc) - gp.stack.lo = 0 - gp.stack.hi = 0 - gp.stkbar = nil - gp.stkbarPos = 0 - } - return - } - if gp.stack.lo == 0 { - throw("missing stack in shrinkstack") - } - if gstatus&_Gscan == 0 { - throw("bad status in shrinkstack") - } - - if debug.gcshrinkstackoff > 0 { - return - } - if gp.startpc == gcBgMarkWorkerPC { - // We're not allowed to shrink the gcBgMarkWorker - // stack (see gcBgMarkWorker for explanation). - return - } - - oldsize := gp.stackAlloc - newsize := oldsize / 2 - // Don't shrink the allocation below the minimum-sized stack - // allocation. - if newsize < _FixedStack { - return - } - // Compute how much of the stack is currently in use and only - // shrink the stack if gp is using less than a quarter of its - // current stack. The currently used stack includes everything - // down to the SP plus the stack guard space that ensures - // there's room for nosplit functions. - avail := gp.stack.hi - gp.stack.lo - if used := gp.stack.hi - gp.sched.sp + _StackLimit; used >= avail/4 { - return - } - - // We can't copy the stack if we're in a syscall. - // The syscall might have pointers into the stack. - if gp.syscallsp != 0 { - return - } - if sys.GoosWindows != 0 && gp.m != nil && gp.m.libcallsp != 0 { - return - } - - if stackDebug > 0 { - print("shrinking stack ", oldsize, "->", newsize, "\n") - } - - copystack(gp, newsize, false) -} - -// freeStackSpans frees unused stack spans at the end of GC. -func freeStackSpans() { - lock(&stackpoolmu) - - // Scan stack pools for empty stack spans. - for order := range stackpool { - list := &stackpool[order] - for s := list.first; s != nil; { - next := s.next - if s.allocCount == 0 { - list.remove(s) - s.stackfreelist = 0 - mheap_.freeStack(s) - } - s = next - } - } - - unlock(&stackpoolmu) - - // Free large stack spans. - lock(&stackLarge.lock) - for i := range stackLarge.free { - for s := stackLarge.free[i].first; s != nil; { - next := s.next - stackLarge.free[i].remove(s) - mheap_.freeStack(s) - s = next - } - } - unlock(&stackLarge.lock) -} - -//go:nosplit -func morestackc() { - systemstack(func() { - throw("attempt to execute C code on Go stack") - }) -} diff --git a/libgo/go/runtime/symtab.go b/libgo/go/runtime/symtab.go index 3d15fc8..12dc672 100644 --- a/libgo/go/runtime/symtab.go +++ b/libgo/go/runtime/symtab.go @@ -115,6 +115,35 @@ type Func struct { entry uintptr } +// A FuncID identifies particular functions that need to be treated +// specially by the runtime. +// Note that in some situations involving plugins, there may be multiple +// copies of a particular special runtime function. +// Note: this list must match the list in cmd/internal/objabi/funcid.go. +type funcID uint32 + +const ( + funcID_normal funcID = iota // not a special function + funcID_goexit + funcID_jmpdefer + funcID_mcall + funcID_morestack + funcID_mstart + funcID_rt0_go + funcID_asmcgocall + funcID_sigpanic + funcID_runfinq + funcID_bgsweep + funcID_forcegchelper + funcID_timerproc + funcID_gcBgMarkWorker + funcID_systemstack_switch + funcID_systemstack + funcID_cgocallback_gofunc + funcID_gogo + funcID_externalthreadhandler +) + // FuncForPC returns a *Func describing the function that contains the // given program counter address, or else nil. // diff --git a/libgo/go/runtime/unaligned2.go b/libgo/go/runtime/unaligned2.go index 891459e..9f52e8d 100644 --- a/libgo/go/runtime/unaligned2.go +++ b/libgo/go/runtime/unaligned2.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build arm mips mipsle mips64 mips64le armbe m68k sparc alpha ia64 mips64p32 mips64p32le sh shbe sparc64 +// +build alpha arm armbe ia64 m68k mips mipsle mips64 mips64le mips64p32 mips64p32le nios2 sh shbe sparc sparc64 package runtime diff --git a/libgo/go/syscall/endian_little.go b/libgo/go/syscall/endian_little.go index 4a73121..a5d32ae 100644 --- a/libgo/go/syscall/endian_little.go +++ b/libgo/go/syscall/endian_little.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // -// +build 386 amd64 amd64p32 arm arm64 ppc64le mips64le mipsle alpha ia64 mips64p32le sh riscv64 +// +build 386 alpha amd64 amd64p32 arm arm64 ia64 mips64le mipsle mips64p32le nios2 ppc64le riscv64 sh package syscall diff --git a/libgo/go/syscall/libcall_linux_ustat.go b/libgo/go/syscall/libcall_linux_ustat.go index 3aff344..f515fce 100644 --- a/libgo/go/syscall/libcall_linux_ustat.go +++ b/libgo/go/syscall/libcall_linux_ustat.go @@ -4,7 +4,7 @@ // GNU/Linux library ustat call. // This is not supported on some kernels, such as arm64. -// +build !arm64,!riscv64 +// +build !arm64,!nios2,!riscv64 package syscall |