f44017549ff9c3cc5eef74ebe7276cd0dfc066b6 go1.3.3
f44017549ff9c3cc5eef74ebe7276cd0dfc066b6 release
1fdfd7dfaedb1b7702141617e621ab7328a236a1 go1.4beta1
+bffdd0cae380ce1ccf3e98ed6b6cd53fece7ba72 go1.4rc1
Ehren Kret <ehren.kret@gmail.com>
Eivind Uggedal <eivind@uggedal.com>
Elias Naur <elias.naur@gmail.com>
-Emil Hessman <c.emil.hessman@gmail.com>
+Emil Hessman <c.emil.hessman@gmail.com> <emil@hessman.se>
Eoghan Sherry <ejsherry@gmail.com>
Eric Clark <zerohp@gmail.com>
Eric Milliken <emilliken@gmail.com>
Ehren Kret <ehren.kret@gmail.com>
Eivind Uggedal <eivind@uggedal.com>
Elias Naur <elias.naur@gmail.com>
-Emil Hessman <c.emil.hessman@gmail.com>
+Emil Hessman <c.emil.hessman@gmail.com> <emil@hessman.se>
Eoghan Sherry <ejsherry@gmail.com>
Eric Clark <zerohp@gmail.com>
Eric Milliken <emilliken@gmail.com>
Nicholas Presta <nick@nickpresta.ca> <nick1presta@gmail.com>
Nicholas Sullivan <nicholas.sullivan@gmail.com>
Nicholas Waples <nwaples@gmail.com>
+Nick Cooper <nmvc@google.com>
Nick Craig-Wood <nick@craig-wood.com> <nickcw@gmail.com>
Nicolas Kaiser <nikai@nikai.net>
Nicolas Owens <mischief@offblast.org>
<h2 id="introduction">Introduction to Go 1.4</h2>
<p>
-The latest Go release, version 1.4, arrives as scheduled six months after 1.3
-and contains only one tiny language change,
-a possibly breaking change to the compiler,
-a backwards-compatible simple form of <code>for</code>-<code>range</code> loop.
+The latest Go release, version 1.4, arrives as scheduled six months after 1.3.
+It contains only one tiny language change,
+in the form of a backwards-compatible simple variant of <code>for</code>-<code>range</code> loop,
+and a possibly breaking change to the compiler involving methods on pointers-to-pointers.
The release focuses primarily on implementation work, improving the garbage collector
and preparing the ground for a fully concurrent collector to be rolled out in the
next few releases.
There are some new tools available including support in the <code>go</code> command
for build-time source code generation.
The release also adds support for ARM processors on Android and Native Client (NaCl)
-and AMD64 on Plan 9.
+and for AMD64 on Plan 9.
As always, Go 1.4 keeps the <a href="/doc/go1compat.html">promise
of compatibility</a>,
and almost everything
<ul>
+<li>
+The <a href="/pkg/archive/zip/"><code>archive/zip</code></a> package's
+<a href="/pkg/archive/zip/#Writer"><code>Writer</code></a> now supports a
+<a href="/pkg/archive/zip/#Writer.Flush"><code>Flush</code></a> method.
+</li>
+
<li>
The <a href="/pkg/compress/flate/"><code>compress/flate</code></a>,
<a href="/pkg/compress/gzip/"><code>compress/gzip</code></a>,
and <a href="/pkg/compress/zlib/"><code>compress/zlib</code></a>
packages now support a <code>Reset</code> method
for the decompressors, allowing them to reuse buffers and improve performance.
+The <a href="/pkg/compress/gzip/"><code>compress/gzip</code></a> package also has a
+<a href="/pkg/compress/gzip/#Reader.Multistream"><code>Multistream</code></a> method to control support
+for multistream files.
+</li>
+
+<li>
+The <a href="/pkg/crypto/"><code>crypto</code></a> package now has a
+<a href="/pkg/crypto/#Signer"><code>Signer</code></a> interface, implemented by the
+<code>PrivateKey</code> types in
+<a href="/pkg/crypto/ecdsa"><code>crypto/ecdsa</code></a> and
+<a href="/pkg/crypto/rsa"><code>crypto/rsa</code></a>.
</li>
<li>
those attacks.)
</li>
+<li>
+The <a href="/pkg/database/sql/"><code>database/sql</code></a> package can now list all registered
+<a href="/pkg/database/sql/#Drivers"><code>Drivers</code></a>.
+</li>
+
+<li>
+The <a href="/pkg/debug/dwarf/"><code>debug/dwarf</code></a> package now supports
+<a href="/pkg/debug/dwarf/#UnspecifiedType"><code>UnspecifiedType</code></a>s.
+</li>
+
<li>
In the <a href="/pkg/encoding/asn1/"><code>encoding/asn1</code></a> package,
optional elements with a default value will now only be omitted if they have that value.
There is no functional change.
</li>
+<li>
+The <a href="/pkg/encoding/xml/"><code>encoding/xml</code></a> package's
+<a href="/pkg/encoding/xml/#Decoder"><code>Decoder</code></a> can now report its input offset.
+</li>
+
<li>
In the <a href="/pkg/fmt/"><code>fmt</code></a> package,
formatting of pointers to maps has changed to be consistent with that of pointers
<code>&map[one:</code> <code>1]</code> rather than as a hexadecimal pointer value.
</li>
+<li>
+The <a href="/pkg/image/"><code>image</code></a> package's
+<a href="/pkg/image/#Image"><code>Image</code></a>
+implementations like
+<a href="/pkg/image/#RGBA"><code>RGBA</code></a> and
+<a href="/pkg/image/#Gray"><code>Gray</code></a> have specialized
+<a href="/pkg/image/#RGBA.RGBAAt"><code>RGBAAt</code></a> and
+<a href="/pkg/image/#Gray.GrayAt"><code>GrayAt</code></a> methods alongside the general
+<a href="/pkg/image/#Image.At"><code>At</code></a> method.
+</li>
+
+<li>
+The <a href="/pkg/image/png/"><code>image/png</code></a> package now has an
+<a href="/pkg/image/png/#Encoder"><code>Encoder</code></a>
+type to control the compression level used for encoding.
+</li>
+
+<li>
+The <a href="/pkg/math/"><code>math</code></a> package now has a
+<a href="/pkg/math/#Nextafter32"><code>Nextafter32</code><a/> function.
+</li>
+
<li>
The <a href="/pkg/net/http/"><code>net/http</code></a> package's
<a href="/pkg/net/http/#Request"><code>Request</code></a> type
now implements symbolic links on the Windows operating system
through the <a href="/pkg/os/#Symlink"><code>Symlink</code></a> function.
Other operating systems already have this functionality.
+There is also a new <a href="/pkg/os/#Unsetenv"><code>Unsetenv</code></a> function.
</li>
<li>
<!--{
"Title": "The Go Programming Language Specification",
- "Subtitle": "Version of October 27, 2014",
+ "Subtitle": "Version of November 11, 2014",
"Path": "/ref/spec"
}-->
<ol>
<li>
For a value <code>x</code> of type <code>T</code> or <code>*T</code>
-where <code>T</code> is not an interface type,
+where <code>T</code> is not a pointer or interface type,
<code>x.f</code> denotes the field or method at the shallowest depth
in <code>T</code> where there
is such an <code>f</code>.
If there is not exactly <a href="#Uniqueness_of_identifiers">one <code>f</code></a>
with shallowest depth, the selector expression is illegal.
</li>
+
<li>
-For a variable <code>x</code> of type <code>I</code> where <code>I</code>
+For a value <code>x</code> of type <code>I</code> where <code>I</code>
is an interface type, <code>x.f</code> denotes the actual method with name
-<code>f</code> of the value assigned to <code>x</code>.
+<code>f</code> of the dynamic value of <code>x</code>.
If there is no method with name <code>f</code> in the
<a href="#Method_sets">method set</a> of <code>I</code>, the selector
expression is illegal.
</li>
+
+<li>
+As an exception, if the type of <code>x</code> is a named pointer type
+and <code>(*x).f</code> is a valid selector expression denoting a field
+(but not a method), <code>x.f</code> is shorthand for <code>(*x).f</code>.
+</li>
+
<li>
In all other cases, <code>x.f</code> is illegal.
</li>
+
<li>
If <code>x</code> is of pointer type and has the value
<code>nil</code> and <code>x.f</code> denotes a struct field,
assigning to or evaluating <code>x.f</code>
causes a <a href="#Run_time_panics">run-time panic</a>.
</li>
+
<li>
If <code>x</code> is of interface type and has the value
<code>nil</code>, <a href="#Calls">calling</a> or
</li>
</ol>
-<p>
-Selectors automatically <a href="#Address_operators">dereference</a>
-pointers to structs.
-If <code>x</code> is a pointer to a struct, <code>x.y</code>
-is shorthand for <code>(*x).y</code>; if the field <code>y</code>
-is also a pointer to a struct, <code>x.y.z</code> is shorthand
-for <code>(*(*x).y).z</code>, and so on.
-If <code>x</code> contains an anonymous field of type <code>*A</code>,
-where <code>A</code> is also a struct type,
-<code>x.f</code> is shorthand for <code>(*x.A).f</code>.
-</p>
-
<p>
For example, given the declarations:
</p>
x int
}
-func (recv *T0) M0()
+func (*T0) M0()
type T1 struct {
y int
}
-func (recv T1) M1()
+func (T1) M1()
type T2 struct {
z int
*T0
}
-func (recv *T2) M2()
+func (*T2) M2()
-var p *T2 // with p != nil and p.T0 != nil
+type Q *T2
+
+var t T2 // with t.T0 != nil
+var p *T2 // with p != nil and (*p).T0 != nil
+var q Q = p
</pre>
<p>
</p>
<pre>
-p.z // (*p).z
-p.y // ((*p).T1).y
-p.x // (*(*p).T0).x
+t.z // t.z
+t.y // t.T1.y
+t.x // (*t.TO).x
+
+p.z // (*p).z
+p.y // (*p).T1.y
+p.x // (*(*p).T0).x
+
+q.x // (*(*q).T0).x (*q).x is a valid field selector
+
+p.M2() // p.M2() M2 expects *T2 receiver
+p.M1() // ((*p).T1).M1() M1 expects T1 receiver
+p.M0() // ((&(*p).T0)).M0() M0 expects *T0 receiver, see section on Calls
+</pre>
-p.M2() // (*p).M2()
-p.M1() // ((*p).T1).M1()
-p.M0() // ((*p).T0).M0()
+<p>
+but the following is invalid:
+</p>
+
+<pre>
+q.M0() // (*q).M0 is valid but not a field selector
</pre>
<tr><td>FreeBSD 8 or later</td> <td>amd64, 386, arm</td> <td>Debian GNU/kFreeBSD not supported; FreeBSD/ARM needs FreeBSD 10 or later</td></tr>
<tr><td>Linux 2.6.23 or later with glibc</td> <td>amd64, 386, arm</td> <td>CentOS/RHEL 5.x not supported; no binary distribution for ARM yet</td></tr>
<tr><td>Mac OS X 10.6 or later</td> <td>amd64, 386</td> <td>use the gcc<sup>†</sup> that comes with Xcode<sup>‡</sup></td></tr>
-<tr><td>Windows XP or later</td> <td>amd64, 386</td> <td>use MinGW gcc<sup>†</sup>. No need for cgywin or msys.</td></tr>
+<tr><td>Windows XP or later</td> <td>amd64, 386</td> <td>use MinGW gcc<sup>†</sup>. No need for cygwin or msys.</td></tr>
</table>
<p>
blogPath = "golang.org/x/blog"
toolPath = "golang.org/x/tools"
tourPath = "code.google.com/p/go-tour"
- defaultToolTag = "release-branch.go1.3"
- defaultTourTag = "release-branch.go1.3"
+ defaultToolTag = "release-branch.go1.4"
+ defaultTourTag = "release-branch.go1.4"
)
// Import paths for tool commands.
/* the mod/div runtime routines smash R12 */
if(p->as == ADIV || p->as == ADIVU || p->as == AMOD || p->as == AMODU)
- r->set.b[z] |= RtoB(12);
+ r->set.b[0] |= RtoB(12);
}
if(firstr == R)
return;
actually requires a pointer to the first element of the array.
C compilers are aware of this calling convention and adjust
the call accordingly, but Go cannot. In Go, you must pass
-the pointer to the first element explicitly: C.f(&x[0]).
+the pointer to the first element explicitly: C.f(&C.x[0]).
A few special functions convert between Go and C types
by making copies of the data. In pseudo-Go definitions:
package objfile
import (
- "debug/goobj"
+ "cmd/internal/goobj"
"fmt"
"os"
)
package main
import (
- "debug/goobj"
+ "cmd/internal/goobj"
"strconv"
"strings"
)
import (
"bytes"
- "debug/goobj"
+ "cmd/internal/goobj"
"testing"
)
package main
-import "debug/goobj"
+import "cmd/internal/goobj"
// dead removes unreachable code and data from the program.
// It is basically a mark-sweep garbage collection: traverse all the
package main
import (
- "debug/goobj"
+ "cmd/internal/goobj"
"reflect"
"strings"
"testing"
package main
import (
- "debug/goobj"
+ "cmd/internal/goobj"
)
// A layoutSection describes a single section to add to the
import (
"bytes"
- "debug/goobj"
+ "cmd/internal/goobj"
"io/ioutil"
"testing"
)
package main
import (
- "debug/goobj"
+ "cmd/internal/goobj"
"encoding/binary"
"os"
"sort"
import (
"bytes"
- "debug/goobj"
+ "cmd/internal/goobj"
"fmt"
"math/rand"
"sort"
package main
import (
- "debug/goobj"
+ "cmd/internal/goobj"
"encoding/binary"
"fmt"
"go/build"
package main
-import "debug/goobj"
+import "cmd/internal/goobj"
func (p *Prog) runtime() {
p.pclntab()
package main
import (
- "debug/goobj"
+ "cmd/internal/goobj"
"os"
"sort"
"strings"
return
}
- // TODO(rsc): Change debug/goobj to record package name as gp.Name.
+ // TODO(rsc): Change cmd/internal/goobj to record package name as gp.Name.
// TODO(rsc): If pkgpath == "main", check that gp.Name == "main".
pkg.Package = gp
for {
line, err := buf.ReadString('\n')
if err != nil {
- if line == "" || err != io.EOF {
+ if err != io.EOF {
return nil, file, err
}
+ if line == "" {
+ // end was at or past EOF; that's okay
+ break
+ }
}
if lineno >= start {
flat, cum := sumNodes(lineNodes[lineno])
"/etc/ssl/cert.pem", // OpenBSD
"/usr/local/share/certs/ca-root-nss.crt", // FreeBSD/DragonFly
"/etc/pki/tls/cacert.pem", // OpenELEC
+ "/etc/certs/ca-certificates.crt", // Solaris 11.2+
}
// Possible directories with certificate files; stop after successfully
// Predefined polynomials.
const (
- // Far and away the most common CRC-32 polynomial.
- // Used by ethernet (IEEE 802.3), v.42, fddi, gzip, zip, png, mpeg-2, ...
+ // IEEE is by far and away the most common CRC-32 polynomial.
+ // Used by ethernet (IEEE 802.3), v.42, fddi, gzip, zip, png, ...
IEEE = 0xedb88320
// Castagnoli's polynomial, used in iSCSI.
"time"
)
-// A Dir implements http.FileSystem using the native file
-// system restricted to a specific directory tree.
+// A Dir implements FileSystem using the native file system restricted to a
+// specific directory tree.
+//
+// While the FileSystem.Open method takes '/'-separated paths, a Dir's string
+// value is a filename on the native file system, not a URL, so it is separated
+// by filepath.Separator, which isn't necessarily '/'.
//
// An empty Dir is treated as ".".
type Dir string
import (
"fmt"
"log"
+ "net/http"
+ "net/http/httputil"
"net/url"
+ "strings"
)
func ExampleValues() {
fmt.Println(u)
// Output: https://google.com/search?q=golang
}
+
+func ExampleURL_opaque() {
+ // Sending a literal '%' in an HTTP request's Path
+ req := &http.Request{
+ Method: "GET",
+ Host: "example.com", // takes precendence over URL.Host
+ URL: &url.URL{
+ Host: "ignored",
+ Scheme: "https",
+ Opaque: "/%2f/",
+ },
+ Header: http.Header{
+ "User-Agent": {"godoc-example/0.1"},
+ },
+ }
+ out, err := httputil.DumpRequestOut(req, true)
+ if err != nil {
+ log.Fatal(err)
+ }
+ fmt.Println(strings.Replace(string(out), "\r", "", -1))
+ // Output:
+ // GET /%2f/ HTTP/1.1
+ // Host: example.com
+ // User-Agent: godoc-example/0.1
+ // Accept-Encoding: gzip
+ //
+}
OpEmptyMatch // matches empty string
OpLiteral // matches Runes sequence
OpCharClass // matches Runes interpreted as range pair list
- OpAnyCharNotNL // matches any character
+ OpAnyCharNotNL // matches any character except newline
OpAnyChar // matches any character
OpBeginLine // matches empty string at beginning of line
OpEndLine // matches empty string at end of line
echo '# sync -cpu=10'
go test sync -short -timeout=$(expr 120 \* $timeout_scale)s -cpu=10
-# Race detector only supported on Linux, FreeBSD and OS X,
-# and only on amd64, and only when cgo is enabled.
-case "$GOHOSTOS-$GOOS-$GOARCH-$CGO_ENABLED" in
-linux-linux-amd64-1 | freebsd-freebsd-amd64-1 | darwin-darwin-amd64-1)
- echo
- echo '# Testing race detector.'
- go test -race -i runtime/race flag
- go test -race -run=Output runtime/race
- go test -race -short flag
-esac
-
xcd() {
echo
echo '#' $1
[ "$CGO_ENABLED" != 1 ] ||
(xcd ../misc/cgo/test
# cgo tests inspect the traceback for runtime functions
+extlink=0
export GOTRACEBACK=2
go test -ldflags '-linkmode=auto' || exit 1
# linkmode=internal fails on dragonfly since errno is a TLS relocation.
openbsd-386 | openbsd-amd64)
# test linkmode=external, but __thread not supported, so skip testtls.
go test -ldflags '-linkmode=external' || exit 1
+ extlink=1
;;
darwin-386 | darwin-amd64)
# linkmode=external fails on OS X 10.6 and earlier == Darwin
# 10.8 and earlier.
case $(uname -r) in
[0-9].* | 10.*) ;;
- *) go test -ldflags '-linkmode=external' || exit 1;;
+ *)
+ go test -ldflags '-linkmode=external' || exit 1
+ extlink=1
+ ;;
esac
;;
android-arm | dragonfly-386 | dragonfly-amd64 | freebsd-386 | freebsd-amd64 | freebsd-arm | linux-386 | linux-amd64 | linux-arm | netbsd-386 | netbsd-amd64)
go test -ldflags '-linkmode=external' || exit 1
go test -ldflags '-linkmode=auto' ../testtls || exit 1
go test -ldflags '-linkmode=external' ../testtls || exit 1
+ extlink=1
case "$GOHOSTOS-$GOARCH" in
netbsd-386 | netbsd-amd64) ;; # no static linking
esac
) || exit $?
+# Race detector only supported on Linux, FreeBSD and OS X,
+# and only on amd64, and only when cgo is enabled.
+# Delayed until here so we know whether to try external linking.
+case "$GOHOSTOS-$GOOS-$GOARCH-$CGO_ENABLED" in
+linux-linux-amd64-1 | freebsd-freebsd-amd64-1 | darwin-darwin-amd64-1)
+ echo
+ echo '# Testing race detector.'
+ go test -race -i runtime/race flag os/exec
+ go test -race -run=Output runtime/race
+ go test -race -short flag os/exec
+
+ # Test with external linking; see issue 9133.
+ if [ "$extlink" = 1 ]; then
+ go test -race -short -ldflags=-linkmode=external flag os/exec
+ fi
+esac
+
# This tests cgo -cdefs. That mode is not supported,
# so it's okay if it doesn't work on some systems.
# In particular, it works badly with clang on OS X.
return nil
}
q.first = sgp.next
+ sgp.next = nil
if q.last == sgp {
q.last = nil
}
// finalizers, etc.) to a file.
// The format of the dumped file is described at
-// http://code.google.com/p/go-wiki/wiki/heapdump14
+// http://golang.org/s/go14heapdump.
package runtime
// linker-provided
var noptrdata struct{}
+var enoptrdata struct{}
+var noptrbss struct{}
var enoptrbss struct{}
// SetFinalizer sets the finalizer associated with x to f.
// func main() {
// runtime.SetFinalizer(Foo, nil)
// }
- // The segments are, in order: text, rodata, noptrdata, data, bss, noptrbss.
- if uintptr(unsafe.Pointer(&noptrdata)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&enoptrbss)) {
+ // The relevant segments are: noptrdata, data, bss, noptrbss.
+ // We cannot assume they are in any order or even contiguous,
+ // due to external linking.
+ if uintptr(unsafe.Pointer(&noptrdata)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&enoptrdata)) ||
+ uintptr(unsafe.Pointer(&data)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&edata)) ||
+ uintptr(unsafe.Pointer(&bss)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&ebss)) ||
+ uintptr(unsafe.Pointer(&noptrbss)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&enoptrbss)) {
return
}
gothrow("runtime.SetFinalizer: pointer not in allocated block")
if c := p.mcache; c != nil {
c.tiny = nil
c.tinysize = 0
+
+ // disconnect cached list before dropping it on the floor,
+ // so that a dangling ref to one entry does not pin all of them.
+ var sg, sgnext *sudog
+ for sg = c.sudogcache; sg != nil; sg = sgnext {
+ sgnext = sg.next
+ sg.next = nil
+ }
c.sudogcache = nil
}
+
// clear defer pools
for i := range p.deferpool {
+ // disconnect cached list before dropping it on the floor,
+ // so that a dangling ref to one entry does not pin all of them.
+ var d, dlink *_defer
+ for d = p.deferpool[i]; d != nil; d = dlink {
+ dlink = d.link
+ d.link = nil
+ }
p.deferpool[i] = nil
}
}
gothrow("acquireSudog: found s.elem != nil in cache")
}
c.sudogcache = s.next
+ s.next = nil
return s
}
if s.selectdone != nil {
gothrow("runtime: sudog with non-nil selectdone")
}
+ if s.next != nil {
+ gothrow("runtime: sudog with non-nil next")
+ }
+ if s.prev != nil {
+ gothrow("runtime: sudog with non-nil prev")
+ }
+ if s.waitlink != nil {
+ gothrow("runtime: sudog with non-nil waitlink")
+ }
gp := getg()
if gp.param != nil {
gothrow("runtime: releaseSudog with non-nil gp.param")
--- /dev/null
+// Copyright 2014 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 race
+// +build darwin freebsd linux
+
+package race_test
+
+import (
+ "sync/atomic"
+ "syscall"
+ "testing"
+ "unsafe"
+)
+
+// Test that race detector does not crash when accessing non-Go allocated memory (issue 9136).
+func TestNonGoMemory(t *testing.T) {
+ data, err := syscall.Mmap(-1, 0, 4096, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_ANON|syscall.MAP_PRIVATE)
+ if err != nil {
+ t.Fatalf("failed to mmap memory: %v", err)
+ }
+ p := (*uint32)(unsafe.Pointer(&data[0]))
+ atomic.AddUint32(p, 1)
+ (*p)++
+ if *p != 2 {
+ t.Fatalf("data[0] = %v, expect 2", *p)
+ }
+ syscall.Munmap(data)
+}
//go:cgo_import_static __tsan_go_atomic32_compare_exchange
//go:cgo_import_static __tsan_go_atomic64_compare_exchange
+// start/end of global data (data+bss).
+var racedatastart uintptr
+var racedataend uintptr
+
// start/end of heap for race_amd64.s
var racearenastart uintptr
var racearenaend uintptr
//go:nosplit
func isvalidaddr(addr unsafe.Pointer) bool {
return racearenastart <= uintptr(addr) && uintptr(addr) < racearenaend ||
- uintptr(unsafe.Pointer(&noptrdata)) <= uintptr(addr) && uintptr(addr) < uintptr(unsafe.Pointer(&enoptrbss))
+ racedatastart <= uintptr(addr) && uintptr(addr) < racedataend
}
//go:nosplit
racecall(&__tsan_init, uintptr(unsafe.Pointer(&racectx)), funcPC(racesymbolizethunk), 0, 0)
// Round data segment to page boundaries, because it's used in mmap().
- start := uintptr(unsafe.Pointer(&noptrdata)) &^ (_PageSize - 1)
- size := round(uintptr(unsafe.Pointer(&enoptrbss))-start, _PageSize)
+ start := ^uintptr(0)
+ end := uintptr(0)
+ if start > uintptr(unsafe.Pointer(&noptrdata)) {
+ start = uintptr(unsafe.Pointer(&noptrdata))
+ }
+ if start > uintptr(unsafe.Pointer(&data)) {
+ start = uintptr(unsafe.Pointer(&data))
+ }
+ if start > uintptr(unsafe.Pointer(&noptrbss)) {
+ start = uintptr(unsafe.Pointer(&noptrbss))
+ }
+ if start > uintptr(unsafe.Pointer(&bss)) {
+ start = uintptr(unsafe.Pointer(&bss))
+ }
+ if end < uintptr(unsafe.Pointer(&enoptrdata)) {
+ end = uintptr(unsafe.Pointer(&enoptrdata))
+ }
+ if end < uintptr(unsafe.Pointer(&edata)) {
+ end = uintptr(unsafe.Pointer(&edata))
+ }
+ if end < uintptr(unsafe.Pointer(&enoptrbss)) {
+ end = uintptr(unsafe.Pointer(&enoptrbss))
+ }
+ if end < uintptr(unsafe.Pointer(&ebss)) {
+ end = uintptr(unsafe.Pointer(&ebss))
+ }
+ size := round(end-start, _PageSize)
racecall(&__tsan_map_shadow, start, size, 0, 0)
+ racedatastart = start
+ racedataend = start + size
return racectx
}
get_tls(R12)
MOVQ g(R12), R14
MOVQ g_racectx(R14), RARG0 // goroutine context
- // Check that addr is within [arenastart, arenaend) or within [noptrdata, enoptrbss).
+ // Check that addr is within [arenastart, arenaend) or within [racedatastart, racedataend).
CMPQ RARG1, runtime·racearenastart(SB)
JB data
CMPQ RARG1, runtime·racearenaend(SB)
JB call
data:
- MOVQ $runtime·noptrdata(SB), R13
- CMPQ RARG1, R13
+ CMPQ RARG1, runtime·racedatastart(SB)
JB ret
- MOVQ $runtime·enoptrbss(SB), R13
- CMPQ RARG1, R13
+ CMPQ RARG1, runtime·racedataend(SB)
JAE ret
call:
MOVQ AX, AX // w/o this 6a miscompiles this function
MOVQ callpc+0(FP), RARG1
// void __tsan_func_enter(ThreadState *thr, void *pc);
MOVQ $__tsan_func_enter(SB), AX
+ // racecall<> preserves R15
CALL racecall<>(SB)
MOVQ R15, DX // restore function entry context
RET
TEXT racecallatomic<>(SB), NOSPLIT, $0-0
// Trigger SIGSEGV early.
MOVQ 16(SP), R12
- MOVL (R12), R12
+ MOVL (R12), R13
+ // Check that addr is within [arenastart, arenaend) or within [racedatastart, racedataend).
+ CMPQ R12, runtime·racearenastart(SB)
+ JB racecallatomic_data
+ CMPQ R12, runtime·racearenaend(SB)
+ JB racecallatomic_ok
+racecallatomic_data:
+ CMPQ R12, runtime·racedatastart(SB)
+ JB racecallatomic_ignore
+ CMPQ R12, runtime·racedataend(SB)
+ JAE racecallatomic_ignore
+racecallatomic_ok:
+ // Addr is within the good range, call the atomic function.
get_tls(R12)
MOVQ g(R12), R14
MOVQ g_racectx(R14), RARG0 // goroutine context
MOVQ 8(SP), RARG1 // caller pc
MOVQ (SP), RARG2 // pc
LEAQ 16(SP), RARG3 // arguments
+ JMP racecall<>(SB) // does not return
+racecallatomic_ignore:
+ // Addr is outside the good range.
+ // Call __tsan_go_ignore_sync_begin to ignore synchronization during the atomic op.
+ // An attempt to synchronize on the address would cause crash.
+ MOVQ AX, R15 // remember the original function
+ MOVQ $__tsan_go_ignore_sync_begin(SB), AX
+ MOVQ g(R12), R14
+ MOVQ g_racectx(R14), RARG0 // goroutine context
+ CALL racecall<>(SB)
+ MOVQ R15, AX // restore the original function
+ // Call the atomic function.
+ MOVQ g_racectx(R14), RARG0 // goroutine context
+ MOVQ 8(SP), RARG1 // caller pc
+ MOVQ (SP), RARG2 // pc
+ LEAQ 16(SP), RARG3 // arguments
+ CALL racecall<>(SB)
+ // Call __tsan_go_ignore_sync_end.
+ MOVQ $__tsan_go_ignore_sync_end(SB), AX
+ MOVQ g_racectx(R14), RARG0 // goroutine context
JMP racecall<>(SB)
// void runtime·racecall(void(*f)(...), ...)
}
}
sgnext = sglist.waitlink
+ sglist.waitlink = nil
releaseSudog(sglist)
sglist = sgnext
}
if q.last == sgp {
q.last = prevsgp
}
+ s.next = nil
return
}
l = &sgp.next
}
unlock(&s.lock)
if wake != nil {
+ wake.next = nil
goready(wake.g)
}
} else {
if wake.releasetime != 0 {
wake.releasetime = cputicks()
}
+ wake.next = nil
goready(wake.g)
n--
}
//
// func f(arg1, arg2, arg3 int) {
// pc := getcallerpc(unsafe.Pointer(&arg1))
-// sp := getcallerpc(unsafe.Pointer(&arg2))
+// sp := getcallersp(unsafe.Pointer(&arg1))
// }
//
// These two lines find the PC and SP immediately following
Setpgid bool // Set process group ID to new pid (SYSV setpgrp)
Setctty bool // Set controlling terminal to fd 0
Noctty bool // Detach fd 0 from controlling terminal
- Foreground bool // Set foreground process group to child's pid. (Implies Setpgid. Stdin should be a TTY)
- Joinpgrp int // If != 0, child's process group ID. (Setpgid must not be set)
}
// Implemented in runtime package.
if r1 != 0 {
// parent; return PID
runtime_AfterFork()
- pid = int(r1)
-
- if sys.Joinpgrp != 0 {
- // Place the child in the specified process group.
- RawSyscall(SYS_SETPGID, r1, uintptr(sys.Joinpgrp), 0)
- } else if sys.Foreground || sys.Setpgid {
- // Place the child in a new process group.
- RawSyscall(SYS_SETPGID, 0, 0, 0)
-
- if sys.Foreground {
- // Set new foreground process group.
- RawSyscall(SYS_IOCTL, uintptr(Stdin), TIOCSPGRP, uintptr(unsafe.Pointer(&pid)))
- }
- }
-
- return pid, 0
+ return int(r1), 0
}
// Fork succeeded, now in child.
}
// Set process group
- if sys.Joinpgrp != 0 {
- // Place the child in the specified process group.
- _, _, err1 = RawSyscall(SYS_SETPGID, r1, uintptr(sys.Joinpgrp), 0)
- if err1 != 0 {
- goto childerror
- }
- } else if sys.Foreground || sys.Setpgid {
- // Place the child in a new process group.
+ if sys.Setpgid {
_, _, err1 = RawSyscall(SYS_SETPGID, 0, 0, 0)
if err1 != 0 {
goto childerror
}
-
- if sys.Foreground {
- r1, _, _ = RawSyscall(SYS_GETPID, 0, 0, 0)
-
- pid := int(r1)
-
- // Set new foreground process group.
- _, _, err1 = RawSyscall(SYS_IOCTL, uintptr(Stdin), TIOCSPGRP, uintptr(unsafe.Pointer(&pid)))
- if err1 != 0 {
- goto childerror
- }
- }
}
// Chroot
Ctty int // Controlling TTY fd (Linux only)
Pdeathsig Signal // Signal that the process will get when its parent dies (Linux only)
Cloneflags uintptr // Flags for clone calls (Linux only)
- Foreground bool // Set foreground process group to child's pid. (Implies Setpgid. Stdin should be a TTY)
- Joinpgrp int // If != 0, child's process group ID. (Setpgid must not be set)
UidMappings []SysProcIDMap // User ID mappings for user namespaces.
GidMappings []SysProcIDMap // Group ID mappings for user namespaces.
}
Close(p[1])
}
- if sys.Joinpgrp != 0 {
- // Place the child in the specified process group.
- RawSyscall(SYS_SETPGID, r1, uintptr(sys.Joinpgrp), 0)
- } else if sys.Foreground || sys.Setpgid {
- // Place the child in a new process group.
- RawSyscall(SYS_SETPGID, 0, 0, 0)
-
- if sys.Foreground {
- // Set new foreground process group.
- RawSyscall(SYS_IOCTL, uintptr(Stdin), TIOCSPGRP, uintptr(unsafe.Pointer(&pid)))
- }
- }
-
return pid, 0
}
}
// Set process group
- if sys.Joinpgrp != 0 {
- // Place the child in the specified process group.
- _, _, err1 = RawSyscall(SYS_SETPGID, r1, uintptr(sys.Joinpgrp), 0)
- if err1 != 0 {
- goto childerror
- }
- } else if sys.Foreground || sys.Setpgid {
- // Place the child in a new process group.
+ if sys.Setpgid {
_, _, err1 = RawSyscall(SYS_SETPGID, 0, 0, 0)
if err1 != 0 {
goto childerror
}
-
- if sys.Foreground {
- r1, _, _ = RawSyscall(SYS_GETPID, 0, 0, 0)
-
- pid := int(r1)
-
- // Set new foreground process group.
- _, _, err1 = RawSyscall(SYS_IOCTL, uintptr(Stdin), TIOCSPGRP, uintptr(unsafe.Pointer(&pid)))
- if err1 != 0 {
- goto childerror
- }
- }
}
// Chroot
--- /dev/null
+// run
+
+// Copyright 2014 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.
+
+// Scenario that used to leak arbitrarily many SudoG structs.
+// See golang.org/issue/9110.
+
+package main
+
+import (
+ "runtime"
+ "runtime/debug"
+ "sync"
+ "time"
+)
+
+func main() {
+ debug.SetGCPercent(1000000) // only GC when we ask for GC
+
+ var stats, stats1, stats2 runtime.MemStats
+
+ release := func() {}
+ for i := 0; i < 20; i++ {
+ if i == 10 {
+ // Should be warmed up by now.
+ runtime.ReadMemStats(&stats1)
+ }
+
+ c := make(chan int)
+ for i := 0; i < 10; i++ {
+ go func() {
+ select {
+ case <-c:
+ case <-c:
+ case <-c:
+ }
+ }()
+ }
+ time.Sleep(1 * time.Millisecond)
+ release()
+
+ close(c) // let select put its sudog's into the cache
+ time.Sleep(1 * time.Millisecond)
+
+ // pick up top sudog
+ var cond1 sync.Cond
+ var mu1 sync.Mutex
+ cond1.L = &mu1
+ go func() {
+ mu1.Lock()
+ cond1.Wait()
+ mu1.Unlock()
+ }()
+ time.Sleep(1 * time.Millisecond)
+
+ // pick up next sudog
+ var cond2 sync.Cond
+ var mu2 sync.Mutex
+ cond2.L = &mu2
+ go func() {
+ mu2.Lock()
+ cond2.Wait()
+ mu2.Unlock()
+ }()
+ time.Sleep(1 * time.Millisecond)
+
+ // put top sudog back
+ cond1.Broadcast()
+ time.Sleep(1 * time.Millisecond)
+
+ // drop cache on floor
+ runtime.GC()
+
+ // release cond2 after select has gotten to run
+ release = func() {
+ cond2.Broadcast()
+ time.Sleep(1 * time.Millisecond)
+ }
+ }
+
+ runtime.GC()
+
+ runtime.ReadMemStats(&stats2)
+
+ if int(stats2.HeapObjects)-int(stats1.HeapObjects) > 20 { // normally at most 1 or 2; was 300 with leak
+ print("BUG: object leak: ", stats.HeapObjects, " -> ", stats1.HeapObjects, " -> ", stats2.HeapObjects, "\n")
+ }
+}