]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: fix memory leak in runfinq
authorRuss Cox <rsc@golang.org>
Fri, 7 Mar 2014 16:27:01 +0000 (11:27 -0500)
committerRuss Cox <rsc@golang.org>
Fri, 7 Mar 2014 16:27:01 +0000 (11:27 -0500)
One reason the sync.Pool finalizer test can fail is that
this function's ef1 contains uninitialized data that just
happens to point at some of the old pool. I've seen this cause
retention of a single pool cache line (32 elements) on arm.

Really we need liveness information for C functions, but
for now we can be more careful about data in long-lived
C functions that block.

LGTM=bradfitz, dvyukov
R=golang-codereviews, bradfitz, dvyukov
CC=golang-codereviews, iant, khr
https://golang.org/cl/72490043

src/pkg/runtime/mgc0.c

index 1677a50b232edd1eea0610d820b9d1f9bff67607..e2bf55ae53c3245d57588483b03e856eba66487f 100644 (file)
@@ -2525,8 +2525,29 @@ runfinq(void)
        uint32 framesz, framecap, i;
        Eface *ef, ef1;
 
+       // This function blocks for long periods of time, and because it is written in C
+       // we have no liveness information. Zero everything so that uninitialized pointers
+       // do not cause memory leaks.
+       f = nil;
+       fb = nil;
+       next = nil;
        frame = nil;
        framecap = 0;
+       framesz = 0;
+       i = 0;
+       ef = nil;
+       ef1.type = nil;
+       ef1.data = nil;
+       
+       // force flush to memory
+       USED(&f);
+       USED(&fb);
+       USED(&next);
+       USED(&framesz);
+       USED(&i);
+       USED(&ef);
+       USED(&ef1);
+
        for(;;) {
                runtime·lock(&gclock);
                fb = finq;
@@ -2581,6 +2602,16 @@ runfinq(void)
                        finc = fb;
                        runtime·unlock(&gclock);
                }
+
+               // Zero everything that's dead, to avoid memory leaks.
+               // See comment at top of function.
+               f = nil;
+               fb = nil;
+               next = nil;
+               i = 0;
+               ef = nil;
+               ef1.type = nil;
+               ef1.data = nil;
                runtime·gc(1); // trigger another gc to clean up the finalized objects, if possible
        }
 }