mirror of
https://github.com/golang/go
synced 2024-11-26 23:31:24 -07:00
runtime: scan defer closure in stack scan
With stack objects, when we scan the stack, it scans defers with tracebackdefers, but it seems to me that tracebackdefers doesn't include the func value itself, which could be a stack allocated closure. Scan it explicitly. Alternatively, we can change tracebackdefers to include the func value, which in turn needs to change the type of stkframe. Fixes #30453. Change-Id: I55a6e43264d6952ab2fa5c638bebb89fdc410e2b Reviewed-on: https://go-review.googlesource.com/c/164118 Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
parent
c04e47f821
commit
4f4c2a79d4
@ -713,6 +713,13 @@ func scanstack(gp *g, gcw *gcWork) {
|
|||||||
// Find additional pointers that point into the stack from the heap.
|
// Find additional pointers that point into the stack from the heap.
|
||||||
// Currently this includes defers and panics. See also function copystack.
|
// Currently this includes defers and panics. See also function copystack.
|
||||||
tracebackdefers(gp, scanframe, nil)
|
tracebackdefers(gp, scanframe, nil)
|
||||||
|
for d := gp._defer; d != nil; d = d.link {
|
||||||
|
// tracebackdefers above does not scan the func value, which could
|
||||||
|
// be a stack allocated closure. See issue 30453.
|
||||||
|
if d.fn != nil {
|
||||||
|
scanblock(uintptr(unsafe.Pointer(&d.fn)), sys.PtrSize, &oneptrmask[0], gcw, &state)
|
||||||
|
}
|
||||||
|
}
|
||||||
if gp._panic != nil {
|
if gp._panic != nil {
|
||||||
state.putPtr(uintptr(unsafe.Pointer(gp._panic)))
|
state.putPtr(uintptr(unsafe.Pointer(gp._panic)))
|
||||||
}
|
}
|
||||||
|
@ -787,3 +787,11 @@ func TestTracebackAncestors(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test that defer closure is correctly scanned when the stack is scanned.
|
||||||
|
func TestDeferLiveness(t *testing.T) {
|
||||||
|
output := runTestProg(t, "testprog", "DeferLiveness", "GODEBUG=clobberfree=1")
|
||||||
|
if output != "" {
|
||||||
|
t.Errorf("output:\n%s\n\nwant no output", output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
23
src/runtime/testdata/testprog/gc.go
vendored
23
src/runtime/testdata/testprog/gc.go
vendored
@ -18,6 +18,7 @@ func init() {
|
|||||||
register("GCFairness2", GCFairness2)
|
register("GCFairness2", GCFairness2)
|
||||||
register("GCSys", GCSys)
|
register("GCSys", GCSys)
|
||||||
register("GCPhys", GCPhys)
|
register("GCPhys", GCPhys)
|
||||||
|
register("DeferLiveness", DeferLiveness)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GCSys() {
|
func GCSys() {
|
||||||
@ -207,3 +208,25 @@ func GCPhys() {
|
|||||||
fmt.Println("OK")
|
fmt.Println("OK")
|
||||||
runtime.KeepAlive(saved)
|
runtime.KeepAlive(saved)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test that defer closure is correctly scanned when the stack is scanned.
|
||||||
|
func DeferLiveness() {
|
||||||
|
var x [10]int
|
||||||
|
escape(&x)
|
||||||
|
fn := func() {
|
||||||
|
if x[0] != 42 {
|
||||||
|
panic("FAIL")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defer fn()
|
||||||
|
|
||||||
|
x[0] = 42
|
||||||
|
runtime.GC()
|
||||||
|
runtime.GC()
|
||||||
|
runtime.GC()
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:noinline
|
||||||
|
func escape(x interface{}) { sink2 = x; sink2 = nil }
|
||||||
|
|
||||||
|
var sink2 interface{}
|
||||||
|
Loading…
Reference in New Issue
Block a user