From: Ian Lance Taylor Date: Thu, 8 Feb 2018 15:30:22 +0000 (+0000) Subject: libgo: update to Go1.10rc2 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=9adab5dd169afd191efd1dcbf50dae0f726a0a42;p=gcc.git libgo: update to Go1.10rc2 Reviewed-on: https://go-review.googlesource.com/92736 From-SVN: r257493 --- diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index f1a43770690..bdaea8180f4 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -cdc28627b7abfd73f5d552813db8eb4293b823b0 +2aa95f1499cf931ef8e95c7958463829276a0f2c 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 4a3c64ed88f..26b8869db90 100644 --- a/libgo/MERGE +++ b/libgo/MERGE @@ -1,4 +1,4 @@ -5348aed83e39bd1d450d92d7f627e994c2db6ebf +20e228f2fdb44350c858de941dff4aea9f3127b8 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 5859fbe0b7a..dc3cdca6363 100644 --- a/libgo/VERSION +++ b/libgo/VERSION @@ -1 +1 @@ -go1.10rc1 +go1.10rc2 diff --git a/libgo/go/cmd/cgo/doc.go b/libgo/go/cmd/cgo/doc.go index 8e4cd88b37c..c16b63a313b 100644 --- a/libgo/go/cmd/cgo/doc.go +++ b/libgo/go/cmd/cgo/doc.go @@ -45,8 +45,8 @@ For example: // #include import "C" -Alternatively, CPPFLAGS and LDFLAGS may be obtained via the pkg-config -tool using a '#cgo pkg-config:' directive followed by the package names. +Alternatively, CPPFLAGS and LDFLAGS may be obtained via the pkg-config tool +using a '#cgo pkg-config:' directive followed by the package names. For example: // #cgo pkg-config: png cairo @@ -55,11 +55,21 @@ For example: The default pkg-config tool may be changed by setting the PKG_CONFIG environment variable. +For security reasons, only a limited set of flags are allowed, notably -D, -I, and -l. +To allow additional flags, set CGO_CFLAGS_ALLOW to a regular expression +matching the new flags. To disallow flags that would otherwise be allowed, +set CGO_CFLAGS_DISALLOW to a regular expression matching arguments +that must be disallowed. In both cases the regular expression must match +a full argument: to allow -mfoo=bar, use CGO_CFLAGS_ALLOW='-mfoo.*', +not just CGO_CFLAGS_ALLOW='-mfoo'. Similarly named variables control +the allowed CPPFLAGS, CXXFLAGS, FFLAGS, and LDFLAGS. + When building, the CGO_CFLAGS, CGO_CPPFLAGS, CGO_CXXFLAGS, CGO_FFLAGS and CGO_LDFLAGS environment variables are added to the flags derived from these directives. Package-specific flags should be set using the directives, not the environment variables, so that builds work in -unmodified environments. +unmodified environments. Flags obtained from environment variables +are not subject to the security limitations described above. All the cgo CPPFLAGS and CFLAGS directives in a package are concatenated and used to compile C files in that package. All the CPPFLAGS and CXXFLAGS diff --git a/libgo/go/cmd/cgo/gcc.go b/libgo/go/cmd/cgo/gcc.go index fcf334ec44e..534fba17eb4 100644 --- a/libgo/go/cmd/cgo/gcc.go +++ b/libgo/go/cmd/cgo/gcc.go @@ -2345,12 +2345,6 @@ func (c *typeConv) FuncArg(dtype dwarf.Type, pos token.Pos) *Type { break } - // If we already know the typedef for t just use that. - // See issue 19832. - if def := typedef[t.Go.(*ast.Ident).Name]; def != nil { - break - } - t = c.Type(ptr, pos) if t == nil { return nil diff --git a/libgo/go/cmd/go/alldocs.go b/libgo/go/cmd/go/alldocs.go index 85b9d2584f2..5e1ac5aaf57 100644 --- a/libgo/go/cmd/go/alldocs.go +++ b/libgo/go/cmd/go/alldocs.go @@ -1227,17 +1227,26 @@ // CGO_CFLAGS // Flags that cgo will pass to the compiler when compiling // C code. -// CGO_CPPFLAGS -// Flags that cgo will pass to the compiler when compiling -// C or C++ code. -// CGO_CXXFLAGS -// Flags that cgo will pass to the compiler when compiling -// C++ code. -// CGO_FFLAGS -// Flags that cgo will pass to the compiler when compiling -// Fortran code. -// CGO_LDFLAGS -// Flags that cgo will pass to the compiler when linking. +// CGO_CFLAGS_ALLOW +// A regular expression specifying additional flags to allow +// to appear in #cgo CFLAGS source code directives. +// Does not apply to the CGO_CFLAGS environment variable. +// CGO_CFLAGS_DISALLOW +// A regular expression specifying flags that must be disallowed +// from appearing in #cgo CFLAGS source code directives. +// Does not apply to the CGO_CFLAGS environment variable. +// CGO_CPPFLAGS, CGO_CPPFLAGS_ALLOW, CGO_CPPFLAGS_DISALLOW +// Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW, +// but for the C preprocessor. +// CGO_CXXFLAGS, CGO_CXXFLAGS_ALLOW, CGO_CXXFLAGS_DISALLOW +// Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW, +// but for the C++ compiler. +// CGO_FFLAGS, CGO_FFLAGS_ALLOW, CGO_FFLAGS_DISALLOW +// Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW, +// but for the Fortran compiler. +// CGO_LDFLAGS, CGO_LDFLAGS_ALLOW, CGO_LDFLAGS_DISALLOW +// Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW, +// but for the linker. // CXX // The command to use to compile C++ code. // PKG_CONFIG diff --git a/libgo/go/cmd/go/go_test.go b/libgo/go/cmd/go/go_test.go index 41a37a575b6..c5a3d7b36bc 100644 --- a/libgo/go/cmd/go/go_test.go +++ b/libgo/go/cmd/go/go_test.go @@ -81,6 +81,13 @@ func init() { skipExternal = true canRun = false } + case "plan9": + switch runtime.GOARCH { + case "arm": + // many plan9/arm machines are too slow to run + // the full set of external tests. + skipExternal = true + } case "windows": exeSuffix = ".exe" } @@ -2815,7 +2822,7 @@ func TestCgoHandlesWlORIGIN(t *testing.T) { defer tg.cleanup() tg.parallel() tg.tempFile("src/origin/origin.go", `package origin - // #cgo !darwin LDFLAGS: -Wl,-rpath -Wl,$ORIGIN + // #cgo !darwin LDFLAGS: -Wl,-rpath,$ORIGIN // void f(void) {} import "C" func f() { C.f() }`) @@ -5421,6 +5428,30 @@ func TestTestCacheInputs(t *testing.T) { } } +func TestNoCache(t *testing.T) { + switch runtime.GOOS { + case "windows": + t.Skipf("no unwritable directories on %s", runtime.GOOS) + } + if os.Getuid() == 0 { + t.Skip("skipping test because running as root") + } + + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempFile("triv.go", `package main; func main() {}`) + tg.must(os.MkdirAll(tg.path("unwritable"), 0555)) + home := "HOME" + if runtime.GOOS == "plan9" { + home = "home" + } + tg.setenv(home, tg.path(filepath.Join("unwritable", "home"))) + tg.unsetenv("GOCACHE") + tg.run("build", "-o", tg.path("triv"), tg.path("triv.go")) + tg.grepStderr("disabling cache", "did not disable cache") +} + func TestTestVet(t *testing.T) { tooSlow(t) tg := testgo(t) @@ -5463,6 +5494,44 @@ func TestTestVet(t *testing.T) { tg.grepStdout(`ok\s+vetfail/p2`, "did not run vetfail/p2") } +func TestTestRebuild(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + + // golang.org/issue/23701. + // b_test imports b with augmented method from export_test.go. + // b_test also imports a, which imports b. + // Must not accidentally see un-augmented b propagate through a to b_test. + tg.tempFile("src/a/a.go", `package a + import "b" + type Type struct{} + func (*Type) M() b.T {return 0} + `) + tg.tempFile("src/b/b.go", `package b + type T int + type I interface {M() T} + `) + tg.tempFile("src/b/export_test.go", `package b + func (*T) Method() *T { return nil } + `) + tg.tempFile("src/b/b_test.go", `package b_test + import ( + "testing" + "a" + . "b" + ) + func TestBroken(t *testing.T) { + x := new(T) + x.Method() + _ = new(a.Type) + } + `) + + tg.setenv("GOPATH", tg.path(".")) + tg.run("test", "b") +} + func TestInstallDeps(t *testing.T) { tooSlow(t) tg := testgo(t) @@ -5712,3 +5781,177 @@ func TestCpuprofileTwice(t *testing.T) { tg.run("test", "-o="+bin, "-cpuprofile="+out, "x") tg.mustExist(out) } + +// Issue 23694. +func TestAtomicCoverpkgAll(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 _ "sync/atomic"; 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", "-covermode=atomic", "x") + if canRace { + tg.run("test", "-coverpkg=all", "-race", "x") + } +} + +func TestBadCommandLines(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + + tg.tempFile("src/x/x.go", "package x\n") + tg.setenv("GOPATH", tg.path(".")) + + tg.run("build", "x") + + tg.tempFile("src/x/@y.go", "package x\n") + tg.runFail("build", "x") + tg.grepStderr("invalid input file name \"@y.go\"", "did not reject @y.go") + tg.must(os.Remove(tg.path("src/x/@y.go"))) + + tg.tempFile("src/x/-y.go", "package x\n") + tg.runFail("build", "x") + tg.grepStderr("invalid input file name \"-y.go\"", "did not reject -y.go") + tg.must(os.Remove(tg.path("src/x/-y.go"))) + + if runtime.Compiler == "gccgo" { + tg.runFail("build", "-gccgoflags=all=@x", "x") + } else { + tg.runFail("build", "-gcflags=all=@x", "x") + } + tg.grepStderr("invalid command-line argument @x in command", "did not reject @x during exec") + + tg.tempFile("src/@x/x.go", "package x\n") + tg.setenv("GOPATH", tg.path(".")) + tg.runFail("build", "@x") + tg.grepStderr("invalid input directory name \"@x\"", "did not reject @x directory") + + tg.tempFile("src/@x/y/y.go", "package y\n") + tg.setenv("GOPATH", tg.path(".")) + tg.runFail("build", "@x/y") + tg.grepStderr("invalid import path \"@x/y\"", "did not reject @x/y import path") + + tg.tempFile("src/-x/x.go", "package x\n") + tg.setenv("GOPATH", tg.path(".")) + tg.runFail("build", "--", "-x") + tg.grepStderr("invalid input directory name \"-x\"", "did not reject -x directory") + + tg.tempFile("src/-x/y/y.go", "package y\n") + tg.setenv("GOPATH", tg.path(".")) + tg.runFail("build", "--", "-x/y") + tg.grepStderr("invalid import path \"-x/y\"", "did not reject -x/y import path") +} + +func TestBadCgoDirectives(t *testing.T) { + if !canCgo { + t.Skip("no cgo") + } + tg := testgo(t) + defer tg.cleanup() + + tg.tempFile("src/x/x.go", "package x\n") + tg.setenv("GOPATH", tg.path(".")) + + if runtime.Compiler == "gc" { + tg.tempFile("src/x/x.go", `package x + + //go:cgo_ldflag "-fplugin=foo.so" + + import "C" + `) + tg.runFail("build", "x") + tg.grepStderr("//go:cgo_ldflag .* only allowed in cgo-generated code", "did not reject //go:cgo_ldflag directive") + } + + tg.must(os.Remove(tg.path("src/x/x.go"))) + tg.runFail("build", "x") + tg.grepStderr("no Go files", "did not report missing source code") + tg.tempFile("src/x/_cgo_yy.go", `package x + + //go:cgo_ldflag "-fplugin=foo.so" + + import "C" + `) + tg.runFail("build", "x") + tg.grepStderr("no Go files", "did not report missing source code") // _* files are ignored... + + if runtime.Compiler == "gc" { + tg.runFail("build", tg.path("src/x/_cgo_yy.go")) // ... but if forced, the comment is rejected + // Actually, today there is a separate issue that _ files named + // on the command-line are ignored. Once that is fixed, + // we want to see the cgo_ldflag error. + tg.grepStderr("//go:cgo_ldflag only allowed in cgo-generated code|no Go files", "did not reject //go:cgo_ldflag directive") + } + + tg.must(os.Remove(tg.path("src/x/_cgo_yy.go"))) + + tg.tempFile("src/x/x.go", "package x\n") + tg.tempFile("src/x/y.go", `package x + // #cgo CFLAGS: -fplugin=foo.so + import "C" + `) + tg.runFail("build", "x") + tg.grepStderr("invalid flag in #cgo CFLAGS: -fplugin=foo.so", "did not reject -fplugin") + + tg.tempFile("src/x/y.go", `package x + // #cgo CFLAGS: -Ibar -fplugin=foo.so + import "C" + `) + tg.runFail("build", "x") + tg.grepStderr("invalid flag in #cgo CFLAGS: -fplugin=foo.so", "did not reject -fplugin") + + tg.tempFile("src/x/y.go", `package x + // #cgo pkg-config: -foo + import "C" + `) + tg.runFail("build", "x") + tg.grepStderr("invalid pkg-config package name: -foo", "did not reject pkg-config: -foo") + + tg.tempFile("src/x/y.go", `package x + // #cgo pkg-config: @foo + import "C" + `) + tg.runFail("build", "x") + tg.grepStderr("invalid pkg-config package name: @foo", "did not reject pkg-config: -foo") + + tg.tempFile("src/x/y.go", `package x + // #cgo CFLAGS: @foo + import "C" + `) + tg.runFail("build", "x") + tg.grepStderr("invalid flag in #cgo CFLAGS: @foo", "did not reject @foo flag") + + tg.tempFile("src/x/y.go", `package x + // #cgo CFLAGS: -D + import "C" + `) + tg.runFail("build", "x") + tg.grepStderr("invalid flag in #cgo CFLAGS: -D without argument", "did not reject trailing -I flag") + + // Note that -I @foo is allowed because we rewrite it into -I /path/to/src/@foo + // before the check is applied. There's no such rewrite for -D. + + tg.tempFile("src/x/y.go", `package x + // #cgo CFLAGS: -D @foo + import "C" + `) + tg.runFail("build", "x") + tg.grepStderr("invalid flag in #cgo CFLAGS: -D @foo", "did not reject -D @foo flag") + + tg.tempFile("src/x/y.go", `package x + // #cgo CFLAGS: -D@foo + import "C" + `) + tg.runFail("build", "x") + tg.grepStderr("invalid flag in #cgo CFLAGS: -D@foo", "did not reject -D@foo flag") + + tg.setenv("CGO_CFLAGS", "-D@foo") + tg.tempFile("src/x/y.go", `package x + import "C" + `) + tg.run("build", "-n", "x") + tg.grepStderr("-D@foo", "did not find -D@foo in commands") +} diff --git a/libgo/go/cmd/go/internal/cache/default.go b/libgo/go/cmd/go/internal/cache/default.go index 8285f787d4c..97283762258 100644 --- a/libgo/go/cmd/go/internal/cache/default.go +++ b/libgo/go/cmd/go/internal/cache/default.go @@ -5,7 +5,7 @@ package cache import ( - "cmd/go/internal/base" + "fmt" "io/ioutil" "os" "path/filepath" @@ -40,7 +40,8 @@ func initDefaultCache() { return } if err := os.MkdirAll(dir, 0777); err != nil { - base.Fatalf("initializing cache in $GOCACHE: %s", err) + fmt.Fprintf(os.Stderr, "go: disabling cache (%s) due to initialization failure: %s\n", dir, err) + return } if _, err := os.Stat(filepath.Join(dir, "README")); err != nil { // Best effort. @@ -49,7 +50,8 @@ func initDefaultCache() { c, err := Open(dir) if err != nil { - base.Fatalf("initializing cache in $GOCACHE: %s", err) + fmt.Fprintf(os.Stderr, "go: disabling cache (%s) due to initialization failure: %s\n", dir, err) + return } defaultCache = c } diff --git a/libgo/go/cmd/go/internal/envcmd/env.go b/libgo/go/cmd/go/internal/envcmd/env.go index fa19bebe218..603f7b5060c 100644 --- a/libgo/go/cmd/go/internal/envcmd/env.go +++ b/libgo/go/cmd/go/internal/envcmd/env.go @@ -113,7 +113,12 @@ func findEnv(env []cfg.EnvVar, name string) string { func ExtraEnvVars() []cfg.EnvVar { var b work.Builder b.Init() - cppflags, cflags, cxxflags, fflags, ldflags := b.CFlags(&load.Package{}) + cppflags, cflags, cxxflags, fflags, ldflags, err := b.CFlags(&load.Package{}) + if err != nil { + // Should not happen - b.CFlags was given an empty package. + fmt.Fprintf(os.Stderr, "go: invalid cflags: %v\n", err) + return nil + } cmd := b.GccCmd(".", "") return []cfg.EnvVar{ // Note: Update the switch in runEnv below when adding to this list. diff --git a/libgo/go/cmd/go/internal/help/helpdoc.go b/libgo/go/cmd/go/internal/help/helpdoc.go index 126e8663fb4..9a9fc4e9448 100644 --- a/libgo/go/cmd/go/internal/help/helpdoc.go +++ b/libgo/go/cmd/go/internal/help/helpdoc.go @@ -487,17 +487,26 @@ Environment variables for use with cgo: CGO_CFLAGS Flags that cgo will pass to the compiler when compiling C code. - CGO_CPPFLAGS - Flags that cgo will pass to the compiler when compiling - C or C++ code. - CGO_CXXFLAGS - Flags that cgo will pass to the compiler when compiling - C++ code. - CGO_FFLAGS - Flags that cgo will pass to the compiler when compiling - Fortran code. - CGO_LDFLAGS - Flags that cgo will pass to the compiler when linking. + CGO_CFLAGS_ALLOW + A regular expression specifying additional flags to allow + to appear in #cgo CFLAGS source code directives. + Does not apply to the CGO_CFLAGS environment variable. + CGO_CFLAGS_DISALLOW + A regular expression specifying flags that must be disallowed + from appearing in #cgo CFLAGS source code directives. + Does not apply to the CGO_CFLAGS environment variable. + CGO_CPPFLAGS, CGO_CPPFLAGS_ALLOW, CGO_CPPFLAGS_DISALLOW + Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW, + but for the C preprocessor. + CGO_CXXFLAGS, CGO_CXXFLAGS_ALLOW, CGO_CXXFLAGS_DISALLOW + Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW, + but for the C++ compiler. + CGO_FFLAGS, CGO_FFLAGS_ALLOW, CGO_FFLAGS_DISALLOW + Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW, + but for the Fortran compiler. + CGO_LDFLAGS, CGO_LDFLAGS_ALLOW, CGO_LDFLAGS_DISALLOW + Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW, + but for the linker. CXX The command to use to compile C++ code. PKG_CONFIG diff --git a/libgo/go/cmd/go/internal/load/pkg.go b/libgo/go/cmd/go/internal/load/pkg.go index 609a47db4bc..ac764b4d028 100644 --- a/libgo/go/cmd/go/internal/load/pkg.go +++ b/libgo/go/cmd/go/internal/load/pkg.go @@ -17,6 +17,7 @@ import ( "sort" "strings" "unicode" + "unicode/utf8" "cmd/go/internal/base" "cmd/go/internal/cfg" @@ -55,6 +56,8 @@ type PackagePublic struct { StaleReason string `json:",omitempty"` // why is Stale true? // Source files + // If you add to this list you MUST add to p.AllFiles (below) too. + // Otherwise file name security lists will not apply to any new additions. GoFiles []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles) CgoFiles []string `json:",omitempty"` // .go sources files that import "C" IgnoredGoFiles []string `json:",omitempty"` // .go sources ignored due to build constraints @@ -86,12 +89,38 @@ type PackagePublic struct { DepsErrors []*PackageError `json:",omitempty"` // errors loading dependencies // Test information + // If you add to this list you MUST add to p.AllFiles (below) too. + // Otherwise file name security lists will not apply to any new additions. TestGoFiles []string `json:",omitempty"` // _test.go files in package TestImports []string `json:",omitempty"` // imports from TestGoFiles XTestGoFiles []string `json:",omitempty"` // _test.go files outside package XTestImports []string `json:",omitempty"` // imports from XTestGoFiles } +// AllFiles returns the names of all the files considered for the package. +// This is used for sanity and security checks, so we include all files, +// even IgnoredGoFiles, because some subcommands consider them. +// The go/build package filtered others out (like foo_wrongGOARCH.s) +// and that's OK. +func (p *Package) AllFiles() []string { + return str.StringList( + p.GoFiles, + p.CgoFiles, + p.IgnoredGoFiles, + p.CFiles, + p.CXXFiles, + p.MFiles, + p.HFiles, + p.FFiles, + p.SFiles, + p.SwigFiles, + p.SwigCXXFiles, + p.SysoFiles, + p.TestGoFiles, + p.XTestGoFiles, + ) +} + type PackageInternal struct { // Unexported fields are not part of the public API. Build *build.Package @@ -420,6 +449,9 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo var err error if debugDeprecatedImportcfgDir != "" { bp, err = cfg.BuildContext.ImportDir(debugDeprecatedImportcfgDir, 0) + } else if DebugDeprecatedImportcfg.enabled { + bp = new(build.Package) + err = fmt.Errorf("unknown import path %q: not in import cfg", importPath) } else { buildMode := build.ImportComment if mode&UseVendor == 0 || path != origPath { @@ -518,6 +550,13 @@ func isDir(path string) bool { // x/vendor/path, vendor/path, or else stay path if none of those exist. // VendoredImportPath returns the expanded path or, if no expansion is found, the original. func VendoredImportPath(parent *Package, path string) (found string) { + if DebugDeprecatedImportcfg.enabled { + if d, i := DebugDeprecatedImportcfg.lookup(parent, path); d != "" { + return i + } + return path + } + if parent == nil || parent.Root == "" { return path } @@ -1010,22 +1049,8 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) { // To avoid problems on case-insensitive files, we reject any package // where two different input files have equal names under a case-insensitive // comparison. - f1, f2 := str.FoldDup(str.StringList( - p.GoFiles, - p.CgoFiles, - p.IgnoredGoFiles, - p.CFiles, - p.CXXFiles, - p.MFiles, - p.HFiles, - p.FFiles, - p.SFiles, - p.SysoFiles, - p.SwigFiles, - p.SwigCXXFiles, - p.TestGoFiles, - p.XTestGoFiles, - )) + inputs := p.AllFiles() + f1, f2 := str.FoldDup(inputs) if f1 != "" { p.Error = &PackageError{ ImportStack: stk.Copy(), @@ -1034,6 +1059,37 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) { return } + // If first letter of input file is ASCII, it must be alphanumeric. + // This avoids files turning into flags when invoking commands, + // and other problems we haven't thought of yet. + // Also, _cgo_ files must be generated by us, not supplied. + // They are allowed to have //go:cgo_ldflag directives. + // The directory scan ignores files beginning with _, + // so we shouldn't see any _cgo_ files anyway, but just be safe. + for _, file := range inputs { + if !SafeArg(file) || strings.HasPrefix(file, "_cgo_") { + p.Error = &PackageError{ + ImportStack: stk.Copy(), + Err: fmt.Sprintf("invalid input file name %q", file), + } + return + } + } + if name := pathpkg.Base(p.ImportPath); !SafeArg(name) { + p.Error = &PackageError{ + ImportStack: stk.Copy(), + Err: fmt.Sprintf("invalid input directory name %q", name), + } + return + } + if !SafeArg(p.ImportPath) { + p.Error = &PackageError{ + ImportStack: stk.Copy(), + Err: fmt.Sprintf("invalid import path %q", p.ImportPath), + } + return + } + // Build list of imported packages and full dependency list. imports := make([]*Package, 0, len(p.Imports)) for i, path := range importPaths { @@ -1160,6 +1216,22 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) { } } +// SafeArg reports whether arg is a "safe" command-line argument, +// meaning that when it appears in a command-line, it probably +// doesn't have some special meaning other than its own name. +// Obviously args beginning with - are not safe (they look like flags). +// Less obviously, args beginning with @ are not safe (they look like +// 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. +func SafeArg(name string) bool { + if name == "" { + return false + } + c := name[0] + return '0' <= c && c <= '9' || 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || c == '.' || c == '_' || c == '/' || c >= utf8.RuneSelf +} + // LinkerDeps returns the list of linker-induced dependencies for main package p. func LinkerDeps(p *Package) []string { // Everything links runtime. diff --git a/libgo/go/cmd/go/internal/test/test.go b/libgo/go/cmd/go/internal/test/test.go index e77e834cb23..97854707964 100644 --- a/libgo/go/cmd/go/internal/test/test.go +++ b/libgo/go/cmd/go/internal/test/test.go @@ -662,6 +662,15 @@ func runTest(cmd *base.Command, args []string) { haveMatch = true } } + + // Silently ignore attempts to run coverage on + // sync/atomic when using atomic coverage mode. + // Atomic coverage mode uses sync/atomic, so + // we can't also do coverage on it. + if testCoverMode == "atomic" && p.Standard && p.ImportPath == "sync/atomic" { + continue + } + if haveMatch { testCoverPkgs = append(testCoverPkgs, p) } @@ -894,7 +903,7 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin t.ImportXtest = true } - if ptest != p && localCover { + if ptest != p { // We have made modifications to the package p being tested // and are rebuilding p (as ptest). // Arrange to rebuild all packages q such that @@ -903,13 +912,6 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin // Strictly speaking, the rebuild is only necessary if the // modifications to p change its export metadata, but // determining that is a bit tricky, so we rebuild always. - // TODO(rsc): Once we get export metadata changes - // handled properly, look into the expense of dropping - // "&& localCover" above. - // - // This will cause extra compilation, so for now we only do it - // when testCover is set. The conditions are more general, though, - // and we may find that we need to do it always in the future. recompileForTest(pmain, p, ptest, pxtest) } diff --git a/libgo/go/cmd/go/internal/work/exec.go b/libgo/go/cmd/go/internal/work/exec.go index b5874982708..5527e90756d 100644 --- a/libgo/go/cmd/go/internal/work/exec.go +++ b/libgo/go/cmd/go/internal/work/exec.go @@ -197,7 +197,7 @@ func (b *Builder) buildActionID(a *Action) cache.ActionID { fmt.Fprintf(h, "omitdebug %v standard %v local %v prefix %q\n", p.Internal.OmitDebug, p.Standard, p.Internal.Local, p.Internal.LocalPrefix) if len(p.CgoFiles)+len(p.SwigFiles) > 0 { fmt.Fprintf(h, "cgo %q\n", b.toolID("cgo")) - cppflags, cflags, cxxflags, fflags, _ := b.CFlags(p) + cppflags, cflags, cxxflags, fflags, _, _ := b.CFlags(p) fmt.Fprintf(h, "CC=%q %q %q\n", b.ccExe(), cppflags, cflags) if len(p.CXXFiles)+len(p.SwigFiles) > 0 { fmt.Fprintf(h, "CXX=%q %q\n", b.cxxExe(), cxxflags) @@ -521,7 +521,14 @@ func (b *Builder) build(a *Action) (err error) { } // Prepare Go import config. + // We start it off with a comment so it can't be empty, so icfg.Bytes() below is never nil. + // It should never be empty anyway, but there have been bugs in the past that resulted + // in empty configs, which then unfortunately turn into "no config passed to compiler", + // and the compiler falls back to looking in pkg itself, which mostly works, + // except when it doesn't. var icfg bytes.Buffer + fmt.Fprintf(&icfg, "# import config\n") + for i, raw := range a.Package.Internal.RawImports { final := a.Package.Imports[i] if final != raw { @@ -938,28 +945,38 @@ 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 { + 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", "--", pkgs) if err != nil { b.showOutput(nil, p.Dir, b.PkgconfigCmd()+" --cflags "+strings.Join(pkgs, " "), string(out)) b.Print(err.Error() + "\n") - err = errPrintedOutput - return + return nil, nil, errPrintedOutput } if len(out) > 0 { cflags = splitPkgConfigOutput(out) + if err := checkCompilerFlags("CFLAGS", "pkg-config --cflags", cflags); err != nil { + 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", "--", pkgs) if err != nil { b.showOutput(nil, p.Dir, b.PkgconfigCmd()+" --libs "+strings.Join(pkgs, " "), string(out)) b.Print(err.Error() + "\n") - err = errPrintedOutput - return + return nil, nil, errPrintedOutput } if len(out) > 0 { ldflags = strings.Fields(string(out)) + if err := checkLinkerFlags("CFLAGS", "pkg-config --cflags", ldflags); err != nil { + return nil, nil, err + } } } + return } @@ -1464,6 +1481,17 @@ func (b *Builder) processOutput(out []byte) string { // It returns the command output and any errors that occurred. func (b *Builder) runOut(dir string, desc string, env []string, cmdargs ...interface{}) ([]byte, error) { cmdline := str.StringList(cmdargs...) + + for _, arg := range cmdline { + // GNU binutils commands, including gcc and gccgo, interpret an argument + // @foo anywhere in the command line (even following --) as meaning + // "read and insert arguments from the file named foo." + // Don't say anything that might be misinterpreted that way. + if strings.HasPrefix(arg, "@") { + return nil, fmt.Errorf("invalid command-line argument %s in command: %s", arg, joinUnambiguously(cmdline)) + } + } + if cfg.BuildN || cfg.BuildX { var envcmdline string for _, e := range env { @@ -1916,22 +1944,44 @@ func envList(key, def string) []string { } // CFlags returns the flags to use when invoking the C, C++ or Fortran compilers, or cgo. -func (b *Builder) CFlags(p *load.Package) (cppflags, cflags, cxxflags, fflags, ldflags []string) { +func (b *Builder) CFlags(p *load.Package) (cppflags, cflags, cxxflags, fflags, ldflags []string, err error) { defaults := "-g -O2" - cppflags = str.StringList(envList("CGO_CPPFLAGS", ""), p.CgoCPPFLAGS) - cflags = str.StringList(envList("CGO_CFLAGS", defaults), p.CgoCFLAGS) - cxxflags = str.StringList(envList("CGO_CXXFLAGS", defaults), p.CgoCXXFLAGS) - fflags = str.StringList(envList("CGO_FFLAGS", defaults), p.CgoFFLAGS) - ldflags = str.StringList(envList("CGO_LDFLAGS", defaults), p.CgoLDFLAGS) + if cppflags, err = buildFlags("CPPFLAGS", "", p.CgoCPPFLAGS, checkCompilerFlags); err != nil { + return + } + if cflags, err = buildFlags("CFLAGS", defaults, p.CgoCFLAGS, checkCompilerFlags); err != nil { + return + } + if cxxflags, err = buildFlags("CXXFLAGS", defaults, p.CgoCXXFLAGS, checkCompilerFlags); err != nil { + return + } + if fflags, err = buildFlags("FFLAGS", defaults, p.CgoFFLAGS, checkCompilerFlags); err != nil { + return + } + if ldflags, err = buildFlags("LDFLAGS", defaults, p.CgoLDFLAGS, checkLinkerFlags); err != nil { + return + } + return } +func buildFlags(name, defaults string, fromPackage []string, check func(string, string, []string) error) ([]string, error) { + if err := check(name, "#cgo "+name, fromPackage); err != nil { + return nil, err + } + return str.StringList(envList("CGO_"+name, defaults), fromPackage), nil +} + var cgoRe = regexp.MustCompile(`[/\\:]`) func (b *Builder) cgo(a *Action, cgoExe, objdir string, pcCFLAGS, pcLDFLAGS, cgofiles, gccfiles, gxxfiles, mfiles, ffiles []string) (outGo, outObj []string, err error) { p := a.Package - cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoFFLAGS, cgoLDFLAGS := b.CFlags(p) + cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoFFLAGS, cgoLDFLAGS, err := b.CFlags(p) + if err != nil { + return nil, nil, err + } + cgoCPPFLAGS = append(cgoCPPFLAGS, pcCFLAGS...) cgoLDFLAGS = append(cgoLDFLAGS, pcLDFLAGS...) // If we are compiling Objective-C code, then we need to link against libobjc @@ -1981,6 +2031,12 @@ func (b *Builder) cgo(a *Action, cgoExe, objdir string, pcCFLAGS, pcLDFLAGS, cgo } // Update $CGO_LDFLAGS with p.CgoLDFLAGS. + // These flags are recorded in the generated _cgo_gotypes.go file + // using //go:cgo_ldflag directives, the compiler records them in the + // object file for the package, and then the Go linker passes them + // along to the host linker. At this point in the code, cgoLDFLAGS + // consists of the original $CGO_LDFLAGS (unchecked) and all the + // flags put together from source code (checked). var cgoenv []string if len(cgoLDFLAGS) > 0 { flags := make([]string, len(cgoLDFLAGS)) @@ -2272,7 +2328,11 @@ func (b *Builder) swigIntSize(objdir string) (intsize string, err error) { // Run SWIG on one SWIG input file. func (b *Builder) swigOne(a *Action, p *load.Package, file, objdir string, pcCFLAGS []string, cxx bool, intgosize string) (outGo, outC string, err error) { - cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _, _ := b.CFlags(p) + cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _, _, err := b.CFlags(p) + if err != nil { + return "", "", err + } + var cflags []string if cxx { cflags = str.StringList(cgoCPPFLAGS, pcCFLAGS, cgoCXXFLAGS) diff --git a/libgo/go/cmd/go/internal/work/security.go b/libgo/go/cmd/go/internal/work/security.go new file mode 100644 index 00000000000..fee5beeb15f --- /dev/null +++ b/libgo/go/cmd/go/internal/work/security.go @@ -0,0 +1,160 @@ +// 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. + +// Checking of compiler and linker flags. +// We must avoid flags like -fplugin=, which can allow +// arbitrary code execution during the build. +// Do not make changes here without carefully +// considering the implications. +// (That's why the code is isolated in a file named security.go.) +// +// Note that -Wl,foo means split foo on commas and pass to +// the linker, so that -Wl,-foo,bar means pass -foo bar to +// the linker. Similarly -Wa,foo for the assembler and so on. +// If any of these are permitted, the wildcard portion must +// disallow commas. +// +// Note also that GNU binutils accept any argument @foo +// as meaning "read more flags from the file foo", so we must +// guard against any command-line argument beginning with @, +// even things like "-I @foo". +// We use load.SafeArg (which is even more conservative) +// to reject these. +// +// Even worse, gcc -I@foo (one arg) turns into cc1 -I @foo (two args), +// so although gcc doesn't expand the @foo, cc1 will. +// So out of paranoia, we reject @ at the beginning of every +// flag argument that might be split into its own argument. + +package work + +import ( + "cmd/go/internal/load" + "fmt" + "os" + "regexp" +) + +var re = regexp.MustCompile + +var validCompilerFlags = []*regexp.Regexp{ + re(`-D([A-Za-z_].*)`), + re(`-I([^@\-].*)`), + re(`-O`), + re(`-O([^@\-].*)`), + re(`-W`), + re(`-W([^@,]+)`), // -Wall but not -Wa,-foo. + re(`-f(no-)?objc-arc`), + re(`-f(no-)?omit-frame-pointer`), + re(`-f(no-)?(pic|PIC|pie|PIE)`), + re(`-f(no-)?split-stack`), + re(`-f(no-)?stack-(.+)`), + re(`-f(no-)?strict-aliasing`), + re(`-fsanitize=(.+)`), + re(`-g([^@\-].*)?`), + re(`-m(arch|cpu|fpu|tune)=([^@\-].*)`), + re(`-m(no-)?stack-(.+)`), + re(`-mmacosx-(.+)`), + re(`-mnop-fun-dllimport`), + re(`-pthread`), + re(`-std=([^@\-].*)`), + re(`-x([^@\-].*)`), +} + +var validCompilerFlagsWithNextArg = []string{ + "-D", + "-I", + "-framework", + "-x", +} + +var validLinkerFlags = []*regexp.Regexp{ + re(`-F([^@\-].*)`), + re(`-l([^@\-].*)`), + re(`-L([^@\-].*)`), + re(`-f(no-)?(pic|PIC|pie|PIE)`), + re(`-fsanitize=([^@\-].*)`), + re(`-g([^@\-].*)?`), + re(`-m(arch|cpu|fpu|tune)=([^@\-].*)`), + re(`-(pic|PIC|pie|PIE)`), + re(`-pthread`), + + // 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-)?warn-([^,]+)`), + + 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) +} + +var validLinkerFlagsWithNextArg = []string{ + "-F", + "-l", + "-L", + "-framework", +} + +func checkCompilerFlags(name, source string, list []string) error { + return checkFlags(name, source, list, validCompilerFlags, validCompilerFlagsWithNextArg) +} + +func checkLinkerFlags(name, source string, list []string) error { + return checkFlags(name, source, list, validLinkerFlags, validLinkerFlagsWithNextArg) +} + +func checkFlags(name, source string, list []string, valid []*regexp.Regexp, validNext []string) error { + // Let users override rules with $CGO_CFLAGS_ALLOW, $CGO_CFLAGS_DISALLOW, etc. + var ( + allow *regexp.Regexp + disallow *regexp.Regexp + ) + if env := os.Getenv("CGO_" + name + "_ALLOW"); env != "" { + r, err := regexp.Compile(env) + if err != nil { + return fmt.Errorf("parsing $CGO_%s_ALLOW: %v", name, err) + } + allow = r + } + if env := os.Getenv("CGO_" + name + "_DISALLOW"); env != "" { + r, err := regexp.Compile(env) + if err != nil { + return fmt.Errorf("parsing $CGO_%s_DISALLOW: %v", name, err) + } + disallow = r + } + +Args: + for i := 0; i < len(list); i++ { + arg := list[i] + if disallow != nil && disallow.FindString(arg) == arg { + goto Bad + } + if allow != nil && allow.FindString(arg) == arg { + continue Args + } + for _, re := range valid { + if re.FindString(arg) == arg { // must be complete match + continue Args + } + } + for _, x := range validNext { + if arg == x { + if i+1 < len(list) && load.SafeArg(list[i+1]) { + 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 without argument", source, arg) + } + } + Bad: + return fmt.Errorf("invalid flag in %s: %s", source, arg) + } + return nil +} diff --git a/libgo/go/cmd/go/internal/work/security_test.go b/libgo/go/cmd/go/internal/work/security_test.go new file mode 100644 index 00000000000..739ab5a6ee6 --- /dev/null +++ b/libgo/go/cmd/go/internal/work/security_test.go @@ -0,0 +1,240 @@ +// 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 work + +import ( + "os" + "testing" +) + +var goodCompilerFlags = [][]string{ + {"-DFOO"}, + {"-Dfoo=bar"}, + {"-I/"}, + {"-I/etc/passwd"}, + {"-I."}, + {"-O"}, + {"-O2"}, + {"-Osmall"}, + {"-W"}, + {"-Wall"}, + {"-fobjc-arc"}, + {"-fno-objc-arc"}, + {"-fomit-frame-pointer"}, + {"-fno-omit-frame-pointer"}, + {"-fpic"}, + {"-fno-pic"}, + {"-fPIC"}, + {"-fno-PIC"}, + {"-fpie"}, + {"-fno-pie"}, + {"-fPIE"}, + {"-fno-PIE"}, + {"-fsplit-stack"}, + {"-fno-split-stack"}, + {"-fstack-xxx"}, + {"-fno-stack-xxx"}, + {"-fsanitize=hands"}, + {"-g"}, + {"-ggdb"}, + {"-march=souza"}, + {"-mcpu=123"}, + {"-mfpu=123"}, + {"-mtune=happybirthday"}, + {"-mstack-overflow"}, + {"-mno-stack-overflow"}, + {"-mmacosx-version"}, + {"-mnop-fun-dllimport"}, + {"-pthread"}, + {"-std=c99"}, + {"-xc"}, + {"-D", "FOO"}, + {"-D", "foo=bar"}, + {"-I", "."}, + {"-I", "/etc/passwd"}, + {"-I", "世界"}, + {"-framework", "Chocolate"}, + {"-x", "c"}, +} + +var badCompilerFlags = [][]string{ + {"-D@X"}, + {"-D-X"}, + {"-I@dir"}, + {"-I-dir"}, + {"-O@1"}, + {"-Wa,-foo"}, + {"-W@foo"}, + {"-g@gdb"}, + {"-g-gdb"}, + {"-march=@dawn"}, + {"-march=-dawn"}, + {"-std=@c99"}, + {"-std=-c99"}, + {"-x@c"}, + {"-x-c"}, + {"-D", "@foo"}, + {"-D", "-foo"}, + {"-I", "@foo"}, + {"-I", "-foo"}, + {"-framework", "-Caffeine"}, + {"-framework", "@Home"}, + {"-x", "--c"}, + {"-x", "@obj"}, +} + +func TestCheckCompilerFlags(t *testing.T) { + for _, f := range goodCompilerFlags { + if err := checkCompilerFlags("test", "test", f); err != nil { + t.Errorf("unexpected error for %q: %v", f, err) + } + } + for _, f := range badCompilerFlags { + if err := checkCompilerFlags("test", "test", f); err == nil { + t.Errorf("missing error for %q", f) + } + } +} + +var goodLinkerFlags = [][]string{ + {"-Fbar"}, + {"-lbar"}, + {"-Lbar"}, + {"-fpic"}, + {"-fno-pic"}, + {"-fPIC"}, + {"-fno-PIC"}, + {"-fpie"}, + {"-fno-pie"}, + {"-fPIE"}, + {"-fno-PIE"}, + {"-fsanitize=hands"}, + {"-g"}, + {"-ggdb"}, + {"-march=souza"}, + {"-mcpu=123"}, + {"-mfpu=123"}, + {"-mtune=happybirthday"}, + {"-pic"}, + {"-pthread"}, + {"-Wl,-rpath,foo"}, + {"-Wl,-rpath,$ORIGIN/foo"}, + {"-Wl,--warn-error"}, + {"-Wl,--no-warn-error"}, + {"foo.so"}, + {"_世界.dll"}, + {"libcgosotest.dylib"}, + {"-F", "framework"}, + {"-l", "."}, + {"-l", "/etc/passwd"}, + {"-l", "世界"}, + {"-L", "framework"}, + {"-framework", "Chocolate"}, +} + +var badLinkerFlags = [][]string{ + {"-DFOO"}, + {"-Dfoo=bar"}, + {"-O"}, + {"-O2"}, + {"-Osmall"}, + {"-W"}, + {"-Wall"}, + {"-fobjc-arc"}, + {"-fno-objc-arc"}, + {"-fomit-frame-pointer"}, + {"-fno-omit-frame-pointer"}, + {"-fsplit-stack"}, + {"-fno-split-stack"}, + {"-fstack-xxx"}, + {"-fno-stack-xxx"}, + {"-mstack-overflow"}, + {"-mno-stack-overflow"}, + {"-mmacosx-version"}, + {"-mnop-fun-dllimport"}, + {"-std=c99"}, + {"-xc"}, + {"-D", "FOO"}, + {"-D", "foo=bar"}, + {"-I", "FOO"}, + {"-L", "@foo"}, + {"-L", "-foo"}, + {"-x", "c"}, + {"-D@X"}, + {"-D-X"}, + {"-I@dir"}, + {"-I-dir"}, + {"-O@1"}, + {"-Wa,-foo"}, + {"-W@foo"}, + {"-g@gdb"}, + {"-g-gdb"}, + {"-march=@dawn"}, + {"-march=-dawn"}, + {"-std=@c99"}, + {"-std=-c99"}, + {"-x@c"}, + {"-x-c"}, + {"-D", "@foo"}, + {"-D", "-foo"}, + {"-I", "@foo"}, + {"-I", "-foo"}, + {"-l", "@foo"}, + {"-l", "-foo"}, + {"-framework", "-Caffeine"}, + {"-framework", "@Home"}, + {"-x", "--c"}, + {"-x", "@obj"}, + {"-Wl,-rpath,@foo"}, +} + +func TestCheckLinkerFlags(t *testing.T) { + for _, f := range goodLinkerFlags { + if err := checkLinkerFlags("test", "test", f); err != nil { + t.Errorf("unexpected error for %q: %v", f, err) + } + } + for _, f := range badLinkerFlags { + if err := checkLinkerFlags("test", "test", f); err == nil { + t.Errorf("missing error for %q", f) + } + } +} + +func TestCheckFlagAllowDisallow(t *testing.T) { + if err := checkCompilerFlags("TEST", "test", []string{"-disallow"}); err == nil { + t.Fatalf("missing error for -disallow") + } + os.Setenv("CGO_TEST_ALLOW", "-disallo") + if err := checkCompilerFlags("TEST", "test", []string{"-disallow"}); err == nil { + t.Fatalf("missing error for -disallow with CGO_TEST_ALLOW=-disallo") + } + os.Setenv("CGO_TEST_ALLOW", "-disallow") + if err := checkCompilerFlags("TEST", "test", []string{"-disallow"}); err != nil { + t.Fatalf("unexpected error for -disallow with CGO_TEST_ALLOW=-disallow: %v", err) + } + os.Unsetenv("CGO_TEST_ALLOW") + + if err := checkCompilerFlags("TEST", "test", []string{"-Wall"}); err != nil { + t.Fatalf("unexpected error for -Wall: %v", err) + } + os.Setenv("CGO_TEST_DISALLOW", "-Wall") + if err := checkCompilerFlags("TEST", "test", []string{"-Wall"}); err == nil { + t.Fatalf("missing error for -Wall with CGO_TEST_DISALLOW=-Wall") + } + os.Setenv("CGO_TEST_ALLOW", "-Wall") // disallow wins + if err := checkCompilerFlags("TEST", "test", []string{"-Wall"}); err == nil { + t.Fatalf("missing error for -Wall with CGO_TEST_DISALLOW=-Wall and CGO_TEST_ALLOW=-Wall") + } + + os.Setenv("CGO_TEST_ALLOW", "-fplugin.*") + os.Setenv("CGO_TEST_DISALLOW", "-fplugin=lint.so") + if err := checkCompilerFlags("TEST", "test", []string{"-fplugin=faster.so"}); err != nil { + t.Fatalf("unexpected error for -fplugin=faster.so: %v", err) + } + if err := checkCompilerFlags("TEST", "test", []string{"-fplugin=lint.so"}); err == nil { + t.Fatalf("missing error for -fplugin=lint.so: %v", err) + } +} diff --git a/libgo/go/database/sql/driver/driver.go b/libgo/go/database/sql/driver/driver.go index 19a3a4f7c9a..1e54b4cf2cf 100644 --- a/libgo/go/database/sql/driver/driver.go +++ b/libgo/go/database/sql/driver/driver.go @@ -379,6 +379,10 @@ type Rows interface { // size as the Columns() are wide. // // Next should return io.EOF when there are no more rows. + // + // The dest should not be written to outside of Next. Care + // should be taken when closing Rows not to modify + // a buffer held in dest. Next(dest []Value) error } diff --git a/libgo/go/database/sql/fakedb_test.go b/libgo/go/database/sql/fakedb_test.go index e795412de01..abb8d40fc02 100644 --- a/libgo/go/database/sql/fakedb_test.go +++ b/libgo/go/database/sql/fakedb_test.go @@ -1020,11 +1020,6 @@ func (rc *rowsCursor) touchMem() { } func (rc *rowsCursor) Close() error { - if !rc.closed { - for _, bs := range rc.bytesClone { - bs[0] = 255 // first byte corrupted - } - } rc.touchMem() rc.parentMem.touchMem() rc.closed = true diff --git a/libgo/go/database/sql/sql_test.go b/libgo/go/database/sql/sql_test.go index 8137eff82b4..ae6bf7102e3 100644 --- a/libgo/go/database/sql/sql_test.go +++ b/libgo/go/database/sql/sql_test.go @@ -663,43 +663,6 @@ func TestPoolExhaustOnCancel(t *testing.T) { } } -func TestByteOwnership(t *testing.T) { - db := newTestDB(t, "people") - defer closeDB(t, db) - rows, err := db.Query("SELECT|people|name,photo|") - if err != nil { - t.Fatalf("Query: %v", err) - } - type row struct { - name []byte - photo RawBytes - } - got := []row{} - for rows.Next() { - var r row - err = rows.Scan(&r.name, &r.photo) - if err != nil { - t.Fatalf("Scan: %v", err) - } - got = append(got, r) - } - corruptMemory := []byte("\xffPHOTO") - want := []row{ - {name: []byte("Alice"), photo: corruptMemory}, - {name: []byte("Bob"), photo: corruptMemory}, - {name: []byte("Chris"), photo: corruptMemory}, - } - if !reflect.DeepEqual(got, want) { - t.Errorf("mismatch.\n got: %#v\nwant: %#v", got, want) - } - - var photo RawBytes - err = db.QueryRow("SELECT|people|photo|name=?", "Alice").Scan(&photo) - if err == nil { - t.Error("want error scanning into RawBytes from QueryRow") - } -} - func TestRowsColumns(t *testing.T) { db := newTestDB(t, "people") defer closeDB(t, db) @@ -3192,8 +3155,11 @@ func TestIssue18429(t *testing.T) { // reported. rows, _ := tx.QueryContext(ctx, "WAIT|"+qwait+"|SELECT|people|name|") if rows != nil { + var name string // Call Next to test Issue 21117 and check for races. for rows.Next() { + // Scan the buffer so it is read and checked for races. + rows.Scan(&name) } rows.Close() } diff --git a/libgo/go/go/build/deps_test.go b/libgo/go/go/build/deps_test.go index e14a304f2fa..6f9838b55b9 100644 --- a/libgo/go/go/build/deps_test.go +++ b/libgo/go/go/build/deps_test.go @@ -302,7 +302,7 @@ var pkgDeps = map[string][]string{ "os/user": {"L4", "CGO", "io/ioutil", "os", "syscall"}, // Internal package used only for testing. - "os/signal/internal/pty": {"CGO", "fmt", "os"}, + "os/signal/internal/pty": {"CGO", "fmt", "os", "syscall"}, // Basic networking. // Because net must be used by any package that wants to diff --git a/libgo/go/go/internal/gccgoimporter/gccgoinstallation_test.go b/libgo/go/go/internal/gccgoimporter/gccgoinstallation_test.go index 52a34433233..299910de284 100644 --- a/libgo/go/go/internal/gccgoimporter/gccgoinstallation_test.go +++ b/libgo/go/go/internal/gccgoimporter/gccgoinstallation_test.go @@ -62,8 +62,6 @@ var importablePackages = [...]string{ "encoding/pem", "encoding/xml", "errors", - "exp/proxy", - "exp/terminal", "expvar", "flag", "fmt", @@ -114,8 +112,6 @@ var importablePackages = [...]string{ "net/smtp", "net/textproto", "net/url", - "old/regexp", - "old/template", "os/exec", "os", "os/signal", diff --git a/libgo/go/net/sock_bsd.go b/libgo/go/net/sock_bsd.go index dfb09205502..516e557cfd2 100644 --- a/libgo/go/net/sock_bsd.go +++ b/libgo/go/net/sock_bsd.go @@ -20,7 +20,7 @@ func maxListenerBacklog() int { case "darwin": n, err = syscall.SysctlUint32("kern.ipc.somaxconn") case "freebsd": - n, err = syscall.SysctlUint32("kern.ipc.acceptqueue") + n, err = syscall.SysctlUint32("kern.ipc.soacceptqueue") case "netbsd": // NOTE: NetBSD has no somaxconn-like kernel state so far case "openbsd": diff --git a/libgo/go/os/exec.go b/libgo/go/os/exec.go index b3f60b62d03..a7f8710b955 100644 --- a/libgo/go/os/exec.go +++ b/libgo/go/os/exec.go @@ -88,6 +88,11 @@ func FindProcess(pid int) (*Process, error) { // specified by name, argv and attr. The argv slice will become os.Args in the // new process, so it normally starts with the program name. // +// If the calling goroutine has locked the operating system thread +// with runtime.LockOSThread and modified any inheritable OS-level +// thread state (for example, Linux or Plan 9 name spaces), the new +// process will inherit the caller's thread state. +// // StartProcess is a low-level interface. The os/exec package provides // higher-level interfaces. // diff --git a/libgo/go/os/exec/exec.go b/libgo/go/os/exec/exec.go index 8a49fe3b58e..5ef9540141e 100644 --- a/libgo/go/os/exec/exec.go +++ b/libgo/go/os/exec/exec.go @@ -293,6 +293,11 @@ func (c *Cmd) closeDescriptors(closers []io.Closer) { // // If the command starts but does not complete successfully, the error is of // type *ExitError. Other error types may be returned for other situations. +// +// If the calling goroutine has locked the operating system thread +// with runtime.LockOSThread and modified any inheritable OS-level +// thread state (for example, Linux or Plan 9 name spaces), the new +// process will inherit the caller's thread state. func (c *Cmd) Run() error { if err := c.Start(); err != nil { return err diff --git a/libgo/go/os/signal/internal/pty/pty.go b/libgo/go/os/signal/internal/pty/pty.go index 1c3480cffc5..e52d19ac30c 100644 --- a/libgo/go/os/signal/internal/pty/pty.go +++ b/libgo/go/os/signal/internal/pty/pty.go @@ -33,21 +33,35 @@ func close(int32) int32 const _O_RDWR = 2 +type PtyError struct { + FuncName string + ErrorString string + Errno syscall.Errno +} + +func ptyError(name string, err error) *PtyError { + return &PtyError{name, err.Error(), err.(syscall.Errno)} +} + +func (e *PtyError) Error() string { + return fmt.Sprintf("%s: %s", e.FuncName, e.ErrorString) +} + // Open returns a master pty and the name of the linked slave tty. func Open() (master *os.File, slave string, err error) { m := posix_openpt(_O_RDWR) if m < 0 { - return nil, "", fmt.Errorf("posix_openpt: %v", syscall.GetErrno()) + return nil, "", ptyError("posix_openpt", syscall.GetErrno()) } if grantpt(m) < 0 { errno := syscall.GetErrno() close(m) - return nil, "", fmt.Errorf("grantpt: %v", errno) + return nil, "", ptyError("grantpt", errno) } if unlockpt(m) < 0 { errno := syscall.GetErrno() close(m) - return nil, "", fmt.Errorf("unlockpt: %v", errno) + return nil, "", ptyError("unlockpt", errno) } p := ptsname(m) s := (*[32000]byte)(unsafe.Pointer(p))[:] diff --git a/libgo/go/os/signal/signal_cgo_test.go b/libgo/go/os/signal/signal_cgo_test.go index 27707fadcee..84a2a08ce9b 100644 --- a/libgo/go/os/signal/signal_cgo_test.go +++ b/libgo/go/os/signal/signal_cgo_test.go @@ -72,6 +72,10 @@ func TestTerminalSignal(t *testing.T) { master, sname, err := pty.Open() if err != nil { + ptyErr := err.(*pty.PtyError) + if ptyErr.FuncName == "posix_openpt" && ptyErr.Errno == syscall.EACCES { + t.Skip("posix_openpt failed with EACCES, assuming chroot and skipping") + } t.Fatal(err) } defer master.Close() diff --git a/libgo/go/runtime/crash_cgo_test.go b/libgo/go/runtime/crash_cgo_test.go index 35321470425..6688b3cbf6b 100644 --- a/libgo/go/runtime/crash_cgo_test.go +++ b/libgo/go/runtime/crash_cgo_test.go @@ -493,3 +493,24 @@ func TestSigStackSwapping(t *testing.T) { t.Errorf("expected %q got %v", want, got) } } + +func TestCgoTracebackSigpanic(t *testing.T) { + // Test unwinding over a sigpanic in C code without a C + // symbolizer. See issue #23576. + if runtime.GOOS == "windows" { + // On Windows if we get an exception in C code, we let + // the Windows exception handler unwind it, rather + // than injecting a sigpanic. + t.Skip("no sigpanic in C on windows") + } + t.Parallel() + got := runTestProg(t, "testprogcgo", "TracebackSigpanic") + want := "runtime.sigpanic" + if !strings.Contains(got, want) { + t.Fatalf("want failure containing %q. output:\n%s\n", want, got) + } + nowant := "unexpected return pc" + if strings.Contains(got, nowant) { + t.Fatalf("failure incorrectly contains %q. output:\n%s\n", nowant, got) + } +} diff --git a/libgo/go/runtime/testdata/testprogcgo/sigpanic.go b/libgo/go/runtime/testdata/testprogcgo/sigpanic.go new file mode 100644 index 00000000000..cb460309802 --- /dev/null +++ b/libgo/go/runtime/testdata/testprogcgo/sigpanic.go @@ -0,0 +1,28 @@ +// 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 main + +// This program will crash. +// We want to test unwinding from sigpanic into C code (without a C symbolizer). + +/* +#cgo CFLAGS: -O0 + +char *pnil; + +static int f1(void) { + *pnil = 0; + return 0; +} +*/ +import "C" + +func init() { + register("TracebackSigpanic", TracebackSigpanic) +} + +func TracebackSigpanic() { + C.f1() +} diff --git a/libgo/go/text/template/doc.go b/libgo/go/text/template/doc.go index f7609293cea..d174ebd9cfe 100644 --- a/libgo/go/text/template/doc.go +++ b/libgo/go/text/template/doc.go @@ -110,12 +110,6 @@ data, defined in detail in the corresponding sections that follow. T0 is executed; otherwise, dot is set to the successive elements of the array, slice, or map and T1 is executed. - {{break}} - Break out of the surrounding range loop. - - {{continue}} - Begin the next iteration of the surrounding range loop. - {{template "name"}} The template with the specified name is executed with nil data. diff --git a/libgo/go/text/template/exec.go b/libgo/go/text/template/exec.go index 90810090e29..2923dd9d83f 100644 --- a/libgo/go/text/template/exec.go +++ b/libgo/go/text/template/exec.go @@ -27,12 +27,11 @@ const maxExecDepth = 1000 // template so that multiple executions of the same template // can execute in parallel. type state struct { - tmpl *Template - wr io.Writer - node parse.Node // current node, for errors. - vars []variable // push-down stack of variable values. - depth int // the height of the stack of executing templates. - rangeDepth int // nesting level of range loops. + tmpl *Template + wr io.Writer + node parse.Node // current node, for errors + vars []variable // push-down stack of variable values. + depth int // the height of the stack of executing templates. } // variable holds the dynamic value of a variable such as $, $x etc. @@ -223,17 +222,9 @@ func (t *Template) DefinedTemplates() string { return s } -type rangeControl int8 - -const ( - rangeNone rangeControl = iota // no action. - rangeBreak // break out of range. - rangeContinue // continues next range iteration. -) - // Walk functions step through the major pieces of the template structure, // generating output as they go. -func (s *state) walk(dot reflect.Value, node parse.Node) rangeControl { +func (s *state) walk(dot reflect.Value, node parse.Node) { s.at(node) switch node := node.(type) { case *parse.ActionNode: @@ -244,15 +235,13 @@ func (s *state) walk(dot reflect.Value, node parse.Node) rangeControl { s.printValue(node, val) } case *parse.IfNode: - return s.walkIfOrWith(parse.NodeIf, dot, node.Pipe, node.List, node.ElseList) + s.walkIfOrWith(parse.NodeIf, dot, node.Pipe, node.List, node.ElseList) case *parse.ListNode: for _, node := range node.Nodes { - if c := s.walk(dot, node); c != rangeNone { - return c - } + s.walk(dot, node) } case *parse.RangeNode: - return s.walkRange(dot, node) + s.walkRange(dot, node) case *parse.TemplateNode: s.walkTemplate(dot, node) case *parse.TextNode: @@ -260,26 +249,15 @@ func (s *state) walk(dot reflect.Value, node parse.Node) rangeControl { s.writeError(err) } case *parse.WithNode: - return s.walkIfOrWith(parse.NodeWith, dot, node.Pipe, node.List, node.ElseList) - case *parse.BreakNode: - if s.rangeDepth == 0 { - s.errorf("invalid break outside of range") - } - return rangeBreak - case *parse.ContinueNode: - if s.rangeDepth == 0 { - s.errorf("invalid continue outside of range") - } - return rangeContinue + s.walkIfOrWith(parse.NodeWith, dot, node.Pipe, node.List, node.ElseList) default: s.errorf("unknown node: %s", node) } - return rangeNone } // walkIfOrWith walks an 'if' or 'with' node. The two control structures // are identical in behavior except that 'with' sets dot. -func (s *state) walkIfOrWith(typ parse.NodeType, dot reflect.Value, pipe *parse.PipeNode, list, elseList *parse.ListNode) rangeControl { +func (s *state) walkIfOrWith(typ parse.NodeType, dot reflect.Value, pipe *parse.PipeNode, list, elseList *parse.ListNode) { defer s.pop(s.mark()) val := s.evalPipeline(dot, pipe) truth, ok := isTrue(val) @@ -288,14 +266,13 @@ func (s *state) walkIfOrWith(typ parse.NodeType, dot reflect.Value, pipe *parse. } if truth { if typ == parse.NodeWith { - return s.walk(val, list) + s.walk(val, list) } else { - return s.walk(dot, list) + s.walk(dot, list) } } else if elseList != nil { - return s.walk(dot, elseList) + s.walk(dot, elseList) } - return rangeNone } // IsTrue reports whether the value is 'true', in the sense of not the zero of its type, @@ -333,14 +310,13 @@ func isTrue(val reflect.Value) (truth, ok bool) { return truth, true } -func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) rangeControl { +func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) { s.at(r) defer s.pop(s.mark()) val, _ := indirect(s.evalPipeline(dot, r.Pipe)) // mark top of stack before any variables in the body are pushed. mark := s.mark() - s.rangeDepth++ - oneIteration := func(index, elem reflect.Value) rangeControl { + oneIteration := func(index, elem reflect.Value) { // Set top var (lexically the second if there are two) to the element. if len(r.Pipe.Decl) > 0 { s.setVar(1, elem) @@ -349,9 +325,8 @@ func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) rangeControl { if len(r.Pipe.Decl) > 1 { s.setVar(2, index) } - ctrl := s.walk(elem, r.List) + s.walk(elem, r.List) s.pop(mark) - return ctrl } switch val.Kind() { case reflect.Array, reflect.Slice: @@ -359,23 +334,17 @@ func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) rangeControl { break } for i := 0; i < val.Len(); i++ { - if ctrl := oneIteration(reflect.ValueOf(i), val.Index(i)); ctrl == rangeBreak { - break - } + oneIteration(reflect.ValueOf(i), val.Index(i)) } - s.rangeDepth-- - return rangeNone + return case reflect.Map: if val.Len() == 0 { break } for _, key := range sortKeys(val.MapKeys()) { - if ctrl := oneIteration(key, val.MapIndex(key)); ctrl == rangeBreak { - break - } + oneIteration(key, val.MapIndex(key)) } - s.rangeDepth-- - return rangeNone + return case reflect.Chan: if val.IsNil() { break @@ -386,25 +355,20 @@ func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) rangeControl { if !ok { break } - if ctrl := oneIteration(reflect.ValueOf(i), elem); ctrl == rangeBreak { - break - } + oneIteration(reflect.ValueOf(i), elem) } if i == 0 { break } - s.rangeDepth-- - return rangeNone + return case reflect.Invalid: break // An invalid value is likely a nil map, etc. and acts like an empty map. default: s.errorf("range can't iterate over %v", val) } - s.rangeDepth-- if r.ElseList != nil { - return s.walk(dot, r.ElseList) + s.walk(dot, r.ElseList) } - return rangeNone } func (s *state) walkTemplate(dot reflect.Value, t *parse.TemplateNode) { diff --git a/libgo/go/text/template/exec_test.go b/libgo/go/text/template/exec_test.go index 79b504f8a4d..d0cda6bd625 100644 --- a/libgo/go/text/template/exec_test.go +++ b/libgo/go/text/template/exec_test.go @@ -513,10 +513,6 @@ var execTests = []execTest{ {"declare in range", "{{range $x := .PSI}}<{{$foo:=$x}}{{$x}}>{{end}}", "<21><22><23>", tVal, true}, {"range count", `{{range $i, $x := count 5}}[{{$i}}]{{$x}}{{end}}`, "[0]a[1]b[2]c[3]d[4]e", tVal, true}, {"range nil count", `{{range $i, $x := count 0}}{{else}}empty{{end}}`, "empty", tVal, true}, - {"range quick break", `{{range .SI}}{{break}}{{.}}{{end}}`, "", tVal, true}, - {"range break after two", `{{range $i, $x := .SI}}{{if ge $i 2}}{{break}}{{end}}{{.}}{{end}}`, "34", tVal, true}, - {"range continue", `{{range .SI}}{{continue}}{{.}}{{end}}`, "", tVal, true}, - {"range continue condition", `{{range .SI}}{{if eq . 3 }}{{continue}}{{end}}{{.}}{{end}}`, "45", tVal, true}, // Cute examples. {"or as if true", `{{or .SI "slice is empty"}}`, "[3 4 5]", tVal, true}, diff --git a/libgo/go/text/template/parse/lex.go b/libgo/go/text/template/parse/lex.go index da766cc7c32..e112cb7714a 100644 --- a/libgo/go/text/template/parse/lex.go +++ b/libgo/go/text/template/parse/lex.go @@ -60,8 +60,6 @@ const ( // Keywords appear after all the rest. itemKeyword // used only to delimit the keywords itemBlock // block keyword - itemBreak // break keyword - itemContinue // continue keyword itemDot // the cursor, spelled '.' itemDefine // define keyword itemElse // else keyword @@ -76,8 +74,6 @@ const ( var key = map[string]itemType{ ".": itemDot, "block": itemBlock, - "break": itemBreak, - "continue": itemContinue, "define": itemDefine, "else": itemElse, "end": itemEnd, diff --git a/libgo/go/text/template/parse/lex_test.go b/libgo/go/text/template/parse/lex_test.go index ca7c3f64bc7..cb01cd98b6a 100644 --- a/libgo/go/text/template/parse/lex_test.go +++ b/libgo/go/text/template/parse/lex_test.go @@ -192,7 +192,7 @@ var lexTests = []lexTest{ tRight, tEOF, }}, - {"keywords", "{{range if else end with break continue}}", []item{ + {"keywords", "{{range if else end with}}", []item{ tLeft, mkItem(itemRange, "range"), tSpace, @@ -203,10 +203,6 @@ var lexTests = []lexTest{ mkItem(itemEnd, "end"), tSpace, mkItem(itemWith, "with"), - tSpace, - mkItem(itemBreak, "break"), - tSpace, - mkItem(itemContinue, "continue"), tRight, tEOF, }}, diff --git a/libgo/go/text/template/parse/node.go b/libgo/go/text/template/parse/node.go index 7e16349b31e..55ff46c17ab 100644 --- a/libgo/go/text/template/parse/node.go +++ b/libgo/go/text/template/parse/node.go @@ -69,8 +69,6 @@ const ( NodeTemplate // A template invocation action. NodeVariable // A $ variable. NodeWith // A with action. - NodeBreak // A break action. - NodeContinue // A continue action. ) // Nodes. @@ -798,68 +796,6 @@ func (r *RangeNode) Copy() Node { return r.tr.newRange(r.Pos, r.Line, r.Pipe.CopyPipe(), r.List.CopyList(), r.ElseList.CopyList()) } -// BreakNode represents a {{break}} action. -type BreakNode struct { - NodeType - Pos - tr *Tree -} - -func (t *Tree) newBreak(pos Pos) *BreakNode { - return &BreakNode{NodeType: NodeBreak, Pos: pos, tr: t} -} - -func (b *BreakNode) Type() NodeType { - return b.NodeType -} - -func (b *BreakNode) String() string { - return "{{break}}" -} - -func (b *BreakNode) Copy() Node { - return b.tr.newBreak(b.Pos) -} - -func (b *BreakNode) Position() Pos { - return b.Pos -} - -func (b *BreakNode) tree() *Tree { - return b.tr -} - -// ContinueNode represents a {{continue}} action. -type ContinueNode struct { - NodeType - Pos - tr *Tree -} - -func (t *Tree) newContinue(pos Pos) *ContinueNode { - return &ContinueNode{NodeType: NodeContinue, Pos: pos, tr: t} -} - -func (c *ContinueNode) Type() NodeType { - return c.NodeType -} - -func (c *ContinueNode) String() string { - return "{{continue}}" -} - -func (c *ContinueNode) Copy() Node { - return c.tr.newContinue(c.Pos) -} - -func (c *ContinueNode) Position() Pos { - return c.Pos -} - -func (c *ContinueNode) tree() *Tree { - return c.tr -} - // WithNode represents a {{with}} action and its commands. type WithNode struct { BranchNode diff --git a/libgo/go/text/template/parse/parse.go b/libgo/go/text/template/parse/parse.go index ad9c0519789..a91a544ce01 100644 --- a/libgo/go/text/template/parse/parse.go +++ b/libgo/go/text/template/parse/parse.go @@ -23,13 +23,12 @@ type Tree struct { Root *ListNode // top-level root of the tree. text string // text parsed to create the template (or its parent) // Parsing only; cleared after parse. - funcs []map[string]interface{} - lex *lexer - token [3]item // three-token lookahead for parser. - peekCount int - vars []string // variables defined at the moment. - treeSet map[string]*Tree - rangeDepth int // nesting level of range loops. + funcs []map[string]interface{} + lex *lexer + token [3]item // three-token lookahead for parser. + peekCount int + vars []string // variables defined at the moment. + treeSet map[string]*Tree } // Copy returns a copy of the Tree. Any parsing state is discarded. @@ -220,7 +219,6 @@ func (t *Tree) stopParse() { t.vars = nil t.funcs = nil t.treeSet = nil - t.rangeDepth = 0 } // Parse parses the template definition string to construct a representation of @@ -375,10 +373,6 @@ func (t *Tree) action() (n Node) { return t.templateControl() case itemWith: return t.withControl() - case itemBreak: - return t.breakControl() - case itemContinue: - return t.continueControl() } t.backup() token := t.peek() @@ -459,13 +453,7 @@ func (t *Tree) parseControl(allowElseIf bool, context string) (pos Pos, line int defer t.popVars(len(t.vars)) pipe = t.pipeline(context) var next Node - if context == "range" { - t.rangeDepth++ - } list, next = t.itemList() - if context == "range" { - t.rangeDepth-- - } switch next.Type() { case nodeEnd: //done case nodeElse: @@ -510,26 +498,6 @@ func (t *Tree) rangeControl() Node { return t.newRange(t.parseControl(false, "range")) } -// Break: -// {{break}} -// Break keyword is past. -func (t *Tree) breakControl() Node { - if t.rangeDepth == 0 { - t.errorf("unexpected break outside of range") - } - return t.newBreak(t.expect(itemRightDelim, "break").pos) -} - -// Continue: -// {{continue}} -// Continue keyword is past. -func (t *Tree) continueControl() Node { - if t.rangeDepth == 0 { - t.errorf("unexpected continue outside of range") - } - return t.newContinue(t.expect(itemRightDelim, "continue").pos) -} - // With: // {{with pipeline}} itemList {{end}} // {{with pipeline}} itemList {{else}} itemList {{end}} diff --git a/libgo/go/text/template/parse/parse_test.go b/libgo/go/text/template/parse/parse_test.go index aade33ea48e..81f14aca986 100644 --- a/libgo/go/text/template/parse/parse_test.go +++ b/libgo/go/text/template/parse/parse_test.go @@ -218,12 +218,6 @@ var parseTests = []parseTest{ `{{range $x := .SI}}{{.}}{{end}}`}, {"range 2 vars", "{{range $x, $y := .SI}}{{.}}{{end}}", noError, `{{range $x, $y := .SI}}{{.}}{{end}}`}, - {"range []int with break", "{{range .SI}}{{break}}{{.}}{{end}}", noError, - `{{range .SI}}{{break}}{{.}}{{end}}`}, - {"range []int with break in else", "{{range .SI}}{{range .SI}}{{.}}{{else}}{{break}}{{end}}{{end}}", noError, - `{{range .SI}}{{range .SI}}{{.}}{{else}}{{break}}{{end}}{{end}}`}, - {"range []int with continue", "{{range .SI}}{{continue}}{{.}}{{end}}", noError, - `{{range .SI}}{{continue}}{{.}}{{end}}`}, {"constants", "{{range .SI 1 -3.2i true false 'a' nil}}{{end}}", noError, `{{range .SI 1 -3.2i true false 'a' nil}}{{end}}`}, {"template", "{{template `x`}}", noError, @@ -294,12 +288,6 @@ var parseTests = []parseTest{ {"empty pipeline", `{{printf "%d" ( ) }}`, hasError, ""}, // Missing pipeline in block {"block definition", `{{block "foo"}}hello{{end}}`, hasError, ""}, - // Invalid range control - {"break outside of range", `{{break}}`, hasError, ""}, - {"break in range else, outside of range", `{{range .}}{{.}}{{else}}{{break}}{{end}}`, hasError, ""}, - {"continue outside of range", `{{continue}}`, hasError, ""}, - {"continue in range else, outside of range", `{{range .}}{{.}}{{else}}{{continue}}{{end}}`, hasError, ""}, - {"additional break data", `{{range .}}{{break label}}{{end}}`, hasError, ""}, } var builtins = map[string]interface{}{ diff --git a/libgo/misc/cgo/errors/src/err1.go b/libgo/misc/cgo/errors/src/err1.go index 61bbcd29577..2c232cf58a7 100644 --- a/libgo/misc/cgo/errors/src/err1.go +++ b/libgo/misc/cgo/errors/src/err1.go @@ -5,7 +5,7 @@ package main /* -#cgo LDFLAGS: -c +#cgo LDFLAGS: -L/nonexist void test() { xxx; // ERROR HERE diff --git a/libgo/misc/cgo/test/issue19832.go b/libgo/misc/cgo/test/issue19832.go deleted file mode 100644 index 44587770af4..00000000000 --- a/libgo/misc/cgo/test/issue19832.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2015 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. - -// Issue 19832. Functions taking a pointer typedef were being expanded and triggering a compiler error. - -package cgotest - -// typedef struct { int i; } *PS; -// void T19832(PS p) {} -import "C" -import "testing" - -func test19832(t *testing.T) { - C.T19832(nil) -} diff --git a/libgo/misc/cgo/test/issue4029.c b/libgo/misc/cgo/test/issue4029.c index eab36834501..7205c5a5a25 100644 --- a/libgo/misc/cgo/test/issue4029.c +++ b/libgo/misc/cgo/test/issue4029.c @@ -4,6 +4,25 @@ // +build !windows +#include +#include + +// Write our own versions of dlopen/dlsym/dlclose so that we represent +// the opaque handle as a Go uintptr rather than a Go pointer to avoid +// garbage collector confusion. See issue 23663. + +uintptr_t dlopen4029(char* name, int flags) { + return (uintptr_t)(dlopen(name, flags)); +} + +uintptr_t dlsym4029(uintptr_t handle, char* name) { + return (uintptr_t)(dlsym((void*)(handle), name)); +} + +int dlclose4029(uintptr_t handle) { + return dlclose((void*)(handle)); +} + void call4029(void *arg) { void (*fn)(void) = arg; fn(); diff --git a/libgo/misc/cgo/test/issue4029.go b/libgo/misc/cgo/test/issue4029.go index 5789b99ef67..8e468d367d1 100644 --- a/libgo/misc/cgo/test/issue4029.go +++ b/libgo/misc/cgo/test/issue4029.go @@ -7,10 +7,15 @@ package cgotest /* +#include #include #cgo linux LDFLAGS: -ldl -extern void call4029(void *arg); +extern uintptr_t dlopen4029(char*, int); +extern uintptr_t dlsym4029(uintptr_t, char*); +extern int dlclose4029(uintptr_t); + +extern void call4029(uintptr_t arg); */ import "C" @@ -51,15 +56,15 @@ func test4029(t *testing.T) { } func loadThySelf(t *testing.T, symbol string) { - this_process := C.dlopen(nil, C.RTLD_NOW) - if this_process == nil { + this_process := C.dlopen4029(nil, C.RTLD_NOW) + if this_process == 0 { t.Error("dlopen:", C.GoString(C.dlerror())) return } - defer C.dlclose(this_process) + defer C.dlclose4029(this_process) - symbol_address := C.dlsym(this_process, C.CString(symbol)) - if symbol_address == nil { + symbol_address := C.dlsym4029(this_process, C.CString(symbol)) + if symbol_address == 0 { t.Error("dlsym:", C.GoString(C.dlerror())) return }