summaryrefslogtreecommitdiff
path: root/rts/sm/MarkWeak.c
diff options
context:
space:
mode:
authorTakano Akio <tak@anoak.io>2016-05-11 14:45:29 +0200
committerBen Gamari <ben@smart-cactus.org>2016-05-11 14:46:48 +0200
commit9363f04d0ff22f3d898af35bb5432c4287e6dc9a (patch)
tree0e80d6c88760bf61ac29da655c1c3356c1c80545 /rts/sm/MarkWeak.c
parent0efbf18b80c261708da9ef61bcd420fa94cfed42 (diff)
downloadhaskell-9363f04d0ff22f3d898af35bb5432c4287e6dc9a.tar.gz
Handle promotion failures when scavenging a WEAK (#11108)
Previously, we ignored promotion failures when evacuating fields of a WEAK object. When a failure happens, this resulted in an WEAK object pointing to another object in a younger generation, causing crashes. I used the test case from #11746 to check that the fix is working. However I haven't managed to produce a test case that quickly reproduces the issue. Test Plan: ./validate Reviewers: austin, bgamari, simonmar Reviewed By: simonmar Subscribers: thomie Differential Revision: https://phabricator.haskell.org/D2189 GHC Trac Issues: #11108
Diffstat (limited to 'rts/sm/MarkWeak.c')
-rw-r--r--rts/sm/MarkWeak.c37
1 files changed, 35 insertions, 2 deletions
diff --git a/rts/sm/MarkWeak.c b/rts/sm/MarkWeak.c
index c6ab5b161c..2393536a74 100644
--- a/rts/sm/MarkWeak.c
+++ b/rts/sm/MarkWeak.c
@@ -25,6 +25,8 @@
#include "Storage.h"
#include "Threads.h"
+#include "sm/GCUtils.h"
+#include "sm/MarkWeak.h"
#include "sm/Sanity.h"
/* -----------------------------------------------------------------------------
@@ -265,10 +267,25 @@ static rtsBool tidyWeakList(generation *gen)
new_gen = Bdescr((P_)w)->gen;
gct->evac_gen_no = new_gen->no;
+ gct->failed_to_evac = rtsFalse;
// evacuate the value and finalizer
- evacuate(&w->value);
- evacuate(&w->finalizer);
+ //
+ // This WEAK object will not be considered by tidyWeakList
+ // during this collection because it is in a generation >= N,
+ // but it is on the mutable list so we must evacuate all of its
+ // pointers because some of them may point into a younger
+ // generation.
+ scavengeLiveWeak(w);
+
+ if (gct->failed_to_evac) {
+ debugTrace(DEBUG_weak,
+ "putting weak pointer %p into mutable list",
+ w);
+ gct->failed_to_evac = rtsFalse;
+ recordMutableGen_GC((StgClosure *)w, new_gen->no);
+ }
+
// remove this weak ptr from the old_weak_ptr list
*last_w = w->link;
next_w = w->link;
@@ -418,3 +435,19 @@ markWeakPtrList ( void )
}
}
+/* -----------------------------------------------------------------------------
+ Fully scavenge a known-to-be-alive weak pointer.
+
+ In scavenge_block, we only partially scavenge a weak pointer because it may
+ turn out to be dead. This function should be called when we decide that the
+ weak pointer is alive after this GC.
+ -------------------------------------------------------------------------- */
+
+void
+scavengeLiveWeak(StgWeak *w)
+{
+ evacuate(&w->value);
+ evacuate(&w->key);
+ evacuate(&w->finalizer);
+ evacuate(&w->cfinalizers);
+}