From b796cbc40657e0891a43bffab0ffb92ce656d8f1 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Mon, 8 Dec 2014 20:04:56 -0800 Subject: [PATCH] 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/1201 Reviewed-by: Russ Cox --- src/runtime/debug/heapdump_test.go | 37 ++++++++++++++++++++++++++++++ src/runtime/malloc2.go | 4 ++-- src/runtime/mgc.go | 5 ++-- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/src/runtime/debug/heapdump_test.go b/src/runtime/debug/heapdump_test.go index 9201901151..cf01f52015 100644 --- a/src/runtime/debug/heapdump_test.go +++ b/src/runtime/debug/heapdump_test.go @@ -31,3 +31,40 @@ func TestWriteHeapDumpNonempty(t *testing.T) { 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") +} diff --git a/src/runtime/malloc2.go b/src/runtime/malloc2.go index a9d40de306..cd8dc0ad8b 100644 --- a/src/runtime/malloc2.go +++ b/src/runtime/malloc2.go @@ -476,8 +476,8 @@ type finblock struct { alllink *finblock next *finblock cnt int32 - cap int32 - fin [1]finalizer + _ int32 + fin [(_FinBlockSize-2*ptrSize-2*4)/unsafe.Sizeof(finalizer{})]finalizer } // Information from the compiler about the layout of stack frames. diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go index 383ce2be3f..a08577434a 100644 --- a/src/runtime/mgc.go +++ b/src/runtime/mgc.go @@ -1093,10 +1093,9 @@ var finalizer1 = [...]byte{ func queuefinalizer(p unsafe.Pointer, fn *funcval, nret uintptr, fint *_type, ot *ptrtype) { lock(&finlock) - if finq == nil || finq.cnt == finq.cap { + if finq == nil || finq.cnt == int32(len(finq.fin)) { if finc == nil { finc = (*finblock)(persistentalloc(_FinBlockSize, 0, &memstats.gc_sys)) - finc.cap = int32((_FinBlockSize-unsafe.Sizeof(finblock{}))/unsafe.Sizeof(finalizer{}) + 1) finc.alllink = allfin allfin = finc if finptrmask[0] == 0 { @@ -1121,7 +1120,7 @@ func queuefinalizer(p unsafe.Pointer, fn *funcval, nret uintptr, fint *_type, ot block.next = finq 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++ f.fn = fn f.nret = nret -- 2.50.0