]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: fix finalizer iterator
authorKeith Randall <khr@golang.org>
Tue, 9 Dec 2014 04:04:56 +0000 (20:04 -0800)
committerKeith Randall <khr@golang.org>
Wed, 10 Dec 2014 16:33:26 +0000 (16:33 +0000)
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 <rsc@golang.org>
src/runtime/debug/heapdump_test.go
src/runtime/malloc2.go
src/runtime/mgc.go

index 9201901151fbaede207f67eaa07f4731392145e8..cf01f520152d55ea1ace110d89556a10bc28532e 100644 (file)
@@ -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")
+}
index a9d40de30638ee2390fed023f59f9e93cfcd97a1..cd8dc0ad8b141457a0b7e7df16b6a789669e8a34 100644 (file)
@@ -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.
index 383ce2be3f020d4abf97bc2be28e8f030e1156a2..a08577434a25bc602014b5949e937980c07f2b83 100644 (file)
@@ -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