diff options
Diffstat (limited to 'src')
36 files changed, 230 insertions, 119 deletions
diff --git a/src/cmd/5g/reg.c b/src/cmd/5g/reg.c index 56ea7826e..611310f12 100644 --- a/src/cmd/5g/reg.c +++ b/src/cmd/5g/reg.c @@ -230,7 +230,7 @@ regopt(Prog *firstp) /* 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; diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go index 69c7ce893..6179c7afd 100644 --- a/src/cmd/cgo/doc.go +++ b/src/cmd/cgo/doc.go @@ -152,7 +152,7 @@ In C, a function argument written as a fixed size array 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: diff --git a/src/debug/goobj/read.go b/src/cmd/internal/goobj/read.go index 79a83e59a..79a83e59a 100644 --- a/src/debug/goobj/read.go +++ b/src/cmd/internal/goobj/read.go diff --git a/src/debug/goobj/read_test.go b/src/cmd/internal/goobj/read_test.go index cc991e5d9..cc991e5d9 100644 --- a/src/debug/goobj/read_test.go +++ b/src/cmd/internal/goobj/read_test.go diff --git a/src/cmd/internal/objfile/goobj.go b/src/cmd/internal/objfile/goobj.go index a1d773023..6b1607a17 100644 --- a/src/cmd/internal/objfile/goobj.go +++ b/src/cmd/internal/objfile/goobj.go @@ -7,7 +7,7 @@ package objfile import ( - "debug/goobj" + "cmd/internal/goobj" "fmt" "os" ) diff --git a/src/cmd/link/auto.go b/src/cmd/link/auto.go index f9228e8ca..21f6d6082 100644 --- a/src/cmd/link/auto.go +++ b/src/cmd/link/auto.go @@ -10,7 +10,7 @@ package main import ( - "debug/goobj" + "cmd/internal/goobj" "strconv" "strings" ) diff --git a/src/cmd/link/auto_test.go b/src/cmd/link/auto_test.go index 27f8e2b96..f99e097a9 100644 --- a/src/cmd/link/auto_test.go +++ b/src/cmd/link/auto_test.go @@ -13,7 +13,7 @@ package main import ( "bytes" - "debug/goobj" + "cmd/internal/goobj" "testing" ) diff --git a/src/cmd/link/dead.go b/src/cmd/link/dead.go index e1e775eb3..ee23a61f8 100644 --- a/src/cmd/link/dead.go +++ b/src/cmd/link/dead.go @@ -6,7 +6,7 @@ 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 diff --git a/src/cmd/link/dead_test.go b/src/cmd/link/dead_test.go index 2e179b453..eb34d0580 100644 --- a/src/cmd/link/dead_test.go +++ b/src/cmd/link/dead_test.go @@ -5,7 +5,7 @@ package main import ( - "debug/goobj" + "cmd/internal/goobj" "reflect" "strings" "testing" diff --git a/src/cmd/link/layout.go b/src/cmd/link/layout.go index 149ebced0..d5c291e25 100644 --- a/src/cmd/link/layout.go +++ b/src/cmd/link/layout.go @@ -7,7 +7,7 @@ package main import ( - "debug/goobj" + "cmd/internal/goobj" ) // A layoutSection describes a single section to add to the diff --git a/src/cmd/link/link_test.go b/src/cmd/link/link_test.go index 984796784..b5ae15fc7 100644 --- a/src/cmd/link/link_test.go +++ b/src/cmd/link/link_test.go @@ -6,7 +6,7 @@ package main import ( "bytes" - "debug/goobj" + "cmd/internal/goobj" "io/ioutil" "testing" ) diff --git a/src/cmd/link/pclntab.go b/src/cmd/link/pclntab.go index 232d586bf..2d131781f 100644 --- a/src/cmd/link/pclntab.go +++ b/src/cmd/link/pclntab.go @@ -7,7 +7,7 @@ package main import ( - "debug/goobj" + "cmd/internal/goobj" "encoding/binary" "os" "sort" diff --git a/src/cmd/link/pclntab_test.go b/src/cmd/link/pclntab_test.go index 19953f579..ea8080674 100644 --- a/src/cmd/link/pclntab_test.go +++ b/src/cmd/link/pclntab_test.go @@ -6,7 +6,7 @@ package main import ( "bytes" - "debug/goobj" + "cmd/internal/goobj" "fmt" "math/rand" "sort" diff --git a/src/cmd/link/prog.go b/src/cmd/link/prog.go index a52b5ff9b..77fb1ece5 100644 --- a/src/cmd/link/prog.go +++ b/src/cmd/link/prog.go @@ -5,7 +5,7 @@ package main import ( - "debug/goobj" + "cmd/internal/goobj" "encoding/binary" "fmt" "go/build" diff --git a/src/cmd/link/runtime.go b/src/cmd/link/runtime.go index b0c1ac98a..acda2d24d 100644 --- a/src/cmd/link/runtime.go +++ b/src/cmd/link/runtime.go @@ -7,7 +7,7 @@ package main -import "debug/goobj" +import "cmd/internal/goobj" func (p *Prog) runtime() { p.pclntab() diff --git a/src/cmd/link/scan.go b/src/cmd/link/scan.go index 0720e039b..7feb0d890 100644 --- a/src/cmd/link/scan.go +++ b/src/cmd/link/scan.go @@ -11,7 +11,7 @@ package main import ( - "debug/goobj" + "cmd/internal/goobj" "os" "sort" "strings" @@ -69,7 +69,7 @@ func (p *Prog) scanFile(pkgpath string, file string) { 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 diff --git a/src/cmd/pprof/internal/report/source.go b/src/cmd/pprof/internal/report/source.go index 57300dd91..73ae1b4ea 100644 --- a/src/cmd/pprof/internal/report/source.go +++ b/src/cmd/pprof/internal/report/source.go @@ -358,9 +358,13 @@ func getFunctionSource(fun, file string, fns nodes, start, end int) (nodes, stri 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]) diff --git a/src/crypto/x509/root_unix.go b/src/crypto/x509/root_unix.go index c65f626ac..f77d6c0c5 100644 --- a/src/crypto/x509/root_unix.go +++ b/src/crypto/x509/root_unix.go @@ -16,6 +16,7 @@ var certFiles = []string{ "/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 diff --git a/src/hash/crc32/crc32.go b/src/hash/crc32/crc32.go index a2a21a06f..6a6b9473b 100644 --- a/src/hash/crc32/crc32.go +++ b/src/hash/crc32/crc32.go @@ -17,8 +17,8 @@ const Size = 4 // 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. diff --git a/src/net/http/fs.go b/src/net/http/fs.go index 7bd777b71..e322f710a 100644 --- a/src/net/http/fs.go +++ b/src/net/http/fs.go @@ -22,8 +22,12 @@ import ( "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 diff --git a/src/net/url/example_test.go b/src/net/url/example_test.go index 56c5dc696..e55c1aa16 100644 --- a/src/net/url/example_test.go +++ b/src/net/url/example_test.go @@ -7,7 +7,10 @@ package url_test import ( "fmt" "log" + "net/http" + "net/http/httputil" "net/url" + "strings" ) func ExampleValues() { @@ -39,3 +42,30 @@ func ExampleURL() { 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 + // +} diff --git a/src/regexp/syntax/regexp.go b/src/regexp/syntax/regexp.go index 329a90e01..cea7d9e04 100644 --- a/src/regexp/syntax/regexp.go +++ b/src/regexp/syntax/regexp.go @@ -39,7 +39,7 @@ const ( 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 diff --git a/src/run.bash b/src/run.bash index d9b985fd1..6b9ecc33c 100755 --- a/src/run.bash +++ b/src/run.bash @@ -64,17 +64,6 @@ echo 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 @@ -120,6 +109,7 @@ go run $GOROOT/test/run.go - . || exit 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. @@ -128,19 +118,24 @@ case "$GOHOSTOS-$GOARCH" in 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 @@ -164,6 +159,23 @@ android-arm | dragonfly-386 | dragonfly-amd64 | freebsd-386 | freebsd-amd64 | fr 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. diff --git a/src/runtime/chan.go b/src/runtime/chan.go index bb0110f94..330422ad0 100644 --- a/src/runtime/chan.go +++ b/src/runtime/chan.go @@ -630,6 +630,7 @@ func (q *waitq) dequeue() *sudog { return nil } q.first = sgp.next + sgp.next = nil if q.last == sgp { q.last = nil } diff --git a/src/runtime/heapdump.go b/src/runtime/heapdump.go index c942e0163..0c1a60c8b 100644 --- a/src/runtime/heapdump.go +++ b/src/runtime/heapdump.go @@ -7,7 +7,7 @@ // 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 diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index 20cb6818d..d73d1ba6a 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -477,6 +477,8 @@ func GC() { // linker-provided var noptrdata struct{} +var enoptrdata struct{} +var noptrbss struct{} var enoptrbss struct{} // SetFinalizer sets the finalizer associated with x to f. @@ -553,8 +555,13 @@ func SetFinalizer(obj interface{}, finalizer interface{}) { // 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") diff --git a/src/runtime/mgc0.go b/src/runtime/mgc0.go index 6d4ae61c1..38406f33a 100644 --- a/src/runtime/mgc0.go +++ b/src/runtime/mgc0.go @@ -51,10 +51,26 @@ func clearpools() { 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 } } diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 05ecb3d9e..50920afe8 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -165,6 +165,7 @@ func acquireSudog() *sudog { gothrow("acquireSudog: found s.elem != nil in cache") } c.sudogcache = s.next + s.next = nil return s } @@ -190,6 +191,15 @@ func releaseSudog(s *sudog) { 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") diff --git a/src/runtime/race/race_unix_test.go b/src/runtime/race/race_unix_test.go new file mode 100644 index 000000000..84f0acece --- /dev/null +++ b/src/runtime/race/race_unix_test.go @@ -0,0 +1,30 @@ +// 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) +} diff --git a/src/runtime/race1.go b/src/runtime/race1.go index 4c580429c..2ec2bee65 100644 --- a/src/runtime/race1.go +++ b/src/runtime/race1.go @@ -81,6 +81,10 @@ var __tsan_go_ignore_sync_end byte //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 @@ -99,7 +103,7 @@ func racecall(*byte, uintptr, uintptr, uintptr, 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 @@ -113,9 +117,36 @@ func raceinit() uintptr { 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 } diff --git a/src/runtime/race_amd64.s b/src/runtime/race_amd64.s index a7f44870a..d54d9798f 100644 --- a/src/runtime/race_amd64.s +++ b/src/runtime/race_amd64.s @@ -139,17 +139,15 @@ TEXT racecalladdr<>(SB), NOSPLIT, $0-0 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 @@ -167,6 +165,7 @@ TEXT runtime·racefuncenter(SB), NOSPLIT, $0-8 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 @@ -307,13 +306,45 @@ TEXT sync∕atomic·CompareAndSwapPointer(SB), NOSPLIT, $0-0 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)(...), ...) diff --git a/src/runtime/select.go b/src/runtime/select.go index fe9178763..6717b9395 100644 --- a/src/runtime/select.go +++ b/src/runtime/select.go @@ -404,6 +404,7 @@ loop: } } sgnext = sglist.waitlink + sglist.waitlink = nil releaseSudog(sglist) sglist = sgnext } @@ -641,6 +642,7 @@ func (q *waitq) dequeueSudoG(s *sudog) { if q.last == sgp { q.last = prevsgp } + s.next = nil return } l = &sgp.next diff --git a/src/runtime/sema.go b/src/runtime/sema.go index d2a028c01..26dbd30ea 100644 --- a/src/runtime/sema.go +++ b/src/runtime/sema.go @@ -201,6 +201,7 @@ func syncsemacquire(s *syncSema) { } unlock(&s.lock) if wake != nil { + wake.next = nil goready(wake.g) } } else { @@ -242,6 +243,7 @@ func syncsemrelease(s *syncSema, n uint32) { if wake.releasetime != 0 { wake.releasetime = cputicks() } + wake.next = nil goready(wake.g) n-- } diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go index 217307a1e..aa7577cf9 100644 --- a/src/runtime/stubs.go +++ b/src/runtime/stubs.go @@ -154,7 +154,7 @@ func setcallerpc(argp unsafe.Pointer, pc uintptr) // // 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 diff --git a/src/syscall/exec_bsd.go b/src/syscall/exec_bsd.go index 7c2c1f707..ff78f197f 100644 --- a/src/syscall/exec_bsd.go +++ b/src/syscall/exec_bsd.go @@ -19,8 +19,6 @@ type SysProcAttr struct { 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. @@ -81,22 +79,7 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr 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. @@ -118,30 +101,11 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr } // 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 diff --git a/src/syscall/exec_linux.go b/src/syscall/exec_linux.go index 72e2f0b69..042c20a46 100644 --- a/src/syscall/exec_linux.go +++ b/src/syscall/exec_linux.go @@ -29,8 +29,6 @@ type SysProcAttr struct { 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. } @@ -105,19 +103,6 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr 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 } @@ -179,30 +164,11 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr } // 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 |