libgo: update to Go1.10rc2

Reviewed-on: https://go-review.googlesource.com/92736

From-SVN: r257493
This commit is contained in:
Ian Lance Taylor 2018-02-08 15:30:22 +00:00
parent b5ec4de777
commit 9adab5dd16
39 changed files with 1035 additions and 345 deletions

View file

@ -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.

View file

@ -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.

View file

@ -1 +1 @@
go1.10rc1
go1.10rc2

View file

@ -45,8 +45,8 @@ For example:
// #include <png.h>
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

View file

@ -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

View file

@ -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

View file

@ -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")
}

View file

@ -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
}

View file

@ -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.

View file

@ -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

View file

@ -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.

View file

@ -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)
}

View file

@ -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)

View file

@ -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
}

View file

@ -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)
}
}

View file

@ -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
}

View file

@ -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

View file

@ -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()
}

View file

@ -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

View file

@ -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",

View file

@ -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":

View file

@ -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.
//

View file

@ -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

View file

@ -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))[:]

View file

@ -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()

View file

@ -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)
}
}

View file

@ -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()
}

View file

@ -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.

View file

@ -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) {

View file

@ -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},

View file

@ -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,

View file

@ -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,
}},

View file

@ -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

View file

@ -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}}

View file

@ -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{}{

View file

@ -5,7 +5,7 @@
package main
/*
#cgo LDFLAGS: -c
#cgo LDFLAGS: -L/nonexist
void test() {
xxx; // ERROR HERE

View file

@ -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)
}

View file

@ -4,6 +4,25 @@
// +build !windows
#include <stdint.h>
#include <dlfcn.h>
// 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();

View file

@ -7,10 +7,15 @@
package cgotest
/*
#include <stdint.h>
#include <dlfcn.h>
#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
}