From 6d002c12eb70e70cda003ccd07b5dbcc217f0675 Mon Sep 17 00:00:00 2001 From: ian Date: Thu, 31 May 2018 21:42:53 +0000 Subject: [PATCH] libgo: update to Go 1.10.2 release Reviewed-on: https://go-review.googlesource.com/115196 git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@261041 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/go/gofrontend/MERGE | 2 +- libgo/MERGE | 2 +- libgo/VERSION | 2 +- libgo/check-packages.txt | 1 + libgo/go/archive/zip/reader.go | 8 +- libgo/go/archive/zip/reader_test.go | 2 +- libgo/go/cmd/go/go_test.go | 85 +++++++++++++ libgo/go/cmd/go/internal/get/vcs.go | 34 +++++- libgo/go/cmd/go/internal/get/vcs_test.go | 43 +++++++ libgo/go/cmd/go/internal/test/test.go | 8 ++ libgo/go/cmd/go/internal/vet/vet.go | 4 +- libgo/go/cmd/go/internal/work/buildid.go | 23 ++-- libgo/go/cmd/go/internal/work/exec.go | 18 ++- libgo/go/cmd/go/internal/work/security.go | 48 +++++++- libgo/go/cmd/go/internal/work/security_test.go | 4 - libgo/go/cmd/internal/objabi/funcid.go | 34 ++++++ libgo/go/crypto/x509/name_constraints_test.go | 135 ++++++++++++++++++++- libgo/go/crypto/x509/verify.go | 88 +++++++++++--- libgo/go/crypto/x509/x509.go | 20 ++- libgo/go/encoding/json/decode.go | 24 +++- libgo/go/encoding/json/decode_test.go | 70 ++++++++--- libgo/go/go/internal/srcimporter/srcimporter.go | 28 +---- .../go/go/internal/srcimporter/srcimporter_test.go | 32 +++++ .../srcimporter/testdata/issue23092/issue23092.go | 5 + .../srcimporter/testdata/issue24392/issue24392.go | 5 + libgo/go/internal/singleflight/singleflight.go | 22 +++- libgo/go/net/http/pprof/pprof.go | 52 ++++---- libgo/go/net/http/pprof/pprof_test.go | 69 +++++++++++ libgo/go/net/lookup.go | 32 +++-- libgo/go/net/lookup_test.go | 25 ++++ libgo/go/net/tcpsock_unix_test.go | 1 + libgo/go/runtime/error.go | 6 +- libgo/go/runtime/panic.go | 3 - libgo/go/runtime/proc.go | 6 + libgo/go/runtime/symtab.go | 29 +++++ libgo/misc/cgo/testplugin/src/issue24351/main.go | 21 ++++ libgo/misc/cgo/testplugin/src/issue24351/plugin.go | 14 +++ libgo/misc/cgo/testplugin/test.bash | 5 + libgo/misc/cgo/testshared/shared_test.go | 1 + 39 files changed, 853 insertions(+), 158 deletions(-) create mode 100644 libgo/go/cmd/internal/objabi/funcid.go create mode 100644 libgo/go/go/internal/srcimporter/testdata/issue23092/issue23092.go create mode 100644 libgo/go/go/internal/srcimporter/testdata/issue24392/issue24392.go create mode 100644 libgo/go/net/http/pprof/pprof_test.go create mode 100644 libgo/misc/cgo/testplugin/src/issue24351/main.go create mode 100644 libgo/misc/cgo/testplugin/src/issue24351/plugin.go diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 8500b37108b..618004c6d8d 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -9731580e76c065b76e3a103356bb8920da05a685 +79eca4fd642724d89e9bec8f79889451f6632a46 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/libgo/MERGE b/libgo/MERGE index b715f06010b..6f31fab2265 100644 --- a/libgo/MERGE +++ b/libgo/MERGE @@ -1,4 +1,4 @@ -bf86aec25972f3a100c3aa58a6abcbcc35bdea49 +71bdbf431b79dff61944f22c25c7e085ccfc25d5 The first line of this file holds the git revision number of the last merge done from the master library sources. diff --git a/libgo/VERSION b/libgo/VERSION index 95ec39eb99b..98736c7cde0 100644 --- a/libgo/VERSION +++ b/libgo/VERSION @@ -1 +1 @@ -go1.10 +go1.10.2 diff --git a/libgo/check-packages.txt b/libgo/check-packages.txt index 8ede851c343..82a08c6554d 100644 --- a/libgo/check-packages.txt +++ b/libgo/check-packages.txt @@ -122,6 +122,7 @@ net/http/httptest net/http/httptrace net/http/httputil net/http/internal +net/http/pprof net/internal/socktest net/mail net/rpc diff --git a/libgo/go/archive/zip/reader.go b/libgo/go/archive/zip/reader.go index 1563e74dfce..2444106ba69 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 0d9040f7674..1e58b26b6e9 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/go/go_test.go b/libgo/go/cmd/go/go_test.go index 294541800af..f6d6f4250eb 100644 --- a/libgo/go/cmd/go/go_test.go +++ b/libgo/go/cmd/go/go_test.go @@ -3265,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) @@ -5099,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) @@ -5792,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() @@ -5949,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/get/vcs.go b/libgo/go/cmd/go/internal/get/vcs.go index 26693b13a93..0b2a04e04f8 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 e29338aec19..a6f8642026c 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/test/test.go b/libgo/go/cmd/go/internal/test/test.go index dbf6eea8a92..72415ccd095 100644 --- a/libgo/go/cmd/go/internal/test/test.go +++ b/libgo/go/cmd/go/internal/test/test.go @@ -673,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) } diff --git a/libgo/go/cmd/go/internal/vet/vet.go b/libgo/go/cmd/go/internal/vet/vet.go index 07eed894586..a737ebd669f 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/work/buildid.go b/libgo/go/cmd/go/internal/work/buildid.go index 6150bbb81a6..733938e0ade 100644 --- a/libgo/go/cmd/go/internal/work/buildid.go +++ b/libgo/go/cmd/go/internal/work/buildid.go @@ -461,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 @@ -546,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. @@ -574,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 } } @@ -584,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 837ffb5e0fd..5994dbc702f 100644 --- a/libgo/go/cmd/go/internal/work/exec.go +++ b/libgo/go/cmd/go/internal/work/exec.go @@ -956,11 +956,19 @@ 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 - for len(pkgs) > 0 && strings.HasPrefix(pkgs[0], "--") { - pcflags = append(pcflags, pkgs[0]) - pkgs = pkgs[1:] + 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) { @@ -1107,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) } diff --git a/libgo/go/cmd/go/internal/work/security.go b/libgo/go/cmd/go/internal/work/security.go index 54fd6b97820..5c67aa945ef 100644 --- a/libgo/go/cmd/go/internal/work/security.go +++ b/libgo/go/cmd/go/internal/work/security.go @@ -46,12 +46,19 @@ 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`), @@ -62,27 +69,42 @@ var validCompilerFlags = []*regexp.Regexp{ 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(`-?-stdlib=([^@\-].*)`), + re(`-w`), re(`-x([^@\-].*)`), } var validCompilerFlagsWithNextArg = []string{ + "-arch", "-D", "-I", - "-isystem", "-framework", + "-isysroot", + "-isystem", + "--sysroot", + "-target", "-x", } @@ -90,43 +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,--(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,-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_/].*\.(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 { diff --git a/libgo/go/cmd/go/internal/work/security_test.go b/libgo/go/cmd/go/internal/work/security_test.go index 976501b8108..bd898c9de6c 100644 --- a/libgo/go/cmd/go/internal/work/security_test.go +++ b/libgo/go/cmd/go/internal/work/security_test.go @@ -140,9 +140,6 @@ var goodLinkerFlags = [][]string{ var badLinkerFlags = [][]string{ {"-DFOO"}, {"-Dfoo=bar"}, - {"-O"}, - {"-O2"}, - {"-Osmall"}, {"-W"}, {"-Wall"}, {"-fobjc-arc"}, @@ -155,7 +152,6 @@ var badLinkerFlags = [][]string{ {"-fno-stack-xxx"}, {"-mstack-overflow"}, {"-mno-stack-overflow"}, - {"-mmacosx-version"}, {"-mnop-fun-dllimport"}, {"-std=c99"}, {"-xc"}, diff --git a/libgo/go/cmd/internal/objabi/funcid.go b/libgo/go/cmd/internal/objabi/funcid.go new file mode 100644 index 00000000000..55f1328ba84 --- /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/crypto/x509/name_constraints_test.go b/libgo/go/crypto/x509/name_constraints_test.go index 10cc3483576..bad488f89fb 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/verify.go b/libgo/go/crypto/x509/verify.go index 9477e85b951..0ea214bd2e0 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 86d9e82aca4..ee08dd9797e 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 536f25dc7c5..730fb920ebd 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 34b7ec6d97a..fa1531f3761 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/internal/srcimporter/srcimporter.go b/libgo/go/go/internal/srcimporter/srcimporter.go index b0dc8abfc2b..9ed7e5e4dca 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 356e71d1287..dd4d56ad17d 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 00000000000..608698bfc51 --- /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 00000000000..8ad52218fc3 --- /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 1e9960d575d..b2d82e26c29 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/net/http/pprof/pprof.go b/libgo/go/net/http/pprof/pprof.go index 21992d62da2..77e0bcdf4f6 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 00000000000..47dd35b9b07 --- /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/