Skip to content

modifyMVar does not restore value if callback returns error value

modifyMVar is currently implemented as follows:

modifyMVar :: MVar a -> (a -> IO (a,b)) -> IO b
modifyMVar m io =
  mask $ \restore -> do
    a      <- takeMVar m
    (a',b) <- restore (io a) `onException` putMVar m a
    putMVar m a'
    return b

The problem is that it forces the (a',b) outside of the exception handler. If forcing this throws an exception, putMVar will not be called, and a subsequent withMVar or similar will hang. Example:

> import Control.Concurrent.MVar
> mv <- newMVar 'x'
> modifyMVar mv $ \_ -> return undefined
*** Exception: Prelude.undefined
> withMVar mv print
-- hang --

Perhaps we can fix it like this:

-     (a',b) <- restore (io a) `onException` putMVar m a
+     (a',b) <- restore (io a >>= evaluate) `onException` putMVar m a
Trac metadata
Trac field Value
Version 7.7
Type Bug
TypeOfFailure OtherFailure
Priority normal
Resolution Unresolved
Component libraries/base
Test case
Differential revisions
BlockedBy
Related
Blocking
CC
Operating system
Architecture
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information