summaryrefslogtreecommitdiff
path: root/rts/Schedule.c
diff options
context:
space:
mode:
authorSimon Marlow <smarlow@fb.com>2016-05-10 03:22:57 -0700
committerSimon Marlow <smarlow@fb.com>2016-05-10 03:25:02 -0700
commitea3d1efb863ca83b28af9056576d47f1abf98fa9 (patch)
tree6c9fc57095e0d6584f4471052c525f2d27c32e3c /rts/Schedule.c
parente996e85f003e783fc8f9af0da653cdd0058d9646 (diff)
downloadhaskell-ea3d1efb863ca83b28af9056576d47f1abf98fa9.tar.gz
Fix a crash in requestSync()
It was possible for a thread to read invalid memory after a conflict when multiple threads were synchronising. I haven't been successful in constructing a test case that triggers this, but we have some internal code that ran into it.
Diffstat (limited to 'rts/Schedule.c')
-rw-r--r--rts/Schedule.c23
1 files changed, 14 insertions, 9 deletions
diff --git a/rts/Schedule.c b/rts/Schedule.c
index 8bbc9cf3e2..d077ce2d5a 100644
--- a/rts/Schedule.c
+++ b/rts/Schedule.c
@@ -1416,25 +1416,30 @@ static void stopAllCapabilities (Capability **pCap, Task *task)
#if defined(THREADED_RTS)
static rtsBool requestSync (
- Capability **pcap, Task *task, PendingSync *sync,
+ Capability **pcap, Task *task, PendingSync *new_sync,
SyncType *prev_sync_type)
{
- PendingSync *prev_sync;
+ PendingSync *sync;
- prev_sync = (PendingSync*)cas((StgVolatilePtr)&pending_sync,
- (StgWord)NULL,
- (StgWord)sync);
+ sync = (PendingSync*)cas((StgVolatilePtr)&pending_sync,
+ (StgWord)NULL,
+ (StgWord)new_sync);
- if (prev_sync)
+ if (sync != NULL)
{
+ // sync is valid until we have called yieldCapability().
+ // After the sync is completed, we cannot read that struct any
+ // more because it has been freed.
+ *prev_sync_type = sync->type;
do {
debugTrace(DEBUG_sched, "someone else is trying to sync (%d)...",
- prev_sync->type);
+ sync->type);
ASSERT(*pcap);
yieldCapability(pcap,task,rtsTrue);
- } while (pending_sync);
+ sync = pending_sync;
+ } while (sync != NULL);
+
// NOTE: task->cap might have changed now
- *prev_sync_type = prev_sync->type;
return rtsTrue;
}
else