[commit: ghc] master: Fix a crash in requestSync() (ea3d1ef)

git at git.haskell.org git at git.haskell.org
Tue May 10 10:59:25 UTC 2016


Repository : ssh://git@git.haskell.org/ghc

On branch  : master
Link       : http://ghc.haskell.org/trac/ghc/changeset/ea3d1efb863ca83b28af9056576d47f1abf98fa9/ghc

>---------------------------------------------------------------

commit ea3d1efb863ca83b28af9056576d47f1abf98fa9
Author: Simon Marlow <smarlow at fb.com>
Date:   Tue May 10 03:22:57 2016 -0700

    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.


>---------------------------------------------------------------

ea3d1efb863ca83b28af9056576d47f1abf98fa9
 rts/Schedule.c | 23 ++++++++++++++---------
 1 file changed, 14 insertions(+), 9 deletions(-)

diff --git a/rts/Schedule.c b/rts/Schedule.c
index 8bbc9cf..d077ce2 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



More information about the ghc-commits mailing list