-cdc28627b7abfd73f5d552813db8eb4293b823b0
+2aa95f1499cf931ef8e95c7958463829276a0f2c
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
-5348aed83e39bd1d450d92d7f627e994c2db6ebf
+20e228f2fdb44350c858de941dff4aea9f3127b8
The first line of this file holds the git revision number of the
last merge done from the master library sources.
// #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
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
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
// 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
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"
}
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() }`)
}
}
+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)
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)
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")
+}
package cache
import (
- "cmd/go/internal/base"
+ "fmt"
"io/ioutil"
"os"
"path/filepath"
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.
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
}
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.
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
"sort"
"strings"
"unicode"
+ "unicode/utf8"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
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
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
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 {
// 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
}
// 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(),
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 {
}
}
+// 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.
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)
}
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
// 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)
}
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)
}
// 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 {
// 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
}
// 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 {
}
// 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
}
// 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))
// 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)
--- /dev/null
+// 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
+}
--- /dev/null
+// 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)
+ }
+}
// 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
}
}
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
}
}
-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)
// 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()
}
"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
"encoding/pem",
"encoding/xml",
"errors",
- "exp/proxy",
- "exp/terminal",
"expvar",
"flag",
"fmt",
"net/smtp",
"net/textproto",
"net/url",
- "old/regexp",
- "old/template",
"os/exec",
"os",
"os/signal",
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":
// 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.
//
//
// 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
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))[:]
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()
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)
+ }
+}
--- /dev/null
+// 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()
+}
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.
// 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.
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:
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:
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)
}
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,
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)
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:
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
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) {
{"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},
// 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
var key = map[string]itemType{
".": itemDot,
"block": itemBlock,
- "break": itemBreak,
- "continue": itemContinue,
"define": itemDefine,
"else": itemElse,
"end": itemEnd,
tRight,
tEOF,
}},
- {"keywords", "{{range if else end with break continue}}", []item{
+ {"keywords", "{{range if else end with}}", []item{
tLeft,
mkItem(itemRange, "range"),
tSpace,
mkItem(itemEnd, "end"),
tSpace,
mkItem(itemWith, "with"),
- tSpace,
- mkItem(itemBreak, "break"),
- tSpace,
- mkItem(itemContinue, "continue"),
tRight,
tEOF,
}},
NodeTemplate // A template invocation action.
NodeVariable // A $ variable.
NodeWith // A with action.
- NodeBreak // A break action.
- NodeContinue // A continue action.
)
// Nodes.
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
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.
t.vars = nil
t.funcs = nil
t.treeSet = nil
- t.rangeDepth = 0
}
// Parse parses the template definition string to construct a representation of
return t.templateControl()
case itemWith:
return t.withControl()
- case itemBreak:
- return t.breakControl()
- case itemContinue:
- return t.continueControl()
}
t.backup()
token := t.peek()
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:
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}}
`{{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,
{"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{}{
package main
/*
-#cgo LDFLAGS: -c
+#cgo LDFLAGS: -L/nonexist
void test() {
xxx; // ERROR HERE
+++ /dev/null
-// 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)
-}
// +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();
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"
}
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
}