Commit b796cbc4 authored by Keith Randall's avatar Keith Randall

runtime: fix finalizer iterator

It could only handle one finalizer before it raised an out-of-bounds error.

Fixes issue #9172

Change-Id: Ibb4d0c8aff2d78a1396e248c7129a631176ab427
Reviewed-on: https://go-review.googlesource.com/1201Reviewed-by: default avatarRuss Cox <rsc@golang.org>
parent 508a22d5
...@@ -31,3 +31,40 @@ func TestWriteHeapDumpNonempty(t *testing.T) { ...@@ -31,3 +31,40 @@ func TestWriteHeapDumpNonempty(t *testing.T) {
t.Fatalf("Heap dump size %d bytes, expected at least %d bytes", size, minSize) t.Fatalf("Heap dump size %d bytes, expected at least %d bytes", size, minSize)
} }
} }
type Obj struct {
x, y int
}
func objfin(x *Obj) {
println("finalized", x)
}
func TestWriteHeapDumpFinalizers(t *testing.T) {
if runtime.GOOS == "nacl" {
t.Skip("WriteHeapDump is not available on NaCl.")
}
f, err := ioutil.TempFile("", "heapdumptest")
if err != nil {
t.Fatalf("TempFile failed: %v", err)
}
defer os.Remove(f.Name())
defer f.Close()
// bug 9172: WriteHeapDump couldn't handle more than one finalizer
println("allocating objects")
x := &Obj{}
runtime.SetFinalizer(x, objfin)
y := &Obj{}
runtime.SetFinalizer(y, objfin)
// Trigger collection of x and y, queueing of their finalizers.
println("starting gc")
runtime.GC()
// Make sure WriteHeapDump doesn't fail with multiple queued finalizers.
println("starting dump")
WriteHeapDump(f.Fd())
println("done dump")
}
...@@ -476,8 +476,8 @@ type finblock struct { ...@@ -476,8 +476,8 @@ type finblock struct {
alllink *finblock alllink *finblock
next *finblock next *finblock
cnt int32 cnt int32
cap int32 _ int32
fin [1]finalizer fin [(_FinBlockSize-2*ptrSize-2*4)/unsafe.Sizeof(finalizer{})]finalizer
} }
// Information from the compiler about the layout of stack frames. // Information from the compiler about the layout of stack frames.
......
...@@ -1093,10 +1093,9 @@ var finalizer1 = [...]byte{ ...@@ -1093,10 +1093,9 @@ var finalizer1 = [...]byte{
func queuefinalizer(p unsafe.Pointer, fn *funcval, nret uintptr, fint *_type, ot *ptrtype) { func queuefinalizer(p unsafe.Pointer, fn *funcval, nret uintptr, fint *_type, ot *ptrtype) {
lock(&finlock) lock(&finlock)
if finq == nil || finq.cnt == finq.cap { if finq == nil || finq.cnt == int32(len(finq.fin)) {
if finc == nil { if finc == nil {
finc = (*finblock)(persistentalloc(_FinBlockSize, 0, &memstats.gc_sys)) finc = (*finblock)(persistentalloc(_FinBlockSize, 0, &memstats.gc_sys))
finc.cap = int32((_FinBlockSize-unsafe.Sizeof(finblock{}))/unsafe.Sizeof(finalizer{}) + 1)
finc.alllink = allfin finc.alllink = allfin
allfin = finc allfin = finc
if finptrmask[0] == 0 { if finptrmask[0] == 0 {
...@@ -1121,7 +1120,7 @@ func queuefinalizer(p unsafe.Pointer, fn *funcval, nret uintptr, fint *_type, ot ...@@ -1121,7 +1120,7 @@ func queuefinalizer(p unsafe.Pointer, fn *funcval, nret uintptr, fint *_type, ot
block.next = finq block.next = finq
finq = block finq = block
} }
f := (*finalizer)(add(unsafe.Pointer(&finq.fin[0]), uintptr(finq.cnt)*unsafe.Sizeof(finq.fin[0]))) f := &finq.fin[finq.cnt]
finq.cnt++ finq.cnt++
f.fn = fn f.fn = fn
f.nret = nret f.nret = nret
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment