diff options
author | Simon Marlow <smarlow@fb.com> | 2016-05-10 03:22:57 -0700 |
---|---|---|
committer | Simon Marlow <smarlow@fb.com> | 2016-05-10 03:25:02 -0700 |
commit | ea3d1efb863ca83b28af9056576d47f1abf98fa9 (patch) | |
tree | 6c9fc57095e0d6584f4471052c525f2d27c32e3c /rts/Schedule.c | |
parent | e996e85f003e783fc8f9af0da653cdd0058d9646 (diff) | |
download | haskell-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.c | 23 |
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 |