aboutsummaryrefslogtreecommitdiff
path: root/src/pkg/runtime
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2014-03-07 11:27:01 -0500
committerRuss Cox <rsc@golang.org>2014-03-07 11:27:01 -0500
commitb08156cd874d9534776cd9ece8f6f4ab092a68a5 (patch)
tree6d44e112d681a874df8a2ef95794580bdb16dd1d /src/pkg/runtime
parente509bbc943e817317e4db04b48f2895bec712c2f (diff)
downloadgo-b08156cd874d9534776cd9ece8f6f4ab092a68a5.tar.xz
runtime: fix memory leak in runfinq
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
Diffstat (limited to 'src/pkg/runtime')
-rw-r--r--src/pkg/runtime/mgc0.c31
1 files changed, 31 insertions, 0 deletions
diff --git a/src/pkg/runtime/mgc0.c b/src/pkg/runtime/mgc0.c
index 1677a50b23..e2bf55ae53 100644
--- a/src/pkg/runtime/mgc0.c
+++ b/src/pkg/runtime/mgc0.c
@@ -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
}
}