mirror of
https://github.com/golang/go
synced 2024-11-02 11:50:30 +00:00
840965f8d7
Currently the runtime fails to clear a G's stack barriers in gfput if the G's stack allocation is _FixedStack bytes. This causes the runtime to panic if the following sequence of events happens: 1) The runtime installs stack barriers on a G. 2) The G exits by calling runtime.Goexit. Since this does not necessarily return through the stack barriers installed on the G, there may still be untriggered stack barriers left on the G's stack in recorded in g.stkbar. 3) The runtime calls gfput to add the exiting G to the free pool. If the G's stack allocation is _FixedStack bytes, we fail to clear g.stkbar. 4) A new G starts and allocates the G that was just added to the free pool. 5) The new G begins to execute and overwrites the stack slots that had stack barriers in them. 6) The garbage collector enters mark termination, attempts to remove stack barriers from the new G, and finds that they've been overwritten. Fix this by clearing the stack barriers in gfput in the case where it reuses the stack. Fixes #11256. Change-Id: I377c44258900e6bcc2d4b3451845814a8eeb2bcf Reviewed-on: https://go-review.googlesource.com/11461 Reviewed-by: Alex Brainman <alex.brainman@gmail.com> Reviewed-by: Russ Cox <rsc@golang.org>
53 lines
1.1 KiB
Go
53 lines
1.1 KiB
Go
// run
|
|
|
|
// Copyright 2015 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// Test that stack barriers are reset when a goroutine exits without
|
|
// returning.
|
|
|
|
package main
|
|
|
|
import (
|
|
"runtime"
|
|
"sync/atomic"
|
|
"time"
|
|
)
|
|
|
|
func main() {
|
|
// Let the garbage collector run concurrently.
|
|
runtime.GOMAXPROCS(2)
|
|
|
|
var x [100][]byte
|
|
|
|
for i := range x {
|
|
var done int32
|
|
|
|
go func() {
|
|
// Use enough stack to get stack barriers, but
|
|
// not so much that we go over _FixedStack.
|
|
// There's a very narrow window here on most
|
|
// OSs, so we basically can't do anything (not
|
|
// even a time.Sleep or a channel).
|
|
var buf [1024]byte
|
|
buf[0]++
|
|
for atomic.LoadInt32(&done) == 0 {
|
|
runtime.Gosched()
|
|
}
|
|
atomic.StoreInt32(&done, 0)
|
|
// Exit without unwinding stack barriers.
|
|
runtime.Goexit()
|
|
}()
|
|
|
|
// Generate some garbage.
|
|
x[i] = make([]byte, 1024*1024)
|
|
|
|
// Give GC some time to install stack barriers in the G.
|
|
time.Sleep(50 * time.Microsecond)
|
|
atomic.StoreInt32(&done, 1)
|
|
for atomic.LoadInt32(&done) == 1 {
|
|
runtime.Gosched()
|
|
}
|
|
}
|
|
}
|