Opened 6 years ago

Closed 6 years ago

#6153 closed bug (fixed)

writeChan not properly protecting again async exceptions

Reported by: klao Owned by:
Priority: normal Milestone:
Component: libraries/base Version: 7.4.1
Keywords: Cc:
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: None/Unknown Test Case:
Blocked By: Blocking:
Related Tickets: Differential Rev(s):
Wiki Page:


In the current code of writeChan from Control.Concurrent.Chan:

writeChan (Chan _ writeVar) val = do
  new_hole <- newEmptyMVar
  modifyMVar_ writeVar $ \old_hole -> do
    putMVar old_hole (ChItem val new_hole)
    return new_hole

if an async exception arrives "between" putMVar old_hole and return, the channel will be left in inconsistent state: the writeVar will be reverted to its original value, but old_hole would remain filled in. Thus all subsequent writers will block on this Chan indefinitely.

The proper solution is to just mask the whole operation. And it's OK, as 'putMVar old_hole' cannot ever block. I attach a patch for this.

Attachments (2)

Chan.diff (1.1 KB) - added by klao 6 years ago.
patch for writeChan
writeChan_deadlock.hs (589 bytes) - added by klao 6 years ago.

Download all attachments as: .zip

Change History (4)

Changed 6 years ago by klao

Attachment: Chan.diff added

patch for writeChan

Changed 6 years ago by klao

Attachment: writeChan_deadlock.hs added

comment:1 Changed 6 years ago by klao

Also, I'm attaching small program that demonstrates this issue. If you compile it with -O0 in a way that Control.Concurrent.Chan is also compiled with -O0 (for example by copying Control/Concurrent/Chan.hs and uncommenting import Chan instead for Control.Concurrent.Chan), then the deadlock is consistently reproduced.

comment:2 Changed 6 years ago by simonmar

difficulty: Unknown
Resolution: fixed
Status: newclosed
Note: See TracTickets for help on using tickets.