Proposal: Use uninterruptibleMask for cleanup actions in Control.Exception

Eyal Lotem eyal.lotem at gmail.com
Wed Sep 3 20:56:58 UTC 2014


I'd like to propose a change in the behavior of Control.Exception to help
guarantee cleanups are not accidentally lost.

For example, bracket is defined as:

bracket before after thing =  mask $ \restore -> do    a <- before
r <- restore (thing a) `onException` after a    _ <- after a    return
r

This definition has a serious problem: "after a" (in either the exception
handling case, or the ordinary case) can include interruptible actions
which abort the cleanup.

This means bracket does not in fact guarantee the cleanup occurs.

For example:

readMVar = bracket takeMVar putMVar -- If async exception occurs during
putMVar, MVar is broken!

withFile .. = bracket (openFile ..) hClose -- Async exception during hClose
leaks the file handle!

Interruptible actions during "before" are fine (as long as "before" handles
them properly).  Interruptible actions during "after" are virtually always
a bug -- at best leaking a resource, and at worst breaking the program's
invariants.

I propose changing all the cleanup handlers to run under
uninterruptibleMask, specifically:

*bracket, bracketOnError, bracket_, catch, catchJust, finally, handle,
handleJust, onException*

should all simply wrap their exception/cancellation handler with
uninterruptibleMask.

The danger of a deadlock is minimal when compared with the virtually
guaranteed buggy incorrect handling of async exceptions during cleanup.

-- 
Eyal
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/libraries/attachments/20140903/3efa6b1b/attachment.html>


More information about the Libraries mailing list