aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitri Shuralyov <dmitshur@golang.org>2021-02-05 19:53:15 +0000
committerDmitri Shuralyov <dmitshur@golang.org>2021-02-05 19:53:15 +0000
commit2a0dd053ecfa528adc0f763a546519a7257ed8cd (patch)
tree11af29257d714309eae879573ff3b7f6000e227c
parent79ea7a16d7e3bc36e98a4b7afd997bb315e80a1c (diff)
parentfa6752a5370735b8c2404d6de5191f2eea67130f (diff)
downloadgo-2a0dd053ecfa528adc0f763a546519a7257ed8cd.tar.gz
go-2a0dd053ecfa528adc0f763a546519a7257ed8cd.zip
[dev.boringcrypto.go1.15] all: merge go1.15.8 into dev.boringcrypto.go1.15
Change-Id: Ife009bce76e8aecb2255c69dbb5cadb61c22d2c3
-rw-r--r--doc/go1.15.html13
-rw-r--r--src/cmd/compile/internal/ssa/gen/generic.rules4
-rw-r--r--src/cmd/compile/internal/ssa/rewritegeneric.go8
-rw-r--r--src/cmd/go/internal/work/action.go3
-rw-r--r--src/cmd/go/internal/work/exec.go27
-rw-r--r--src/cmd/go/testdata/script/cgo_path.txt12
-rw-r--r--src/cmd/go/testdata/script/cgo_path_space.txt56
-rw-r--r--src/cmd/go/testdata/script/get_update_unknown_protocol.txt3
-rw-r--r--src/cmd/go/testdata/script/mod_get_fallback.txt2
-rw-r--r--src/cmd/internal/goobj2/objfile.go9
-rw-r--r--src/cmd/link/internal/ld/pe.go12
-rw-r--r--src/internal/execabs/execabs_test.go5
-rw-r--r--src/net/http/h2_bundle.go12
-rw-r--r--src/runtime/cgo/gcc_linux_386.c2
-rw-r--r--src/runtime/cgo/gcc_linux_amd64.c2
-rw-r--r--src/runtime/cgo/gcc_linux_arm.c2
-rw-r--r--src/runtime/cgo/gcc_linux_arm64.c2
-rw-r--r--src/runtime/time.go6
-rw-r--r--test/fixedbugs/issue43570.go40
19 files changed, 178 insertions, 42 deletions
diff --git a/doc/go1.15.html b/doc/go1.15.html
index c691bf3bd5b..c9997c0ca36 100644
--- a/doc/go1.15.html
+++ b/doc/go1.15.html
@@ -397,6 +397,19 @@ Do not send CLs removing the interior tags from such phrases.
documentation</a> for more information.
</p>
+<p><!-- CL 250940 -->
+ In Go 1.15.3 and later, cgo will not permit Go code to allocate an
+ undefined struct type (a C struct defined as just <code>struct
+ S;</code> or similar) on the stack or heap.
+ Go code will only be permitted to use pointers to those types.
+ Allocating an instance of such a struct and passing a pointer, or a
+ full struct value, to C code was always unsafe and unlikely to work
+ correctly; it is now forbidden.
+ The fix is to either rewrite the Go code to use only pointers, or to
+ ensure that the Go code sees the full definition of the struct by
+ including the appropriate C header file.
+</p>
+
<h3 id="commonname">X.509 CommonName deprecation</h3>
<p><!-- CL 231379 -->
diff --git a/src/cmd/compile/internal/ssa/gen/generic.rules b/src/cmd/compile/internal/ssa/gen/generic.rules
index ed5bfc81fd8..8bbe9133809 100644
--- a/src/cmd/compile/internal/ssa/gen/generic.rules
+++ b/src/cmd/compile/internal/ssa/gen/generic.rules
@@ -2404,7 +2404,7 @@
(Move {t1} [s] dst tmp1 midmem:(Move {t2} [s] tmp2 src _))
&& t1.Compare(t2) == types.CMPeq
&& isSamePtr(tmp1, tmp2)
- && isStackPtr(src)
+ && isStackPtr(src) && !isVolatile(src)
&& disjoint(src, s, tmp2, s)
&& (disjoint(src, s, dst, s) || isInlinableMemmove(dst, src, s, config))
=> (Move {t1} [s] dst src midmem)
@@ -2413,7 +2413,7 @@
(Move {t1} [s] dst tmp1 midmem:(VarDef (Move {t2} [s] tmp2 src _)))
&& t1.Compare(t2) == types.CMPeq
&& isSamePtr(tmp1, tmp2)
- && isStackPtr(src)
+ && isStackPtr(src) && !isVolatile(src)
&& disjoint(src, s, tmp2, s)
&& (disjoint(src, s, dst, s) || isInlinableMemmove(dst, src, s, config))
=> (Move {t1} [s] dst src midmem)
diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go
index 9f4e1b95bd0..6a09616aada 100644
--- a/src/cmd/compile/internal/ssa/rewritegeneric.go
+++ b/src/cmd/compile/internal/ssa/rewritegeneric.go
@@ -13666,7 +13666,7 @@ func rewriteValuegeneric_OpMove(v *Value) bool {
return true
}
// match: (Move {t1} [s] dst tmp1 midmem:(Move {t2} [s] tmp2 src _))
- // cond: t1.Compare(t2) == types.CMPeq && isSamePtr(tmp1, tmp2) && isStackPtr(src) && disjoint(src, s, tmp2, s) && (disjoint(src, s, dst, s) || isInlinableMemmove(dst, src, s, config))
+ // cond: t1.Compare(t2) == types.CMPeq && isSamePtr(tmp1, tmp2) && isStackPtr(src) && !isVolatile(src) && disjoint(src, s, tmp2, s) && (disjoint(src, s, dst, s) || isInlinableMemmove(dst, src, s, config))
// result: (Move {t1} [s] dst src midmem)
for {
s := auxIntToInt64(v.AuxInt)
@@ -13680,7 +13680,7 @@ func rewriteValuegeneric_OpMove(v *Value) bool {
t2 := auxToType(midmem.Aux)
src := midmem.Args[1]
tmp2 := midmem.Args[0]
- if !(t1.Compare(t2) == types.CMPeq && isSamePtr(tmp1, tmp2) && isStackPtr(src) && disjoint(src, s, tmp2, s) && (disjoint(src, s, dst, s) || isInlinableMemmove(dst, src, s, config))) {
+ if !(t1.Compare(t2) == types.CMPeq && isSamePtr(tmp1, tmp2) && isStackPtr(src) && !isVolatile(src) && disjoint(src, s, tmp2, s) && (disjoint(src, s, dst, s) || isInlinableMemmove(dst, src, s, config))) {
break
}
v.reset(OpMove)
@@ -13690,7 +13690,7 @@ func rewriteValuegeneric_OpMove(v *Value) bool {
return true
}
// match: (Move {t1} [s] dst tmp1 midmem:(VarDef (Move {t2} [s] tmp2 src _)))
- // cond: t1.Compare(t2) == types.CMPeq && isSamePtr(tmp1, tmp2) && isStackPtr(src) && disjoint(src, s, tmp2, s) && (disjoint(src, s, dst, s) || isInlinableMemmove(dst, src, s, config))
+ // cond: t1.Compare(t2) == types.CMPeq && isSamePtr(tmp1, tmp2) && isStackPtr(src) && !isVolatile(src) && disjoint(src, s, tmp2, s) && (disjoint(src, s, dst, s) || isInlinableMemmove(dst, src, s, config))
// result: (Move {t1} [s] dst src midmem)
for {
s := auxIntToInt64(v.AuxInt)
@@ -13708,7 +13708,7 @@ func rewriteValuegeneric_OpMove(v *Value) bool {
t2 := auxToType(midmem_0.Aux)
src := midmem_0.Args[1]
tmp2 := midmem_0.Args[0]
- if !(t1.Compare(t2) == types.CMPeq && isSamePtr(tmp1, tmp2) && isStackPtr(src) && disjoint(src, s, tmp2, s) && (disjoint(src, s, dst, s) || isInlinableMemmove(dst, src, s, config))) {
+ if !(t1.Compare(t2) == types.CMPeq && isSamePtr(tmp1, tmp2) && isStackPtr(src) && !isVolatile(src) && disjoint(src, s, tmp2, s) && (disjoint(src, s, dst, s) || isInlinableMemmove(dst, src, s, config))) {
break
}
v.reset(OpMove)
diff --git a/src/cmd/go/internal/work/action.go b/src/cmd/go/internal/work/action.go
index 03ca301bdd8..6b5f9e48079 100644
--- a/src/cmd/go/internal/work/action.go
+++ b/src/cmd/go/internal/work/action.go
@@ -56,9 +56,6 @@ type Builder struct {
id sync.Mutex
toolIDCache map[string]string // tool name -> tool ID
buildIDCache map[string]string // file name -> build ID
-
- cgoEnvOnce sync.Once
- cgoEnvCache []string
}
// NOTE: Much of Action would not need to be exported if not for test.
diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go
index f5f9951afa3..eb1efd9f824 100644
--- a/src/cmd/go/internal/work/exec.go
+++ b/src/cmd/go/internal/work/exec.go
@@ -1081,7 +1081,10 @@ func (b *Builder) vet(a *Action) error {
}
// TODO(rsc): Why do we pass $GCCGO to go vet?
- env := b.cgoEnv()
+ env := b.cCompilerEnv()
+ if cfg.BuildToolchainName == "gccgo" {
+ env = append(env, "GCCGO="+BuildToolchain.compiler())
+ }
p := a.Package
tool := VetTool
@@ -2015,24 +2018,6 @@ func (b *Builder) cCompilerEnv() []string {
return []string{"TERM=dumb"}
}
-// cgoEnv returns environment variables to set when running cgo.
-// Some of these pass through to cgo running the C compiler,
-// so it includes cCompilerEnv.
-func (b *Builder) cgoEnv() []string {
- b.cgoEnvOnce.Do(func() {
- cc, err := exec.LookPath(b.ccExe()[0])
- if err != nil || filepath.Base(cc) == cc { // reject relative path
- cc = "/missing-cc"
- }
- gccgo := GccgoBin
- if filepath.Base(gccgo) == gccgo { // reject relative path
- gccgo = "/missing-gccgo"
- }
- b.cgoEnvCache = append(b.cCompilerEnv(), "CC="+cc, "GCCGO="+gccgo)
- })
- return b.cgoEnvCache
-}
-
// mkdir makes the named directory.
func (b *Builder) Mkdir(dir string) error {
// Make Mkdir(a.Objdir) a no-op instead of an error when a.Objdir == "".
@@ -2622,7 +2607,7 @@ func (b *Builder) cgo(a *Action, cgoExe, objdir string, pcCFLAGS, pcLDFLAGS, cgo
// along to the host linker. At this point in the code, cgoLDFLAGS
// consists of the original $CGO_LDFLAGS (unchecked) and all the
// flags put together from source code (checked).
- cgoenv := b.cgoEnv()
+ cgoenv := b.cCompilerEnv()
if len(cgoLDFLAGS) > 0 {
flags := make([]string, len(cgoLDFLAGS))
for i, f := range cgoLDFLAGS {
@@ -2843,7 +2828,7 @@ func (b *Builder) dynimport(a *Action, p *load.Package, objdir, importGo, cgoExe
if p.Standard && p.ImportPath == "runtime/cgo" {
cgoflags = []string{"-dynlinker"} // record path to dynamic linker
}
- return b.run(a, p.Dir, p.ImportPath, b.cgoEnv(), cfg.BuildToolexec, cgoExe, "-dynpackage", p.Name, "-dynimport", dynobj, "-dynout", importGo, cgoflags)
+ return b.run(a, p.Dir, p.ImportPath, b.cCompilerEnv(), cfg.BuildToolexec, cgoExe, "-dynpackage", p.Name, "-dynimport", dynobj, "-dynout", importGo, cgoflags)
}
// Run SWIG on all SWIG input files.
diff --git a/src/cmd/go/testdata/script/cgo_path.txt b/src/cmd/go/testdata/script/cgo_path.txt
index 0d159984262..3eba71bc158 100644
--- a/src/cmd/go/testdata/script/cgo_path.txt
+++ b/src/cmd/go/testdata/script/cgo_path.txt
@@ -1,12 +1,20 @@
[!cgo] skip
+# Set CC explicitly to something that requires a PATH lookup.
+# Normally, the default is gcc or clang, but if CC was set during make.bash,
+# that becomes the default.
+[exec:clang] env CC=clang
+[exec:gcc] env CC=gcc
+[!exec:clang] [!exec:gcc] skip 'Unknown C compiler'
+
env GOCACHE=$WORK/gocache # Looking for compile flags, so need a clean cache.
[!windows] env PATH=.:$PATH
-[!windows] chmod 0777 p/gcc p/clang
+[!windows] chmod 0755 p/gcc p/clang
[!windows] exists -exec p/gcc p/clang
[windows] exists -exec p/gcc.bat p/clang.bat
! exists p/bug.txt
-go build -x
+! go build -x
+stderr '^cgo: exec (clang|gcc): (clang|gcc) resolves to executable in current directory \(.[/\\](clang|gcc)(.bat)?\)$'
! exists p/bug.txt
-- go.mod --
diff --git a/src/cmd/go/testdata/script/cgo_path_space.txt b/src/cmd/go/testdata/script/cgo_path_space.txt
new file mode 100644
index 00000000000..654295dc692
--- /dev/null
+++ b/src/cmd/go/testdata/script/cgo_path_space.txt
@@ -0,0 +1,56 @@
+# Check that if the PATH directory containing the C compiler has a space,
+# we can still use that compiler with cgo.
+# Verifies #43808.
+[!cgo] skip
+
+# Set CC explicitly to something that requires a PATH lookup.
+# Normally, the default is gcc or clang, but if CC was set during make.bash,
+# that becomes the default.
+[exec:clang] env CC=clang
+[exec:gcc] env CC=gcc
+[!exec:clang] [!exec:gcc] skip 'Unknown C compiler'
+
+[!windows] chmod 0755 $WORK/'program files'/clang
+[!windows] chmod 0755 $WORK/'program files'/gcc
+[!windows] exists -exec $WORK/'program files'/clang
+[!windows] exists -exec $WORK/'program files'/gcc
+[!windows] env PATH=$WORK/'program files':$PATH
+[windows] exists -exec $WORK/'program files'/gcc.bat
+[windows] exists -exec $WORK/'program files'/clang.bat
+[windows] env PATH=$WORK\'program files';%PATH%
+
+! exists $WORK/log.txt
+? go build -x
+exists $WORK/log.txt
+rm $WORK/log.txt
+
+# TODO(#41400, #43078): when CC is set explicitly, it should be allowed to
+# contain spaces separating arguments, and it should be possible to quote
+# arguments with spaces (including the path), as in CGO_CFLAGS and other
+# variables. For now, this doesn't work.
+[!windows] env CC=$WORK/'program files'/gcc
+[windows] env CC=$WORK\'program files'\gcc.bat
+! go build -x
+! exists $WORK/log.txt
+
+-- go.mod --
+module m
+
+-- m.go --
+package m
+
+// #define X 1
+import "C"
+
+-- $WORK/program files/gcc --
+#!/bin/sh
+
+echo ok >$WORK/log.txt
+-- $WORK/program files/clang --
+#!/bin/sh
+
+echo ok >$WORK/log.txt
+-- $WORK/program files/gcc.bat --
+echo ok >%WORK%\log.txt
+-- $WORK/program files/clang.bat --
+echo ok >%WORK%\log.txt
diff --git a/src/cmd/go/testdata/script/get_update_unknown_protocol.txt b/src/cmd/go/testdata/script/get_update_unknown_protocol.txt
index 85c2e24bc81..b00adea70b2 100644
--- a/src/cmd/go/testdata/script/get_update_unknown_protocol.txt
+++ b/src/cmd/go/testdata/script/get_update_unknown_protocol.txt
@@ -1,5 +1,6 @@
[!net] skip
[!exec:git] skip
+env GO111MODULE=off
# Clone the repo via HTTPS manually.
exec git clone -q https://github.com/golang/example github.com/golang/example
@@ -10,4 +11,4 @@ cd github.com/golang/example
exec git remote set-url origin xyz://github.com/golang/example
exec git config --local url.https://github.com/.insteadOf xyz://github.com/
-go get -d -u -f github.com/golang/example/hello \ No newline at end of file
+go get -d -u -f github.com/golang/example/hello
diff --git a/src/cmd/go/testdata/script/mod_get_fallback.txt b/src/cmd/go/testdata/script/mod_get_fallback.txt
index a9834a324e2..9733fa366be 100644
--- a/src/cmd/go/testdata/script/mod_get_fallback.txt
+++ b/src/cmd/go/testdata/script/mod_get_fallback.txt
@@ -6,5 +6,5 @@ env GOPROXY=https://proxy.golang.org,direct
env GOSUMDB=off
go get -x -v -d golang.org/x/tools/cmd/goimports
-stderr '# get https://proxy.golang.org/golang.org/x/tools/@latest'
+stderr '# get https://proxy.golang.org/golang.org/x/tools/@v/list'
! stderr '# get https://golang.org'
diff --git a/src/cmd/internal/goobj2/objfile.go b/src/cmd/internal/goobj2/objfile.go
index 7f728e4f766..aba9b9856e2 100644
--- a/src/cmd/internal/goobj2/objfile.go
+++ b/src/cmd/internal/goobj2/objfile.go
@@ -379,6 +379,11 @@ func (a *Aux) Write(w *Writer) { w.Bytes(a[:]) }
// for testing
func (a *Aux) fromBytes(b []byte) { copy(a[:], b) }
+// Used to construct an artifically large array type when reading an
+// item from the object file relocs section or aux sym section (needs
+// to work on 32-bit as well as 64-bit). See issue 41621.
+const huge = (1<<31 - 1) / RelocSize
+
// Referenced symbol name.
//
// Serialized format:
@@ -652,7 +657,7 @@ func (r *Reader) Reloc(i int, j int) *Reloc {
func (r *Reader) Relocs(i int) []Reloc {
off := r.RelocOff(i, 0)
n := r.NReloc(i)
- return (*[1 << 20]Reloc)(unsafe.Pointer(&r.b[off]))[:n:n]
+ return (*[huge]Reloc)(unsafe.Pointer(&r.b[off]))[:n:n]
}
// NAux returns the number of aux symbols of the i-th symbol.
@@ -678,7 +683,7 @@ func (r *Reader) Aux(i int, j int) *Aux {
func (r *Reader) Auxs(i int) []Aux {
off := r.AuxOff(i, 0)
n := r.NAux(i)
- return (*[1 << 20]Aux)(unsafe.Pointer(&r.b[off]))[:n:n]
+ return (*[huge]Aux)(unsafe.Pointer(&r.b[off]))[:n:n]
}
// DataOff returns the offset of the i-th symbol's data.
diff --git a/src/cmd/link/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go
index c9cb25dbe5b..5d68ca7d9ca 100644
--- a/src/cmd/link/internal/ld/pe.go
+++ b/src/cmd/link/internal/ld/pe.go
@@ -1515,6 +1515,18 @@ func Asmbpe(ctxt *Link) {
case sys.AMD64, sys.I386, sys.ARM:
}
+ if rsrcsym != 0 {
+ // The resource symbol may have been copied to the mmap'd
+ // output buffer. If so, certain conditions can cause that
+ // mmap'd output buffer to be munmap'd before we get a chance
+ // to use it. To avoid any issues we copy the data to the heap
+ // when the resource symbol exists.
+ rsrc := ctxt.loader.Syms[rsrcsym]
+ data := make([]byte, len(rsrc.P))
+ copy(data, rsrc.P)
+ rsrc.P = data
+ }
+
t := pefile.addSection(".text", int(Segtext.Length), int(Segtext.Length))
t.characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ
if ctxt.LinkMode == LinkExternal {
diff --git a/src/internal/execabs/execabs_test.go b/src/internal/execabs/execabs_test.go
index a0b88dd2a0c..1a197b8701a 100644
--- a/src/internal/execabs/execabs_test.go
+++ b/src/internal/execabs/execabs_test.go
@@ -7,6 +7,7 @@ package execabs
import (
"context"
"fmt"
+ "internal/testenv"
"io/ioutil"
"os"
"os/exec"
@@ -30,6 +31,8 @@ func TestFixCmd(t *testing.T) {
}
func TestCommand(t *testing.T) {
+ testenv.MustHaveExec(t)
+
for _, cmd := range []func(string) *Cmd{
func(s string) *Cmd { return Command(s) },
func(s string) *Cmd { return CommandContext(context.Background(), s) },
@@ -71,6 +74,8 @@ func TestCommand(t *testing.T) {
}
func TestLookPath(t *testing.T) {
+ testenv.MustHaveExec(t)
+
tmpDir, err := ioutil.TempDir("", "execabs-test")
if err != nil {
t.Fatalf("ioutil.TempDir failed: %s", err)
diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go
index b03b84d2f30..678c6eb9d4a 100644
--- a/src/net/http/h2_bundle.go
+++ b/src/net/http/h2_bundle.go
@@ -7592,6 +7592,9 @@ func (cc *http2ClientConn) roundTrip(req *Request) (res *Response, gotErrAfterRe
// we can keep it.
bodyWriter.cancel()
cs.abortRequestBodyWrite(http2errStopReqBodyWrite)
+ if hasBody && !bodyWritten {
+ <-bodyWriter.resc
+ }
}
if re.err != nil {
cc.forgetStreamID(cs.ID)
@@ -7612,6 +7615,7 @@ func (cc *http2ClientConn) roundTrip(req *Request) (res *Response, gotErrAfterRe
} else {
bodyWriter.cancel()
cs.abortRequestBodyWrite(http2errStopReqBodyWriteAndCancel)
+ <-bodyWriter.resc
}
cc.forgetStreamID(cs.ID)
return nil, cs.getStartedWrite(), http2errTimeout
@@ -7621,6 +7625,7 @@ func (cc *http2ClientConn) roundTrip(req *Request) (res *Response, gotErrAfterRe
} else {
bodyWriter.cancel()
cs.abortRequestBodyWrite(http2errStopReqBodyWriteAndCancel)
+ <-bodyWriter.resc
}
cc.forgetStreamID(cs.ID)
return nil, cs.getStartedWrite(), ctx.Err()
@@ -7630,6 +7635,7 @@ func (cc *http2ClientConn) roundTrip(req *Request) (res *Response, gotErrAfterRe
} else {
bodyWriter.cancel()
cs.abortRequestBodyWrite(http2errStopReqBodyWriteAndCancel)
+ <-bodyWriter.resc
}
cc.forgetStreamID(cs.ID)
return nil, cs.getStartedWrite(), http2errRequestCanceled
@@ -7639,6 +7645,7 @@ func (cc *http2ClientConn) roundTrip(req *Request) (res *Response, gotErrAfterRe
// forgetStreamID.
return nil, cs.getStartedWrite(), cs.resetErr
case err := <-bodyWriter.resc:
+ bodyWritten = true
// Prefer the read loop's response, if available. Issue 16102.
select {
case re := <-readLoopResCh:
@@ -7649,7 +7656,6 @@ func (cc *http2ClientConn) roundTrip(req *Request) (res *Response, gotErrAfterRe
cc.forgetStreamID(cs.ID)
return nil, cs.getStartedWrite(), err
}
- bodyWritten = true
if d := cc.responseHeaderTimeout(); d != 0 {
timer := time.NewTimer(d)
defer timer.Stop()
@@ -9060,7 +9066,9 @@ func (t *http2Transport) getBodyWriterState(cs *http2clientStream, body io.Reade
func (s http2bodyWriterState) cancel() {
if s.timer != nil {
- s.timer.Stop()
+ if s.timer.Stop() {
+ s.resc <- nil
+ }
}
}
diff --git a/src/runtime/cgo/gcc_linux_386.c b/src/runtime/cgo/gcc_linux_386.c
index ece9f933c56..70c942aeb84 100644
--- a/src/runtime/cgo/gcc_linux_386.c
+++ b/src/runtime/cgo/gcc_linux_386.c
@@ -12,7 +12,7 @@ static void *threadentry(void*);
static void (*setg_gcc)(void*);
// This will be set in gcc_android.c for android-specific customization.
-void (*x_cgo_inittls)(void **tlsg, void **tlsbase);
+void (*x_cgo_inittls)(void **tlsg, void **tlsbase) __attribute__((common));
void
x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase)
diff --git a/src/runtime/cgo/gcc_linux_amd64.c b/src/runtime/cgo/gcc_linux_amd64.c
index 9134e0df920..f2bf6482cb5 100644
--- a/src/runtime/cgo/gcc_linux_amd64.c
+++ b/src/runtime/cgo/gcc_linux_amd64.c
@@ -14,7 +14,7 @@ static void* threadentry(void*);
static void (*setg_gcc)(void*);
// This will be set in gcc_android.c for android-specific customization.
-void (*x_cgo_inittls)(void **tlsg, void **tlsbase);
+void (*x_cgo_inittls)(void **tlsg, void **tlsbase) __attribute__((common));
void
x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase)
diff --git a/src/runtime/cgo/gcc_linux_arm.c b/src/runtime/cgo/gcc_linux_arm.c
index 61855b96b22..5bc0fee90d4 100644
--- a/src/runtime/cgo/gcc_linux_arm.c
+++ b/src/runtime/cgo/gcc_linux_arm.c
@@ -10,7 +10,7 @@
static void *threadentry(void*);
-void (*x_cgo_inittls)(void **tlsg, void **tlsbase);
+void (*x_cgo_inittls)(void **tlsg, void **tlsbase) __attribute__((common));
static void (*setg_gcc)(void*);
void
diff --git a/src/runtime/cgo/gcc_linux_arm64.c b/src/runtime/cgo/gcc_linux_arm64.c
index 261c884ac95..17ff274fbbe 100644
--- a/src/runtime/cgo/gcc_linux_arm64.c
+++ b/src/runtime/cgo/gcc_linux_arm64.c
@@ -12,7 +12,7 @@
static void *threadentry(void*);
-void (*x_cgo_inittls)(void **tlsg, void **tlsbase);
+void (*x_cgo_inittls)(void **tlsg, void **tlsbase) __attribute__((common));
static void (*setg_gcc)(void*);
void
diff --git a/src/runtime/time.go b/src/runtime/time.go
index fdb5066b24f..ec3eae9ccad 100644
--- a/src/runtime/time.go
+++ b/src/runtime/time.go
@@ -594,8 +594,14 @@ func moveTimers(pp *p, timers []*timer) {
for {
switch s := atomic.Load(&t.status); s {
case timerWaiting:
+ if !atomic.Cas(&t.status, s, timerMoving) {
+ continue
+ }
t.pp = 0
doaddtimer(pp, t)
+ if !atomic.Cas(&t.status, timerMoving, timerWaiting) {
+ badTimer()
+ }
break loop
case timerModifiedEarlier, timerModifiedLater:
if !atomic.Cas(&t.status, s, timerMoving) {
diff --git a/test/fixedbugs/issue43570.go b/test/fixedbugs/issue43570.go
new file mode 100644
index 00000000000..d073fde5f6b
--- /dev/null
+++ b/test/fixedbugs/issue43570.go
@@ -0,0 +1,40 @@
+// run
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "fmt"
+
+type T [8]*int
+
+//go:noinline
+func f(x int) T {
+ return T{}
+}
+
+//go:noinline
+func g(x int, t T) {
+ if t != (T{}) {
+ panic(fmt.Sprintf("bad: %v", t))
+ }
+}
+
+func main() {
+ const N = 10000
+ var q T
+ func() {
+ for i := 0; i < N; i++ {
+ q = f(0)
+ g(0, q)
+ sink = make([]byte, 1024)
+ }
+ }()
+ // Note that the closure is a trick to get the write to q to be a
+ // write to a pointer that is known to be non-nil and requires
+ // a write barrier.
+}
+
+var sink []byte