Commit 6e3041b9 authored by Russ Cox's avatar Russ Cox

all: merge master into release-branch.go1.6

Change-Id: Ie2a999e36ee654c1217bd03f720791360f66718d
parents 5d343bdf 939a9424
......@@ -12,7 +12,7 @@ The document is not comprehensive.
<p>
The assembler is based on the input style of the Plan 9 assemblers, which is documented in detail
<a href="http://plan9.bell-labs.com/sys/doc/asm.html">elsewhere</a>.
<a href="https://9p.io/sys/doc/asm.html">elsewhere</a>.
If you plan to write assembly language, you should read that document although much of it is Plan 9-specific.
The current document provides a summary of the syntax and the differences with
what is explained in that document, and
......@@ -23,7 +23,7 @@ describes the peculiarities that apply when writing assembly code to interact wi
The most important thing to know about Go's assembler is that it is not a direct representation of the underlying machine.
Some of the details map precisely to the machine, but some do not.
This is because the compiler suite (see
<a href="http://plan9.bell-labs.com/sys/doc/compiler.html">this description</a>)
<a href="https://9p.io/sys/doc/compiler.html">this description</a>)
needs no assembler pass in the usual pipeline.
Instead, the compiler operates on a kind of semi-abstract instruction set,
and instruction selection occurs partly after code generation.
......@@ -621,6 +621,15 @@ These modes accept only 1, 2, 4, and 8 as scale factors.
</ul>
<p>
When using the compiler and assembler's
<code>-dynlink</code> or <code>-shared</code> modes,
any load or store of a fixed memory location such as a global variable
must be assumed to overwrite <code>CX</code>.
Therefore, to be safe for use with these modes,
assembly sources should typically avoid CX except between memory references.
</p>
<h3 id="amd64">64-bit Intel 386 (a.k.a. amd64)</h3>
<p>
......
......@@ -91,7 +91,7 @@
The full address syntax is summarized in this table
(an excerpt of Table II from
<a href="http://plan9.bell-labs.com/sys/doc/sam/sam.html">The text editor <code>sam</code></a>):
<a href="https://9p.io/sys/doc/sam/sam.html">The text editor <code>sam</code></a>):
<br/><br/>
<table>
......
......@@ -198,9 +198,13 @@ prints help text, not an error.
</p>
<p>
Note to Git aficionados: The <code>git-codereview</code> command is not required to
<b>Note to Git aficionados:</b>
The <code>git-codereview</code> command is not required to
upload and manage Gerrit code reviews. For those who prefer plain Git, the text
below gives the Git equivalent of each git-codereview command. If you do use plain
below gives the Git equivalent of each git-codereview command.
</p>
<p>If you do use plain
Git, note that you still need the commit hooks that the git-codereview command
configures; those hooks add a Gerrit <code>Change-Id</code> line to the commit
message and check that all Go source files have been formatted with gofmt. Even
......@@ -208,6 +212,12 @@ if you intend to use plain Git for daily work, install the hooks in a new Git
checkout by running <code>git-codereview</code> <code>hooks</code>.
</p>
<p>
The workflow described below assumes a single change per branch.
It is also possible to prepare a sequence of (usually related) changes in a single branch.
See the <a href="https://golang.org/x/review/git-codereview">git-codereview documentation</a> for details.
</p>
<h3 id="git-config">Set up git aliases</h3>
<p>
......
<!--{
"Title": "Go 1.6 Release Notes DRAFT",
"Title": "Go 1.6 Release Notes",
"Path": "/doc/go1.6",
"Template": true
}-->
......@@ -13,13 +13,6 @@ Edit .,s;^([a-z][A-Za-z0-9_/]+)\.([A-Z][A-Za-z0-9_]+\.)?([A-Z][A-Za-z0-9_]+)([ .
ul li { margin: 0.5em 0; }
</style>
<p>
<i>NOTE: This is a DRAFT of the Go 1.6 release notes, prepared for the Go 1.6 beta.
Go 1.6 has NOT yet been released.
By our regular schedule, it is expected some time in February 2016.
</i>
</p>
<h2 id="introduction">Introduction to Go 1.6</h2>
<p>
......@@ -70,9 +63,12 @@ On NaCl, Go 1.5 required SDK version pepper-41.
Go 1.6 adds support for later SDK versions.
</p>
<pre>
TODO: CX no longer available on 386 assembly? (https://golang.org/cl/16386)
</pre>
<p>
On 32-bit x86 systems using the <code>-dynlink</code> or <code>-shared</code> compilation modes,
the register CX is now overwritten by certain memory references and should
be avoided in hand-written assembly.
See the <a href="/doc/asm#x86">assembly documentation</a> for details.
</p>
<h2 id="tools">Tools</h2>
......@@ -248,7 +244,7 @@ Some programs may run faster, some slower.
On average the programs in the Go 1 benchmark suite run a few percent faster in Go 1.6
than they did in Go 1.5.
The garbage collector's pauses are even lower than in Go 1.5,
although the effect is likely only noticeable for programs using
especially for programs using
a large amount of memory.
</p>
......@@ -569,7 +565,7 @@ The <a href="/pkg/debug/elf/"><code>debug/elf</code></a> package
adds support for general compressed ELF sections.
User code needs no updating: the sections are decompressed automatically when read.
However, compressed
<a href="/pkg/debug/elf/#Section"><code>Section</code></a>'s do not support random access:
<a href="/pkg/debug/elf/#Section"><code>Sections</code></a> do not support random access:
they have a nil <code>ReaderAt</code> field.
</li>
......@@ -632,7 +628,6 @@ In previous releases, the argument to <code>*</code> was required to have type <
Also in the <a href="/pkg/fmt/"><code>fmt</code></a> package,
<a href="/pkg/fmt/#Scanf"><code>Scanf</code></a> can now scan hexadecimal strings using %X, as an alias for %x.
Both formats accept any mix of upper- and lower-case hexadecimal.
<a href="https://golang.org/issues/13585">TODO: Keep?</a>
</li>
<li>
......@@ -717,9 +712,6 @@ Second, DNS lookup functions such as
<a href="/pkg/net/#LookupAddr"><code>LookupAddr</code></a>
now return rooted domain names (with a trailing dot)
on Plan 9 and Windows, to match the behavior of Go on Unix systems.
TODO: Third, lookups satisfied from /etc/hosts now add a trailing dot as well,
so that looking up 127.0.0.1 typically now returns &ldquo;localhost.&rdquo; not &ldquo;localhost&rdquo;.
This is arguably a mistake but is not yet fixed. See https://golang.org/issue/13564.
</li>
<li>
......@@ -875,16 +867,18 @@ should only be used when contention has been observed.
<li>
The <a href="/pkg/strconv/"><code>strconv</code></a> package adds
<a href="/pkg/strconv/#IsGraphic"><code>IsGraphic</code></a>,
similar to <a href="/pkg/strconv/#IsPrint"><code>IsPrint</code></a>.
It also adds
<a href="/pkg/strconv/#QuoteToGraphic"><code>QuoteToGraphic</code></a>,
<a href="/pkg/strconv/#QuoteRuneToGraphic"><code>QuoteRuneToGraphic</code></a>,
<a href="/pkg/strconv/#AppendQuoteToGraphic"><code>AppendQuoteToGraphic</code></a>,
and
<a href="/pkg/strconv/#AppendQuoteRuneToGraphic"><code>AppendQuoteRuneToGraphic</code></a>,
analogous to
<a href="/pkg/strconv/#IsPrint"><code>IsPrint</code></a>,
<a href="/pkg/strconv/#QuoteToPrint"><code>QuoteToPrint</code></a>,
<a href="/pkg/strconv/#QuoteToASCII"><code>QuoteToASCII</code></a>,
<a href="/pkg/strconv/#QuoteRuneToASCII"><code>QuoteRuneToASCII</code></a>,
and so on.
The <code>Print</code> family escapes all space characters except ASCII space (U+0020).
The <code>ASCII</code> family escapes all space characters except ASCII space (U+0020).
In contrast, the <code>Graphic</code> family does not escape any Unicode space characters (category Zs).
</li>
......
......@@ -98,7 +98,7 @@ What's the origin of the mascot?</h3>
<p>
The mascot and logo were designed by
<a href="http://reneefrench.blogspot.com">Renée French</a>, who also designed
<a href="http://plan9.bell-labs.com/plan9/glenda.html">Glenda</a>,
<a href="https://9p.io/plan9/glenda.html">Glenda</a>,
the Plan 9 bunny.
The <a href="https://blog.golang.org/gopher">gopher</a>
is derived from one she used for an <a href="http://wfmu.org/">WFMU</a>
......
......@@ -27,23 +27,23 @@ go src=..
internal
objfile
objfile.go
unvendor
golang.org
x
arch
arm
armasm
testdata
+
x86
x86asm
testdata
+
gofmt
gofmt.go
gofmt_test.go
testdata
+
vendor
golang.org
x
arch
arm
armasm
testdata
+
x86
x86asm
testdata
+
archive
tar
testdata
......
......@@ -748,7 +748,13 @@ func typefmt(t *Type, flag int) string {
if name != "" {
str = name + " " + typ
}
if flag&obj.FmtShort == 0 && !fmtbody && t.Note != nil {
// The fmtbody flag is intended to suppress escape analysis annotations
// when printing a function type used in a function body.
// (The escape analysis tags do not apply to func vars.)
// But it must not suppress struct field tags.
// See golang.org/issue/13777 and golang.org/issue/14331.
if flag&obj.FmtShort == 0 && (!fmtbody || !t.Funarg) && t.Note != nil {
str += " " + strconv.Quote(*t.Note)
}
return str
......
......@@ -836,7 +836,7 @@ func gen(n *Node) {
Cgen_as_wb(n.Left, n.Right, true)
case OAS2DOTTYPE:
cgen_dottype(n.Rlist.N, n.List.N, n.List.Next.N, false)
cgen_dottype(n.Rlist.N, n.List.N, n.List.Next.N, needwritebarrier(n.List.N, n.Rlist.N))
case OCALLMETH:
cgen_callmeth(n, 0)
......
......@@ -947,6 +947,11 @@ func (t *tester) raceTest(dt *distTest) error {
t.addCmd(dt, "src", "go", "test", "-race", "-i", "runtime/race", "flag", "os/exec")
t.addCmd(dt, "src", "go", "test", "-race", "-run=Output", "runtime/race")
t.addCmd(dt, "src", "go", "test", "-race", "-short", "-run=TestParse|TestEcho", "flag", "os/exec")
// We don't want the following line, because it
// slows down all.bash (by 10 seconds on my laptop).
// The race builder should catch any error here, but doesn't.
// TODO(iant): Figure out how to catch this.
// t.addCmd(dt, "src", "go", "test", "-race", "-run=TestParallelTest", "cmd/go")
if t.cgoEnabled {
env := mergeEnvLists([]string{"GOTRACEBACK=2"}, os.Environ())
cmd := t.addCmd(dt, "misc/cgo/test", "go", "test", "-race", "-short")
......
......@@ -667,6 +667,7 @@ var (
goarch string
goos string
exeSuffix string
gopath []string
)
func init() {
......@@ -675,6 +676,7 @@ func init() {
if goos == "windows" {
exeSuffix = ".exe"
}
gopath = filepath.SplitList(buildContext.GOPATH)
}
// A builder holds global state about a build.
......@@ -1684,6 +1686,22 @@ func (b *builder) includeArgs(flag string, all []*action) []string {
inc = append(inc, flag, b.work)
// Finally, look in the installed package directories for each action.
// First add the package dirs corresponding to GOPATH entries
// in the original GOPATH order.
need := map[string]*build.Package{}
for _, a1 := range all {
if a1.p != nil && a1.pkgdir == a1.p.build.PkgRoot {
need[a1.p.build.Root] = a1.p.build
}
}
for _, root := range gopath {
if p := need[root]; p != nil && !incMap[p.PkgRoot] {
incMap[p.PkgRoot] = true
inc = append(inc, flag, p.PkgTargetRoot)
}
}
// Then add anything that's left.
for _, a1 := range all {
if a1.p == nil {
continue
......
......@@ -10,6 +10,7 @@ import (
"fmt"
"go/build"
"go/format"
"internal/race"
"internal/testenv"
"io"
"io/ioutil"
......@@ -69,7 +70,11 @@ func TestMain(m *testing.M) {
flag.Parse()
if canRun {
out, err := exec.Command("go", "build", "-tags", "testgo", "-o", "testgo"+exeSuffix).CombinedOutput()
args := []string{"build", "-tags", "testgo", "-o", "testgo" + exeSuffix}
if race.Enabled {
args = append(args, "-race")
}
out, err := exec.Command("go", args...).CombinedOutput()
if err != nil {
fmt.Fprintf(os.Stderr, "building testgo failed: %v\n%s", err, out)
os.Exit(2)
......@@ -2565,6 +2570,59 @@ func TestGoInstallShadowedGOPATH(t *testing.T) {
tg.grepStderr("no install location for.*gopath2.src.test: hidden by .*gopath1.src.test", "missing error")
}
func TestGoBuildGOPATHOrder(t *testing.T) {
// golang.org/issue/14176#issuecomment-179895769
// golang.org/issue/14192
// -I arguments to compiler could end up not in GOPATH order,
// leading to unexpected import resolution in the compiler.
// This is still not a complete fix (see golang.org/issue/14271 and next test)
// but it is clearly OK and enough to fix both of the two reported
// instances of the underlying problem. It will have to do for now.
tg := testgo(t)
defer tg.cleanup()
tg.makeTempdir()
tg.setenv("GOPATH", tg.path("p1")+string(filepath.ListSeparator)+tg.path("p2"))
tg.tempFile("p1/src/foo/foo.go", "package foo\n")
tg.tempFile("p2/src/baz/baz.go", "package baz\n")
tg.tempFile("p2/pkg/"+runtime.GOOS+"_"+runtime.GOARCH+"/foo.a", "bad\n")
tg.tempFile("p1/src/bar/bar.go", `
package bar
import _ "baz"
import _ "foo"
`)
tg.run("install", "-x", "bar")
}
func TestGoBuildGOPATHOrderBroken(t *testing.T) {
// This test is known not to work.
// See golang.org/issue/14271.
t.Skip("golang.org/issue/14271")
tg := testgo(t)
defer tg.cleanup()
tg.makeTempdir()
tg.tempFile("p1/src/foo/foo.go", "package foo\n")
tg.tempFile("p2/src/baz/baz.go", "package baz\n")
tg.tempFile("p1/pkg/"+runtime.GOOS+"_"+runtime.GOARCH+"/baz.a", "bad\n")
tg.tempFile("p2/pkg/"+runtime.GOOS+"_"+runtime.GOARCH+"/foo.a", "bad\n")
tg.tempFile("p1/src/bar/bar.go", `
package bar
import _ "baz"
import _ "foo"
`)
colon := string(filepath.ListSeparator)
tg.setenv("GOPATH", tg.path("p1")+colon+tg.path("p2"))
tg.run("install", "-x", "bar")
tg.setenv("GOPATH", tg.path("p2")+colon+tg.path("p1"))
tg.run("install", "-x", "bar")
}
func TestIssue11709(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
......@@ -2682,3 +2740,22 @@ func TestIssue13655(t *testing.T) {
tg.grepStdout("runtime/internal/sys", "did not find required dependency of "+pkg+" on runtime/internal/sys")
}
}
// For issue 14337.
func TestParallelTest(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.makeTempdir()
const testSrc = `package package_test
import (
"testing"
)
func TestTest(t *testing.T) {
}`
tg.tempFile("src/p1/p1_test.go", strings.Replace(testSrc, "package_test", "p1_test", 1))
tg.tempFile("src/p2/p2_test.go", strings.Replace(testSrc, "package_test", "p2_test", 1))
tg.tempFile("src/p3/p3_test.go", strings.Replace(testSrc, "package_test", "p3_test", 1))
tg.tempFile("src/p4/p4_test.go", strings.Replace(testSrc, "package_test", "p4_test", 1))
tg.setenv("GOPATH", tg.path("."))
tg.run("test", "-p=4", "p1", "p2", "p3", "p4")
}
......@@ -454,7 +454,9 @@ func envForDir(dir string, base []string) []string {
// mergeEnvLists merges the two environment lists such that
// variables with the same name in "in" replace those in "out".
// This always returns a newly allocated slice.
func mergeEnvLists(in, out []string) []string {
out = append([]string(nil), out...)
NextVar:
for _, inkv := range in {
k := strings.SplitAfterN(inkv, "=", 2)[0]
......
......@@ -967,7 +967,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
}
}
}
if p.Standard && !p1.Standard && p.Error == nil {
if p.Standard && p.Error == nil && !p1.Standard && p1.Error == nil {
p.Error = &PackageError{
ImportStack: stk.copy(),
Err: fmt.Sprintf("non-standard import %q in standard package %q", path, p.ImportPath),
......
......@@ -15,8 +15,8 @@ import (
"strings"
"text/tabwriter"
"golang.org/x/arch/arm/armasm"
"golang.org/x/arch/x86/x86asm"
"cmd/internal/unvendor/golang.org/x/arch/arm/armasm"
"cmd/internal/unvendor/golang.org/x/arch/x86/x86asm"
)
// Disasm is a disassembler for a given File.
......
......@@ -1946,7 +1946,9 @@ func writepub(ispub func(*DWDie) bool) int64 {
*/
func writearanges() int64 {
sectionstart := Cpos()
headersize := int(Rnd(4+2+4+1+1, int64(Thearch.Ptrsize))) // don't count unit_length field itself
// The first tuple is aligned to a multiple of the size of a single tuple
// (twice the size of an address)
headersize := int(Rnd(4+2+4+1+1, int64(Thearch.Ptrsize*2))) // don't count unit_length field itself
for compunit := dwroot.child; compunit != nil; compunit = compunit.link {
b := getattr(compunit, DW_AT_low_pc)
......
......@@ -96,7 +96,7 @@ func (x stringVal) String() string {
// only the first maxLen-3 runes; then add "...".
i := 0
for n := 0; n < maxLen-3; n++ {
_, size := utf8.DecodeRuneInString(s)
_, size := utf8.DecodeRuneInString(s[i:])
i += size
}
s = s[:i] + "..."
......
......@@ -204,6 +204,7 @@ func eql(x, y Value) bool {
// String tests
var xxx = strings.Repeat("x", 68)
var issue14262 = `"بموجب الشروط التالية نسب المصنف — يجب عليك أن تنسب العمل بالطريقة التي تحددها المؤلف أو المرخص (ولكن ليس بأي حال من الأحوال أن توحي وتقترح بتحول أو استخدامك للعمل). المشاركة على قدم المساواة — إذا كنت يعدل ، والتغيير ، أو الاستفادة من هذا العمل ، قد ينتج عن توزيع العمل إلا في ظل تشابه او تطابق فى واحد لهذا الترخيص."`
var stringTests = []struct {
input, short, exact string
......@@ -225,6 +226,7 @@ var stringTests = []struct {
{`"` + xxx + `xx"`, `"` + xxx + `xx"`, `"` + xxx + `xx"`},
{`"` + xxx + `xxx"`, `"` + xxx + `...`, `"` + xxx + `xxx"`},
{`"` + xxx + xxx + `xxx"`, `"` + xxx + `...`, `"` + xxx + xxx + `xxx"`},
{issue14262, `"بموجب الشروط التالية نسب المصنف — يجب عليك أن تنسب العمل بالطريقة ال...`, issue14262},
// Int
{"0", "0", "0"},
......
......@@ -31,7 +31,8 @@ var pkgExts = [...]string{".a", ".o"}
// FindPkg returns the filename and unique package id for an import
// path based on package information provided by build.Import (using
// the build.Default build.Context).
// the build.Default build.Context). A relative srcDir is interpreted
// relative to the current working directory.
// If no file was found, an empty filename is returned.
//
func FindPkg(path, srcDir string) (filename, id string) {
......@@ -44,6 +45,9 @@ func FindPkg(path, srcDir string) (filename, id string) {
default:
// "x" -> "$GOPATH/pkg/$GOOS_$GOARCH/x.ext", "x"
// Don't require the source files to be present.
if abs, err := filepath.Abs(srcDir); err == nil { // see issue 14282
srcDir = abs
}
bp, _ := build.Import(path, srcDir, build.FindOnly|build.AllowBinary)
if bp.PkgObj == "" {
return
......
......@@ -184,7 +184,8 @@ func roundFloat64(x constant.Value) constant.Value {
// provided (only needed for int/uint sizes).
//
// If rounded != nil, *rounded is set to the rounded value of x for
// representable floating-point values; it is left alone otherwise.
// representable floating-point and complex values, and to an Int
// value for integer values; it is left alone otherwise.
// It is ok to provide the addressof the first argument for rounded.
func representableConst(x constant.Value, conf *Config, typ *Basic, rounded *constant.Value) bool {
if x.Kind() == constant.Unknown {
......@@ -197,6 +198,9 @@ func representableConst(x constant.Value, conf *Config, typ *Basic, rounded *con
if x.Kind() != constant.Int {
return false
}
if rounded != nil {
*rounded = x
}
if x, ok := constant.Int64Val(x); ok {
switch typ.kind {
case Int:
......@@ -808,8 +812,6 @@ func (check *Checker) binary(x *operand, e *ast.BinaryExpr, lhs, rhs ast.Expr, o
typ := x.typ.Underlying().(*Basic)
// force integer division of integer operands
if op == token.QUO && isInteger(typ) {
xval = constant.ToInt(xval)
yval = constant.ToInt(yval)
op = token.QUO_ASSIGN
}
x.val = constant.BinaryOp(xval, op, yval)
......
......@@ -483,11 +483,9 @@ func pkgName(path string) string {
// (Per the go/build package dependency tests, we cannot import
// path/filepath and simply use filepath.Dir.)
func dir(path string) string {
if i := strings.LastIndexAny(path, "/\\"); i >= 0 {
path = path[:i]
if i := strings.LastIndexAny(path, `/\`); i > 0 {
return path[:i]
}
if path == "" {
path = "."
}
return path
// i <= 0
return "."
}
......@@ -153,3 +153,20 @@ func issue10260() {
make(chan I1) <- i0 /* ERROR cannot use .* in send: missing method foo */
make(chan I1) <- i2 /* ERROR cannot use .* in send: wrong type for method foo */
}
// Check that constants representable as integers are in integer form
// before being used in operations that are only defined on integers.
func issue14229() {
// from the issue
const _ = int64(-1<<63) % 1e6
// related
const (
a int = 3
b = 4.0
_ = a / b
_ = a % b
_ = b / a
_ = b % a
)
}
// Code generated by golang.org/x/tools/cmd/bundle command:
// $ bundle golang.org/x/net/http2 net/http http2
// Code generated by golang.org/x/tools/cmd/bundle.
//go:generate bundle -o h2_bundle.go -prefix http2 -import golang.org/x/net/http2/hpack=internal/golang.org/x/net/http2/hpack golang.org/x/net/http2
// Package http2 implements the HTTP/2 protocol.
//
......@@ -2331,6 +2331,10 @@ var http2isTokenTable = [127]bool{
'~': true,
}
type http2connectionStater interface {
ConnectionState() tls.ConnectionState
}
// pipe is a goroutine-safe io.Reader/io.Writer pair. It's like
// io.Pipe except there are no PipeReader/PipeWriter halves, and the
// underlying buffer is an interface. (io.Pipe is always unbuffered)
......@@ -2593,28 +2597,76 @@ func http2ConfigureServer(s *Server, conf *http2Server) error {
if http2testHookOnConn != nil {
http2testHookOnConn()
}
conf.handleConn(hs, c, h)
conf.ServeConn(c, &http2ServeConnOpts{
Handler: h,
BaseConfig: hs,
})
}
s.TLSNextProto[http2NextProtoTLS] = protoHandler
s.TLSNextProto["h2-14"] = protoHandler
return nil
}
func (srv *http2Server) handleConn(hs *Server, c net.Conn, h Handler) {
// ServeConnOpts are options for the Server.ServeConn method.
type http2ServeConnOpts struct {
// BaseConfig optionally sets the base configuration
// for values. If nil, defaults are used.
BaseConfig *Server
// Handler specifies which handler to use for processing
// requests. If nil, BaseConfig.Handler is used. If BaseConfig
// or BaseConfig.Handler is nil, http.DefaultServeMux is used.
Handler Handler
}
func (o *http2ServeConnOpts) baseConfig() *Server {
if o != nil && o.BaseConfig != nil {
return o.BaseConfig
}
return new(Server)
}
func (o *http2ServeConnOpts) handler() Handler {
if o != nil {
if o.Handler != nil {
return o.Handler
}
if o.BaseConfig != nil && o.BaseConfig.Handler != nil {
return o.BaseConfig.Handler
}
}
return DefaultServeMux
}
// ServeConn serves HTTP/2 requests on the provided connection and
// blocks until the connection is no longer readable.
//
// ServeConn starts speaking HTTP/2 assuming that c has not had any
// reads or writes. It writes its initial settings frame and expects
// to be able to read the preface and settings frame from the
// client. If c has a ConnectionState method like a *tls.Conn, the
// ConnectionState is used to verify the TLS ciphersuite and to set
// the Request.TLS field in Handlers.
//
// ServeConn does not support h2c by itself. Any h2c support must be
// implemented in terms of providing a suitably-behaving net.Conn.
//
// The opts parameter is optional. If nil, default values are used.
func (s *http2Server) ServeConn(c net.Conn, opts *http2ServeConnOpts) {
sc := &http2serverConn{
srv: srv,
hs: hs,
srv: s,
hs: opts.baseConfig(),
conn: c,
remoteAddrStr: c.RemoteAddr().String(),
bw: http2newBufferedWriter(c),
handler: h,
handler: opts.handler(),
streams: make(map[uint32]*http2stream),
readFrameCh: make(chan http2readFrameResult),
wantWriteFrameCh: make(chan http2frameWriteMsg, 8),
wroteFrameCh: make(chan http2frameWriteResult, 1),
bodyReadCh: make(chan http2bodyReadMsg),
doneServing: make(chan struct{}),
advMaxStreams: srv.maxConcurrentStreams(),
advMaxStreams: s.maxConcurrentStreams(),
writeSched: http2writeScheduler{
maxFrameSize: http2initialMaxFrameSize,
},
......@@ -2630,10 +2682,10 @@ func (srv *http2Server) handleConn(hs *Server, c net.Conn, h Handler) {
sc.hpackDecoder.SetMaxStringLength(sc.maxHeaderStringLen())
fr := http2NewFramer(sc.bw, c)
fr.SetMaxReadFrameSize(srv.maxReadFrameSize())
fr.SetMaxReadFrameSize(s.maxReadFrameSize())
sc.framer = fr
if tc, ok := c.(*tls.Conn); ok {
if tc, ok := c.(http2connectionStater); ok {
sc.tlsState = new(tls.ConnectionState)
*sc.tlsState = tc.ConnectionState()
......@@ -2646,7 +2698,7 @@ func (srv *http2Server) handleConn(hs *Server, c net.Conn, h Handler) {
}
if !srv.PermitProhibitedCipherSuites && http2isBadCipher(sc.tlsState.CipherSuite) {
if !s.PermitProhibitedCipherSuites && http2isBadCipher(sc.tlsState.CipherSuite) {
sc.rejectConn(http2ErrCodeInadequateSecurity, fmt.Sprintf("Prohibited TLS 1.2 Cipher Suite: %x", sc.tlsState.CipherSuite))
return
......@@ -4874,10 +4926,7 @@ func (t *http2Transport) NewClientConn(c net.Conn) (*http2ClientConn, error) {
cc.henc = hpack.NewEncoder(&cc.hbuf)
type connectionStater interface {
ConnectionState() tls.ConnectionState
}
if cs, ok := c.(connectionStater); ok {
if cs, ok := c.(http2connectionStater); ok {
state := cs.ConnectionState()
cc.tlsState = &state
}
......@@ -5028,7 +5077,27 @@ func (cc *http2ClientConn) responseHeaderTimeout() time.Duration {
return 0
}
// checkConnHeaders checks whether req has any invalid connection-level headers.
// per RFC 7540 section 8.1.2.2: Connection-Specific Header Fields.
// Certain headers are special-cased as okay but not transmitted later.
func http2checkConnHeaders(req *Request) error {
if v := req.Header.Get("Upgrade"); v != "" {
return errors.New("http2: invalid Upgrade request header")
}
if v := req.Header.Get("Transfer-Encoding"); (v != "" && v != "chunked") || len(req.Header["Transfer-Encoding"]) > 1 {
return errors.New("http2: invalid Transfer-Encoding request header")
}
if v := req.Header.Get("Connection"); (v != "" && v != "close" && v != "keep-alive") || len(req.Header["Connection"]) > 1 {
return errors.New("http2: invalid Connection request header")
}
return nil
}
func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) {
if err := http2checkConnHeaders(req); err != nil {
return nil, err
}
trailers, err := http2commaSeparatedTrailers(req)
if err != nil {
return nil, err
......@@ -5334,10 +5403,14 @@ func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trail
var didUA bool
for k, vv := range req.Header {
lowKey := strings.ToLower(k)
if lowKey == "host" || lowKey == "content-length" {
switch lowKey {
case "host", "content-length":
continue
}
if lowKey == "user-agent" {
case "connection", "proxy-connection", "transfer-encoding", "upgrade":
continue
case "user-agent":
didUA = true
if len(vv) < 1 {
......@@ -5445,8 +5518,9 @@ func (cc *http2ClientConn) streamByID(id uint32, andRemove bool) *http2clientStr
// clientConnReadLoop is the state owned by the clientConn's frame-reading readLoop.
type http2clientConnReadLoop struct {
cc *http2ClientConn
activeRes map[uint32]*http2clientStream // keyed by streamID
cc *http2ClientConn
activeRes map[uint32]*http2clientStream // keyed by streamID
closeWhenIdle bool
hdec *hpack.Decoder
......@@ -5503,7 +5577,7 @@ func (rl *http2clientConnReadLoop) cleanup() {
func (rl *http2clientConnReadLoop) run() error {
cc := rl.cc
closeWhenIdle := cc.t.disableKeepAlives()
rl.closeWhenIdle = cc.t.disableKeepAlives()
gotReply := false
for {
f, err := cc.fr.ReadFrame()
......@@ -5552,7 +5626,7 @@ func (rl *http2clientConnReadLoop) run() error {
if err != nil {
return err
}
if closeWhenIdle && gotReply && maybeIdle && len(rl.activeRes) == 0 {
if rl.closeWhenIdle && gotReply && maybeIdle && len(rl.activeRes) == 0 {
cc.closeIfIdle()
}
}
......@@ -5803,6 +5877,9 @@ func (rl *http2clientConnReadLoop) endStream(cs *http2clientStream) {
}
cs.bufPipe.closeWithErrorAndCode(err, code)
delete(rl.activeRes, cs.ID)
if cs.req.Close || cs.req.Header.Get("Connection") == "close" {
rl.closeWhenIdle = true
}
}
func (cs *http2clientStream) copyTrailers() {
......@@ -6064,13 +6141,18 @@ func (rt http2erringRoundTripper) RoundTrip(*Request) (*Response, error) { retur
// call gzip.NewReader on the first call to Read
type http2gzipReader struct {
body io.ReadCloser // underlying Response.Body
zr io.Reader // lazily-initialized gzip reader
zr *gzip.Reader // lazily-initialized gzip reader
zerr error // sticky error
}
func (gz *http2gzipReader) Read(p []byte) (n int, err error) {
if gz.zerr != nil {
return 0, gz.zerr
}
if gz.zr == nil {
gz.zr, err = gzip.NewReader(gz.body)
if err != nil {
gz.zerr = err
return 0, err
}
}
......
......@@ -202,10 +202,31 @@ func (s *Server) logCloseHangDebugInfo() {
// CloseClientConnections closes any open HTTP connections to the test Server.
func (s *Server) CloseClientConnections() {
var conns int
ch := make(chan bool)
s.mu.Lock()
defer s.mu.Unlock()
for c := range s.conns {
s.closeConn(c)
conns++
s.closeConnChan(c, ch)
}
s.mu.Unlock()
// Wait for outstanding closes to finish.
//
// Out of paranoia for making a late change in Go 1.6, we
// bound how long this can wait, since golang.org/issue/14291
// isn't fully understood yet. At least this should only be used
// in tests.
timer := time.NewTimer(5 * time.Second)
defer timer.Stop()
for i := 0; i < conns; i++ {
select {
case <-ch:
case <-timer.C:
// Too slow. Give up.
return
}
}
}
......@@ -267,9 +288,13 @@ func (s *Server) wrap() {
}
}
// closeConn closes c. Except on plan9, which is special. See comment below.
// closeConn closes c.
// s.mu must be held.
func (s *Server) closeConn(c net.Conn) {
func (s *Server) closeConn(c net.Conn) { s.closeConnChan(c, nil) }
// closeConnChan is like closeConn, but takes an optional channel to receive a value
// when the goroutine closing c is done.
func (s *Server) closeConnChan(c net.Conn, done chan<- bool) {
if runtime.GOOS == "plan9" {
// Go's Plan 9 net package isn't great at unblocking reads when
// their underlying TCP connections are closed. Don't trust
......@@ -278,7 +303,21 @@ func (s *Server) closeConn(c net.Conn) {
// resources if the syscall doesn't end up returning. Oh well.
s.forgetConn(c)
}
go c.Close()
// Somewhere in the chaos of https://golang.org/cl/15151 we found that
// some types of conns were blocking in Close too long (or deadlocking?)
// and we had to call Close in a goroutine. I (bradfitz) forget what
// that was at this point, but I suspect it was *tls.Conns, which
// were later fixed in https://golang.org/cl/18572, so this goroutine
// is _probably_ unnecessary now. But it's too late in Go 1.6 too remove
// it with confidence.
// TODO(bradfitz): try to remove it for Go 1.7. (golang.org/issue/14291)
go func() {
c.Close()
if done != nil {
done <- true
}
}()
}
// forgetConn removes c from the set of tracked conns and decrements it from the
......
......@@ -84,3 +84,17 @@ func TestServerCloseBlocking(t *testing.T) {
ts.Close() // test we don't hang here forever.
}
// Issue 14290
func TestServerCloseClientConnections(t *testing.T) {
var s *Server
s = NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
s.CloseClientConnections()
}))
defer s.Close()
res, err := http.Get(s.URL)
if err == nil {
res.Body.Close()
t.Fatal("Unexpected response: %#v", res)
}
}
......@@ -99,30 +99,37 @@ type Request struct {
ProtoMajor int // 1
ProtoMinor int // 0
// A header maps request lines to their values.
// If the header says
// Header contains the request header fields either received
// by the server or to be sent by the client.
//
// If a server received a request with header lines,
//
// Host: example.com
// accept-encoding: gzip, deflate
// Accept-Language: en-us
// Connection: keep-alive
// fOO: Bar
// foo: two
//
// then
//
// Header = map[string][]string{
// "Accept-Encoding": {"gzip, deflate"},
// "Accept-Language": {"en-us"},
// "Connection": {"keep-alive"},
// "Foo": {"Bar", "two"},
// }
//
// HTTP defines that header names are case-insensitive.
// The request parser implements this by canonicalizing the
// name, making the first character and any characters
// following a hyphen uppercase and the rest lowercase.
// For incoming requests, the Host header is promoted to the
// Request.Host field and removed from the Header map.
//
// For client requests certain headers are automatically
// added and may override values in Header.
// HTTP defines that header names are case-insensitive. The
// request parser implements this by using CanonicalHeaderKey,
// making the first character and any characters following a
// hyphen uppercase and the rest lowercase.
//
// See the documentation for the Request.Write method.
// For client requests, certain headers such as Content-Length
// and Connection are automatically written when needed and
// values in Header may be ignored. See the documentation
// for the Request.Write method.
Header Header
// Body is the request's body.
......@@ -152,8 +159,15 @@ type Request struct {
TransferEncoding []string
// Close indicates whether to close the connection after
// replying to this request (for servers) or after sending
// the request (for clients).
// replying to this request (for servers) or after sending this
// request and reading its response (for clients).
//
// For server requests, the HTTP server handles this automatically
// and this field is not needed by Handlers.
//
// For client requests, setting this field prevents re-use of
// TCP connections between requests to the same hosts, as if
// Transport.DisableKeepAlives were set.
Close bool
// For server requests Host specifies the host on which the
......
......@@ -1039,12 +1039,30 @@ func TestAutomaticHTTP2_Serve(t *testing.T) {
}
func TestAutomaticHTTP2_ListenAndServe(t *testing.T) {
defer afterTest(t)
defer SetTestHookServerServe(nil)
cert, err := tls.X509KeyPair(internal.LocalhostCert, internal.LocalhostKey)
if err != nil {
t.Fatal(err)
}
testAutomaticHTTP2_ListenAndServe(t, &tls.Config{
Certificates: []tls.Certificate{cert},
})
}
func TestAutomaticHTTP2_ListenAndServe_GetCertificate(t *testing.T) {
cert, err := tls.X509KeyPair(internal.LocalhostCert, internal.LocalhostKey)
if err != nil {
t.Fatal(err)
}
testAutomaticHTTP2_ListenAndServe(t, &tls.Config{
GetCertificate: func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
return &cert, nil
},
})
}
func testAutomaticHTTP2_ListenAndServe(t *testing.T, tlsConf *tls.Config) {
defer afterTest(t)
defer SetTestHookServerServe(nil)
var ok bool
var s *Server
const maxTries = 5
......@@ -1060,10 +1078,8 @@ Try:
lnc <- ln
})
s = &Server{
Addr: addr,
TLSConfig: &tls.Config{
Certificates: []tls.Certificate{cert},
},
Addr: addr,
TLSConfig: tlsConf,
}
errc := make(chan error, 1)
go func() { errc <- s.ListenAndServeTLS("", "") }()
......@@ -2416,7 +2432,7 @@ func TestCloseNotifierPipelined(t *testing.T) {
if err != nil {
t.Fatalf("error dialing: %v", err)
}
diec := make(chan bool, 2)
diec := make(chan bool, 1)
go func() {
const req = "GET / HTTP/1.1\r\nConnection: keep-alive\r\nHost: foo\r\n\r\n"
_, err = io.WriteString(conn, req+req) // two requests
......@@ -2426,13 +2442,23 @@ func TestCloseNotifierPipelined(t *testing.T) {
<-diec
conn.Close()
}()
reqs := 0
closes := 0
For:
for {
select {
case <-gotReq:
diec <- true
reqs++
if reqs > 2 {
t.Fatal("too many requests")
} else if reqs > 1 {
diec <- true
}
case <-sawClose:
break For
closes++
if closes > 1 {
break For
}
case <-time.After(5 * time.Second):
ts.CloseClientConnections()
t.Fatal("timeout")
......
......@@ -2233,10 +2233,11 @@ func ListenAndServeTLS(addr, certFile, keyFile string, handler Handler) error {
// Accepted connections are configured to enable TCP keep-alives.
//
// Filenames containing a certificate and matching private key for the
// server must be provided if the Server's TLSConfig.Certificates is
// not populated. If the certificate is signed by a certificate
// authority, the certFile should be the concatenation of the server's
// certificate, any intermediates, and the CA's certificate.
// server must be provided if neither the Server's TLSConfig.Certificates
// nor TLSConfig.GetCertificate are populated. If the certificate is
// signed by a certificate authority, the certFile should be the
// concatenation of the server's certificate, any intermediates, and
// the CA's certificate.
//
// If srv.Addr is blank, ":https" is used.
//
......@@ -2258,7 +2259,8 @@ func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
config.NextProtos = append(config.NextProtos, "http/1.1")
}
if len(config.Certificates) == 0 || certFile != "" || keyFile != "" {
configHasCert := len(config.Certificates) > 0 || config.GetCertificate != nil
if !configHasCert || certFile != "" || keyFile != "" {
var err error
config.Certificates = make([]tls.Certificate, 1)
config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
......
......@@ -163,6 +163,22 @@ func (t *Transport) onceSetNextProtoDefaults() {
return
}
if t.TLSNextProto != nil {
// This is the documented way to disable http2 on a
// Transport.
return
}
if t.TLSClientConfig != nil {
// Be conservative for now (for Go 1.6) at least and
// don't automatically enable http2 if they've
// specified a custom TLS config. Let them opt-in
// themselves via http2.ConfigureTransport so we don't
// surprise them by modifying their tls.Config.
// Issue 14275.
return
}
if t.ExpectContinueTimeout != 0 {
// Unsupported in http2, so disable http2 for now.
// Issue 13851.
return
}
t2, err := http2configureTransport(t)
......
......@@ -2885,23 +2885,34 @@ func TestTransportPrefersResponseOverWriteError(t *testing.T) {
}
func TestTransportAutomaticHTTP2(t *testing.T) {
tr := &Transport{}
_, err := tr.RoundTrip(new(Request))
if err == nil {
t.Error("expected error from RoundTrip")
}
if tr.TLSNextProto["h2"] == nil {
t.Errorf("HTTP/2 not registered.")
}
testTransportAutoHTTP(t, &Transport{}, true)
}
// Now with TLSNextProto set:
tr = &Transport{TLSNextProto: make(map[string]func(string, *tls.Conn) RoundTripper)}
_, err = tr.RoundTrip(new(Request))
func TestTransportAutomaticHTTP2_TLSNextProto(t *testing.T) {
testTransportAutoHTTP(t, &Transport{
TLSNextProto: make(map[string]func(string, *tls.Conn) RoundTripper),
}, false)
}
func TestTransportAutomaticHTTP2_TLSConfig(t *testing.T) {
testTransportAutoHTTP(t, &Transport{
TLSClientConfig: new(tls.Config),
}, false)
}
func TestTransportAutomaticHTTP2_ExpectContinueTimeout(t *testing.T) {
testTransportAutoHTTP(t, &Transport{
ExpectContinueTimeout: 1 * time.Second,
}, false)
}
func testTransportAutoHTTP(t *testing.T, tr *Transport, wantH2 bool) {
_, err := tr.RoundTrip(new(Request))
if err == nil {
t.Error("expected error from RoundTrip")
}
if tr.TLSNextProto["h2"] != nil {
t.Errorf("HTTP/2 registered, despite non-nil TLSNextProto field")
if reg := tr.TLSNextProto["h2"] != nil; reg != wantH2 {
t.Errorf("HTTP/2 registered = %v; want %v", reg, wantH2)
}
}
......
......@@ -314,20 +314,43 @@ func TestInterfacesWithNetsh(t *testing.T) {
}
}
func netshInterfaceIPv4ShowAddress(name string) ([]string, error) {
out, err := runCmd("netsh", "interface", "ipv4", "show", "address", "name=\""+name+"\"")
if err != nil {
return nil, err
}
func netshInterfaceIPv4ShowAddress(name string, netshOutput []byte) []string {
// adress information is listed like:
//
//Configuration for interface "Local Area Connection"
// DHCP enabled: Yes
// IP Address: 10.0.0.2
// Subnet Prefix: 10.0.0.0/24 (mask 255.255.255.0)
// IP Address: 10.0.0.3
// Subnet Prefix: 10.0.0.0/24 (mask 255.255.255.0)
// Default Gateway: 10.0.0.254
// Gateway Metric: 0
// InterfaceMetric: 10
//
//Configuration for interface "Loopback Pseudo-Interface 1"
// DHCP enabled: No
// IP Address: 127.0.0.1
// Subnet Prefix: 127.0.0.0/8 (mask 255.0.0.0)
// InterfaceMetric: 50
//
addrs := make([]string, 0)
var addr, subnetprefix string
lines := bytes.Split(out, []byte{'\r', '\n'})
var processingOurInterface bool
lines := bytes.Split(netshOutput, []byte{'\r', '\n'})
for _, line := range lines {
if !processingOurInterface {
if !bytes.HasPrefix(line, []byte("Configuration for interface")) {
continue
}
if !bytes.Contains(line, []byte(`"`+name+`"`)) {
continue
}
processingOurInterface = true
continue
}
if len(line) == 0 {
break
}
if bytes.Contains(line, []byte("Subnet Prefix:")) {
f := bytes.Split(line, []byte{':'})
if len(f) == 2 {
......@@ -351,18 +374,50 @@ func netshInterfaceIPv4ShowAddress(name string) ([]string, error) {
}
}
}
return addrs, nil
return addrs
}
func netshInterfaceIPv6ShowAddress(name string) ([]string, error) {
func netshInterfaceIPv6ShowAddress(name string, netshOutput []byte) []string {
// adress information is listed like:
//
//Address ::1 Parameters
//---------------------------------------------------------
//Interface Luid : Loopback Pseudo-Interface 1
//Scope Id : 0.0
//Valid Lifetime : infinite
//Preferred Lifetime : infinite
//DAD State : Preferred
//Address Type : Other
//Skip as Source : false
//
//Address XXXX::XXXX:XXXX:XXXX:XXXX%11 Parameters
//---------------------------------------------------------
//Interface Luid : Local Area Connection
//Scope Id : 0.11
//Valid Lifetime : infinite
//Preferred Lifetime : infinite
//DAD State : Preferred
//Address Type : Other
//Skip as Source : false
//
// TODO: need to test ipv6 netmask too, but netsh does not outputs it
out, err := runCmd("netsh", "interface", "ipv6", "show", "address", "interface=\""+name+"\"")
if err != nil {
return nil, err
}
var addr string
addrs := make([]string, 0)
lines := bytes.Split(out, []byte{'\r', '\n'})
lines := bytes.Split(netshOutput, []byte{'\r', '\n'})
for _, line := range lines {
if addr != "" {
if len(line) == 0 {
addr = ""
continue
}
if string(line) != "Interface Luid : "+name {
continue
}
addrs = append(addrs, addr)
addr = ""
continue
}
if !bytes.HasPrefix(line, []byte("Address")) {
continue
}
......@@ -383,9 +438,9 @@ func netshInterfaceIPv6ShowAddress(name string) ([]string, error) {
f[0] = []byte(ParseIP(string(f[0])).String())
}
addrs = append(addrs, string(bytes.ToLower(bytes.TrimSpace(f[0]))))
addr = string(bytes.ToLower(bytes.TrimSpace(f[0])))
}
return addrs, nil
return addrs
}
func TestInterfaceAddrsWithNetsh(t *testing.T) {
......@@ -395,6 +450,16 @@ func TestInterfaceAddrsWithNetsh(t *testing.T) {
if !isEnglishOS(t) {
t.Skip("English version of OS required for this test")
}
outIPV4, err := runCmd("netsh", "interface", "ipv4", "show", "address")
if err != nil {
t.Fatal(err)
}
outIPV6, err := runCmd("netsh", "interface", "ipv6", "show", "address", "level=verbose")
if err != nil {
t.Fatal(err)
}
ift, err := Interfaces()
if err != nil {
t.Fatal(err)
......@@ -431,14 +496,8 @@ func TestInterfaceAddrsWithNetsh(t *testing.T) {
}
sort.Strings(have)
want, err := netshInterfaceIPv4ShowAddress(ifi.Name)
if err != nil {
t.Fatal(err)
}
wantIPv6, err := netshInterfaceIPv6ShowAddress(ifi.Name)
if err != nil {
t.Fatal(err)
}
want := netshInterfaceIPv4ShowAddress(ifi.Name, outIPV4)
wantIPv6 := netshInterfaceIPv6ShowAddress(ifi.Name, outIPV6)
want = append(want, wantIPv6...)
sort.Strings(want)
......@@ -487,8 +546,13 @@ func TestInterfaceHardwareAddrWithGetmac(t *testing.T) {
//
//Connection Name: Bluetooth Network Connection
//Network Adapter: Bluetooth Device (Personal Area Network)
//Physical Address: XX-XX-XX-XX-XX-XX
//Transport Name: Media disconnected
//Physical Address: N/A
//Transport Name: Hardware not present
//
//Connection Name: VMware Network Adapter VMnet8
//Network Adapter: VMware Virtual Ethernet Adapter for VMnet8
//Physical Address: Disabled
//Transport Name: Disconnected
//
want := make(map[string]string)
var name string
......@@ -516,6 +580,9 @@ func TestInterfaceHardwareAddrWithGetmac(t *testing.T) {
if addr == "" {
t.Fatal("empty address on \"Physical Address\" line: %q", line)
}
if addr == "disabled" || addr == "n/a" {
continue
}
addr = strings.Replace(addr, "-", ":", -1)
want[name] = addr
name = ""
......
......@@ -135,9 +135,6 @@ func cgoCheckTypedBlock(typ *_type, src unsafe.Pointer, off, size uintptr) {
hbits := heapBitsForAddr(uintptr(src))
for i := uintptr(0); i < off+size; i += sys.PtrSize {
bits := hbits.bits()
if bits != 0 {
println(i, bits)
}
if i >= off && bits&bitPointer != 0 {
v := *(*unsafe.Pointer)(add(src, i))
if cgoIsGoPointer(v) {
......
......@@ -317,3 +317,22 @@ func TestNetpollDeadlock(t *testing.T) {
t.Fatalf("output does not start with %q:\n%s", want, output)
}
}
func TestPanicTraceback(t *testing.T) {
output := runTestProg(t, "testprog", "PanicTraceback")
want := "panic: hello"
if !strings.HasPrefix(output, want) {
t.Fatalf("output does not start with %q:\n%s", want, output)
}
// Check functions in the traceback.
fns := []string{"panic", "main.pt1.func1", "panic", "main.pt2.func1", "panic", "main.pt2", "main.pt1"}
for _, fn := range fns {
re := regexp.MustCompile(`(?m)^` + regexp.QuoteMeta(fn) + `\(.*\n`)
idx := re.FindStringIndex(output)
if idx == nil {
t.Fatalf("expected %q function in traceback:\n%s", fn, output)
}
output = output[idx[1]:]
}
}
......@@ -14,6 +14,7 @@ import (
"os/exec"
"path/filepath"
"runtime"
"strings"
"syscall"
"testing"
)
......@@ -52,6 +53,18 @@ func TestCrashDumpsAllThreads(t *testing.T) {
cmd = exec.Command(filepath.Join(dir, "a.exe"))
cmd = testEnv(cmd)
cmd.Env = append(cmd.Env, "GOTRACEBACK=crash")
// Set GOGC=off. Because of golang.org/issue/10958, the tight
// loops in the test program are not preemptible. If GC kicks
// in, it may lock up and prevent main from saying it's ready.
newEnv := []string{}
for _, s := range cmd.Env {
if !strings.HasPrefix(s, "GOGC=") {
newEnv = append(newEnv, s)
}
}
cmd.Env = append(newEnv, "GOGC=off")
var outbuf bytes.Buffer
cmd.Stdout = &outbuf
cmd.Stderr = &outbuf
......@@ -137,8 +150,8 @@ func loop(i int, c chan bool) {
func TestSignalExitStatus(t *testing.T) {
testenv.MustHaveGoBuild(t)
switch runtime.GOOS {
case "netbsd":
t.Skip("skipping on NetBSD; see https://golang.org/issue/14063")
case "netbsd", "solaris":
t.Skipf("skipping on %s; see https://golang.org/issue/14063", runtime.GOOS)
}
exe, err := buildTestProg(t, "testprog")
if err != nil {
......
......@@ -7,3 +7,4 @@
package runtime
var NewOSProc0 = newosproc0
var Mincore = mincore
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
// Export guts for testing.
package runtime
var Mmap = mmap
const ENOMEM = _ENOMEM
const MAP_ANON = _MAP_ANON
const MAP_PRIVATE = _MAP_PRIVATE
......@@ -59,9 +59,9 @@ func sysReserve(v unsafe.Pointer, n uintptr, reserved *bool) unsafe.Pointer {
return p
}
func sysMap(v unsafe.Pointer, n uintptr, reserved bool, sysStat *uint64) {
const _ENOMEM = 12
const _ENOMEM = 12
func sysMap(v unsafe.Pointer, n uintptr, reserved bool, sysStat *uint64) {
mSysStatInc(sysStat, n)
// On 64-bit, we don't actually have v reserved, so tread carefully.
......
......@@ -10,18 +10,19 @@ const (
// native_client/src/trusted/service_runtime/include/sys/errno.h
// The errors are mainly copied from Linux.
_EPERM = 1 /* Operation not permitted */
_ENOENT = 2 /* No such file or directory */
_ESRCH = 3 /* No such process */
_EINTR = 4 /* Interrupted system call */
_EIO = 5 /* I/O error */
_ENXIO = 6 /* No such device or address */
_E2BIG = 7 /* Argument list too long */
_ENOEXEC = 8 /* Exec format error */
_EBADF = 9 /* Bad file number */
_ECHILD = 10 /* No child processes */
_EAGAIN = 11 /* Try again */
_ENOMEM = 12 /* Out of memory */
_EPERM = 1 /* Operation not permitted */
_ENOENT = 2 /* No such file or directory */
_ESRCH = 3 /* No such process */
_EINTR = 4 /* Interrupted system call */
_EIO = 5 /* I/O error */
_ENXIO = 6 /* No such device or address */
_E2BIG = 7 /* Argument list too long */
_ENOEXEC = 8 /* Exec format error */
_EBADF = 9 /* Bad file number */
_ECHILD = 10 /* No child processes */
_EAGAIN = 11 /* Try again */
// _ENOMEM is defined in mem_bsd.go for nacl.
// _ENOMEM = 12 /* Out of memory */
_EACCES = 13 /* Permission denied */
_EFAULT = 14 /* Bad address */
_EBUSY = 16 /* Device or resource busy */
......
......@@ -442,7 +442,21 @@ func madvise(addr unsafe.Pointer, n uintptr, flags int32) {
//go:nosplit
func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer {
return unsafe.Pointer(sysvicall6(&libc_mmap, uintptr(addr), uintptr(n), uintptr(prot), uintptr(flags), uintptr(fd), uintptr(off)))
p, err := doMmap(uintptr(addr), n, uintptr(prot), uintptr(flags), uintptr(fd), uintptr(off))
if p == ^uintptr(0) {
return unsafe.Pointer(err)
}
return unsafe.Pointer(p)
}
//go:nosplit
func doMmap(addr, n, prot, flags, fd, off uintptr) (uintptr, uintptr) {
var libcall libcall
libcall.fn = uintptr(unsafe.Pointer(&libc_mmap))
libcall.n = 6
libcall.args = uintptr(noescape(unsafe.Pointer(&addr)))
asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&libcall))
return libcall.r1, libcall.err
}
//go:nosplit
......
......@@ -346,7 +346,7 @@ func printStackRecord(w io.Writer, stk []uintptr, allFrames bool) {
name := f.Name()
// Hide runtime.goexit and any runtime functions at the beginning.
// This is useful mainly for allocation traces.
wasPanic = name == "runtime.panic"
wasPanic = name == "runtime.gopanic"
if name == "runtime.goexit" || !show && strings.HasPrefix(name, "runtime.") {
continue
}
......
// Copyright 2016 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 runtime_test
import (
"debug/elf"
"debug/macho"
"encoding/binary"
"internal/testenv"
"io"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"testing"
)
var lldbPath string
func checkLldbPython(t *testing.T) {
cmd := exec.Command("lldb", "-P")
out, err := cmd.CombinedOutput()
if err != nil {
t.Skipf("skipping due to issue running lldb: %v\n%s", err, out)
}
lldbPath = strings.TrimSpace(string(out))
cmd = exec.Command("/usr/bin/python2.7", "-c", "import sys;sys.path.append(sys.argv[1]);import lldb; print('go lldb python support')", lldbPath)
out, err = cmd.CombinedOutput()
if err != nil {
t.Skipf("skipping due to issue running python: %v\n%s", err, out)
}
if string(out) != "go lldb python support\n" {
t.Skipf("skipping due to lack of python lldb support: %s", out)
}
if runtime.GOOS == "darwin" {
// Try to see if we have debugging permissions.
cmd = exec.Command("/usr/sbin/DevToolsSecurity", "-status")
out, err = cmd.CombinedOutput()
if err != nil {
t.Skipf("DevToolsSecurity failed: %v", err)
} else if !strings.Contains(string(out), "enabled") {
t.Skip(string(out))
}
cmd = exec.Command("/usr/bin/groups")
out, err = cmd.CombinedOutput()
if err != nil {
t.Skipf("groups failed: %v", err)
} else if !strings.Contains(string(out), "_developer") {
t.Skip("Not in _developer group")
}
}
}
const lldbHelloSource = `
package main
import "fmt"
func main() {
mapvar := make(map[string]string,5)
mapvar["abc"] = "def"
mapvar["ghi"] = "jkl"
intvar := 42
ptrvar := &intvar
fmt.Println("hi") // line 10
_ = ptrvar
}
`
const lldbScriptSource = `
import sys
sys.path.append(sys.argv[1])
import lldb
import os
TIMEOUT_SECS = 5
debugger = lldb.SBDebugger.Create()
debugger.SetAsync(True)
target = debugger.CreateTargetWithFileAndArch("a.exe", None)
if target:
print "Created target"
main_bp = target.BreakpointCreateByLocation("main.go", 10)
if main_bp:
print "Created breakpoint"
process = target.LaunchSimple(None, None, os.getcwd())
if process:
print "Process launched"
listener = debugger.GetListener()
process.broadcaster.AddListener(listener, lldb.SBProcess.eBroadcastBitStateChanged)
while True:
event = lldb.SBEvent()
if listener.WaitForEvent(TIMEOUT_SECS, event):
if lldb.SBProcess.GetRestartedFromEvent(event):
continue
state = process.GetState()
if state in [lldb.eStateUnloaded, lldb.eStateLaunching, lldb.eStateRunning]:
continue
else:
print "Timeout launching"
break
if state == lldb.eStateStopped:
for t in process.threads:
if t.GetStopReason() == lldb.eStopReasonBreakpoint:
print "Hit breakpoint"
frame = t.GetFrameAtIndex(0)
if frame:
if frame.line_entry:
print "Stopped at %s:%d" % (frame.line_entry.file.basename, frame.line_entry.line)
if frame.function:
print "Stopped in %s" % (frame.function.name,)
var = frame.FindVariable('intvar')
if var:
print "intvar = %s" % (var.GetValue(),)
else:
print "no intvar"
else:
print "Process state", state
process.Destroy()
else:
print "Failed to create target a.exe"
lldb.SBDebugger.Destroy(debugger)
sys.exit()
`
const expectedLldbOutput = `Created target
Created breakpoint
Process launched
Hit breakpoint
Stopped at main.go:10
Stopped in main.main
intvar = 42
`
func TestLldbPython(t *testing.T) {
testenv.MustHaveGoBuild(t)
if final := os.Getenv("GOROOT_FINAL"); final != "" && runtime.GOROOT() != final {
t.Skip("gdb test can fail with GOROOT_FINAL pending")
}
checkLldbPython(t)
dir, err := ioutil.TempDir("", "go-build")
if err != nil {
t.Fatalf("failed to create temp directory: %v", err)
}
defer os.RemoveAll(dir)
src := filepath.Join(dir, "main.go")
err = ioutil.WriteFile(src, []byte(lldbHelloSource), 0644)
if err != nil {
t.Fatalf("failed to create file: %v", err)
}
cmd := exec.Command("go", "build", "-gcflags", "-N -l", "-o", "a.exe")
cmd.Dir = dir
out, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("building source %v\n%s", err, out)
}
src = filepath.Join(dir, "script.py")
err = ioutil.WriteFile(src, []byte(lldbScriptSource), 0755)
if err != nil {
t.Fatalf("failed to create script: %v", err)
}
cmd = exec.Command("/usr/bin/python2.7", "script.py", lldbPath)
cmd.Dir = dir
got, _ := cmd.CombinedOutput()
if string(got) != expectedLldbOutput {
if strings.Contains(string(got), "Timeout launching") {
t.Skip("Timeout launching")
}
t.Fatalf("Unexpected lldb output:\n%s", got)
}
}
// Check that aranges are valid even when lldb isn't installed.
func TestDwarfAranges(t *testing.T) {
testenv.MustHaveGoBuild(t)
dir, err := ioutil.TempDir("", "go-build")
if err != nil {
t.Fatalf("failed to create temp directory: %v", err)
}
defer os.RemoveAll(dir)
src := filepath.Join(dir, "main.go")
err = ioutil.WriteFile(src, []byte(lldbHelloSource), 0644)
if err != nil {
t.Fatalf("failed to create file: %v", err)
}
cmd := exec.Command("go", "build", "-o", "a.exe")
cmd.Dir = dir
out, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("building source %v\n%s", err, out)
}
filename := filepath.Join(dir, "a.exe")
if f, err := elf.Open(filename); err == nil {
sect := f.Section(".debug_aranges")
if sect == nil {
t.Fatal("Missing aranges section")
}
verifyAranges(t, f.ByteOrder, sect.Open())
} else if f, err := macho.Open(filename); err == nil {
sect := f.Section("__debug_aranges")
if sect == nil {
t.Fatal("Missing aranges section")
}
verifyAranges(t, f.ByteOrder, sect.Open())
} else {
t.Skip("Not an elf or macho binary.")
}
}
func verifyAranges(t *testing.T, byteorder binary.ByteOrder, data io.ReadSeeker) {
var header struct {
UnitLength uint32 // does not include the UnitLength field
Version uint16
Offset uint32
AddressSize uint8
SegmentSize uint8
}
for {
offset, err := data.Seek(0, 1)
if err != nil {
t.Fatalf("Seek error: %v", err)
}
if err = binary.Read(data, byteorder, &header); err == io.EOF {
return
} else if err != nil {
t.Fatalf("Error reading arange header: %v", err)
}
tupleSize := int64(header.SegmentSize) + 2*int64(header.AddressSize)
lastTupleOffset := offset + int64(header.UnitLength) + 4 - tupleSize
if lastTupleOffset%tupleSize != 0 {
t.Fatalf("Invalid arange length %d, (addr %d, seg %d)", header.UnitLength, header.AddressSize, header.SegmentSize)
}
if _, err = data.Seek(lastTupleOffset, 0); err != nil {
t.Fatalf("Seek error: %v", err)
}
buf := make([]byte, tupleSize)
if n, err := data.Read(buf); err != nil || int64(n) < tupleSize {
t.Fatalf("Read error: %v", err)
}
for _, val := range buf {
if val != 0 {
t.Fatalf("Invalid terminator")
}
}
}
}
......@@ -8,6 +8,7 @@ import (
. "runtime"
"syscall"
"testing"
"unsafe"
)
var pid, tid int
......@@ -27,3 +28,15 @@ func TestLockOSThread(t *testing.T) {
t.Fatalf("pid=%d but tid=%d", pid, tid)
}
}
// Test that error values are negative. Use address 1 (a misaligned
// pointer) to get -EINVAL.
func TestMincoreErrorSign(t *testing.T) {
var dst byte
v := Mincore(unsafe.Pointer(uintptr(1)), 1, &dst)
const EINVAL = 0x16
if v != -EINVAL {
t.Errorf("mincore = %v, want %v", v, -EINVAL)
}
}
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package runtime_test
import (
"runtime"
"runtime/internal/sys"
"testing"
)
// Test that the error value returned by mmap is positive, as that is
// what the code in mem_bsd.go, mem_darwin.go, and mem_linux.go expects.
// See the uses of ENOMEM in sysMap in those files.
func TestMmapErrorSign(t *testing.T) {
p := runtime.Mmap(nil, ^uintptr(0)&^(sys.PhysPageSize-1), 0, runtime.MAP_ANON|runtime.MAP_PRIVATE, -1, 0)
// The runtime.mmap function is nosplit, but t.Errorf is not.
// Reset the pointer so that we don't get an "invalid stack
// pointer" error from t.Errorf if we call it.
v := uintptr(p)
p = nil
if v != runtime.ENOMEM {
t.Errorf("mmap = %v, want %v", v, runtime.ENOMEM)
}
}
......@@ -111,7 +111,8 @@ func TestStackGrowth(t *testing.T) {
select {
case <-done:
case <-time.After(20 * time.Second):
t.Fatal("finalizer did not run")
t.Error("finalizer did not run")
return
}
}()
wg.Wait()
......@@ -191,7 +192,6 @@ func TestStackGrowthCallback(t *testing.T) {
<-done
})
}()
wg.Wait()
}
......
......@@ -139,7 +139,7 @@ func slicebytetostringtmp(b []byte) string {
func stringtoslicebyte(buf *tmpBuf, s string) []byte {
var b []byte
if buf != nil && len(s) <= len(buf) {
b = buf[:len(s)]
b = buf[:len(s):len(s)]
} else {
b = rawbyteslice(len(s))
}
......@@ -171,7 +171,7 @@ func stringtoslicerune(buf *[tmpStringBufSize]rune, s string) []rune {
}
var a []rune
if buf != nil && n <= len(buf) {
a = buf[:n]
a = buf[:n:n]
} else {
a = rawruneslice(n)
}
......
......@@ -222,3 +222,18 @@ func TestRangeStringCast(t *testing.T) {
t.Fatalf("want 0 allocs, got %v", n)
}
}
func TestString2Slice(t *testing.T) {
// Make sure we don't return slices that expose
// an unzeroed section of stack-allocated temp buf
// between len and cap. See issue 14232.
s := "foož"
b := ([]byte)(s)
if cap(b) != 5 {
t.Errorf("want cap of 5, got %d", cap(b))
}
r := ([]rune)(s)
if cap(r) != 4 {
t.Errorf("want cap of 4, got %d", cap(r))
}
}
......@@ -269,6 +269,9 @@ TEXT runtime·mmap(SB),NOSPLIT,$-8
MOVD $SYS_mmap, R8
SVC
CMN $4095, R0
BCC 2(PC)
NEG R0,R0
MOVD R0, ret+32(FP)
RET
......
......@@ -168,6 +168,7 @@ TEXT runtime·mincore(SB),NOSPLIT,$-8-28
MOVV dst+16(FP), R6
MOVV $SYS_mincore, R2
SYSCALL
SUBVU R2, R0, R2 // caller expects negative errno
MOVW R2, ret+24(FP)
RET
......
......@@ -153,6 +153,7 @@ TEXT runtime·mincore(SB),NOSPLIT|NOFRAME,$0-28
MOVD n+8(FP), R4
MOVD dst+16(FP), R5
SYSCALL $SYS_mincore
NEG R3 // caller expects negative errno
MOVW R3, ret+24(FP)
RET
......
......@@ -227,6 +227,9 @@ TEXT runtime·mmap(SB),NOSPLIT,$32
LEAL 24(SP), AX
MOVL AX, 20(SP)
NACL_SYSCALL(SYS_mmap)
CMPL AX, $-4095
JNA 2(PC)
NEGL AX
MOVL AX, ret+24(FP)
RET
......
......@@ -29,7 +29,7 @@ func init() {
register("GoexitInPanic", GoexitInPanic)
register("PanicAfterGoexit", PanicAfterGoexit)
register("RecoveredPanicAfterGoexit", RecoveredPanicAfterGoexit)
register("PanicTraceback", PanicTraceback)
}
func SimpleDeadlock() {
......@@ -171,3 +171,21 @@ func RecoveredPanicAfterGoexit() {
}()
runtime.Goexit()
}
func PanicTraceback() {
pt1()
}
func pt1() {
defer func() {
panic("panic pt1")
}()
pt2()
}
func pt2() {
defer func() {
panic("panic pt2")
}()
panic("hello")
}
......@@ -16,7 +16,7 @@ type timer struct {
i int // heap index
// Timer wakes up at when, and then at when+period, ... (period > 0 only)
// each time calling f(now, arg) in the timer goroutine, so f must be
// each time calling f(arg, now) in the timer goroutine, so f must be
// a well-behaved function and not block.
when int64
period int64
......
......@@ -380,7 +380,11 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
if (n > 0 || flags&_TraceTrap == 0) && frame.pc > f.entry && !waspanic {
tracepc--
}
print(funcname(f), "(")
name := funcname(f)
if name == "runtime.gopanic" {
name = "panic"
}
print(name, "(")
argp := (*[100]uintptr)(unsafe.Pointer(frame.argp))
for i := uintptr(0); i < frame.arglen/sys.PtrSize; i++ {
if i >= 10 {
......@@ -617,10 +621,10 @@ func showframe(f *_func, gp *g) bool {
level, _, _ := gotraceback()
name := funcname(f)
// Special case: always show runtime.panic frame, so that we can
// Special case: always show runtime.gopanic frame, so that we can
// see where a panic started in the middle of a stack trace.
// See golang.org/issue/5832.
if name == "runtime.panic" {
if name == "runtime.gopanic" {
return true
}
......
// Copyright 2016 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 a
var S struct {
Str string `tag`
}
func F() string {
v := S
return v.Str
}
// Copyright 2016 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 b
import "./a"
func G() string {
return a.F()
}
// compiledir
// Copyright 2016 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.
// Inline function misses struct tags.
package ignored
......@@ -144,3 +144,17 @@ type T8 struct {
func f16(x []T8, y T8) []T8 {
return append(x, y) // ERROR "write barrier"
}
func t1(i interface{}) **int {
// From issue 14306, make sure we have write barriers in a type switch
// where the assigned variable escapes.
switch x := i.(type) { // ERROR "write barrier"
case *int:
return &x
}
switch y := i.(type) { // no write barrier here
case **int:
return y
}
return nil
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment