caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: Khoo Yit Phang <khooyp@cs.umd.edu>
To: caml-list@yquem.inria.fr
Cc: Khoo Yit Phang <khooyp@cs.umd.edu>
Subject: [Caml-list] Race conditions with asynchronous exceptions in standard library
Date: Tue, 5 Jul 2011 23:26:52 -0400	[thread overview]
Message-ID: <102E6342-F199-4A3C-B651-06795D14EB89@cs.umd.edu> (raw)

[-- Attachment #1: Type: text/plain, Size: 3038 bytes --]

Hi all,

I recently discovered a race condition when asynchronous exceptions, i.e., exceptions raised by signal handlers, are used with the DelimCC library. After consulting with Oleg Kiselyov, he realized that the problem with asynchronous exceptions is far more pervasive than I had originally thought. For example, the following program, using only the standard OCaml library, leads to a segfault:

> let q = Queue.create ();;
> 
> let () =
>     let en = ref false in
>     Sys.set_signal Sys.sigalrm (Sys.Signal_handle (fun _ -> if !en then raise Exit));
>     ignore (Unix.setitimer Unix.ITIMER_REAL { Unix.it_interval=1e-6; Unix.it_value=1e-3 });
>     while true do
>         try
>             en := true;
>             Queue.add "a" q;
>             en := false;
>             ignore (Queue.pop q)
>         with Exit ->
>             en := false;
>             if Queue.length q > 0 then prerr_endline "Non-empty";
>             assert (let len = Queue.length q in len = 0 || len = 1);
>             Queue.iter print_string q;
>             Queue.clear q;
>     done

The problem occurs in Queue.ml:

> let create () = {
>   length = 0;
>   tail = Obj.magic None
> }
> 
> let add x q =
>   q.length <- q.length + 1;
>   (* asynchronous exception occurs here *)
>   ...

When Queue.add is interrupted by an exception immediately after the length is updated, the length becomes inconsistent with the tail, and subsequent operations such as Queue.iter will attempt to operate on Obj.magic None, leading to the segfault.

Probably much of the standard library is similarly susceptible to such races, particularly the parts that operate on mutable data. These mostly lead to less dramatic consequences than segfaults, but are still seemingly random errors such as corrupted data or violated invariants.

For DelimCC, my solution was to provide a pair of C functions, mask_signals and unmask_signals, to bracket operations that are unsafe under asynchronous exceptions, using sigprocmask to suppress signal handling between them. However, since this requires access to OCaml's signal handling internals (caml_process_pending_signals and caml_signals_are_pending) to flush pending signals, it would be great to have mask_signals and unmask_signals or something similar in the standard library, so as to make it easier to develop libraries that are safe under asynchronous exceptions. (For reference, Haskell has seen this and other issues with asynchronous exception and implemented a similar solution, see http://hackage.haskell.org/trac/ghc/ticket/1036.)

Another option would be to simply warn against or disallow signal handlers that raise exceptions, but that seems less useful, e.g., it would make it hard to interrupt a long-running library function with a timeout.

We look forward to hearing what the official fix or guideline for handling asynchronous exception will be, for the standard library, third-party libraries, as well as applications.


Thank you,

Yit
July 5, 2011

[-- Attachment #2: Type: text/html, Size: 7208 bytes --]

             reply	other threads:[~2011-07-06  3:27 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-07-06  3:26 Khoo Yit Phang [this message]
2011-07-06  8:17 ` Mark Shinwell
2011-07-06  9:04   ` Fabrice Le Fessant
2011-07-06 18:06 ` Gerd Stolpmann
2011-07-06 21:13 ` Richard W.M. Jones
2011-07-06 23:40 ` [Caml-list] " Khoo Yit Phang
2011-07-07  0:07   ` Gerd Stolpmann
2011-07-09 13:02 ` [Caml-list] " ygrek

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=102E6342-F199-4A3C-B651-06795D14EB89@cs.umd.edu \
    --to=khooyp@cs.umd.edu \
    --cc=caml-list@yquem.inria.fr \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).