Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling OCaml-wrapped ZeroMQ code from signal handler

Tags:

c

zeromq

ocaml

I've written some OCaml bindings for CZMQ based on the guide at http://www.linux-nantes.org/~fmonnier/ocaml/ocaml-wrapping-c.php, which seem to work pretty well. For example here's zstr_send:

CAMLprim value caml_zstr_send(value socket_val, value string_val) {     CAMLparam2 (socket_val, string_val);      void *sock = CAML_CZMQ_zsocket_val(socket_val);     char *string = String_val(string_val);     int rc = zstr_send(sock, string);      CAMLreturn (Val_int(rc)); } 

I can send and receive messages using these bindings in most of my code just fine. However, I have a scenario where I would like to do sends and receives inside of a signal handler, to the end of doing message passing in the background of some other code. Take this simplified example:

open ZMQ exception SocketBindFailure  let bg_ctx = zctx_new ();; let pub_sock = zsocket_new bg_ctx ZMQ_PUB;;  let handler _ =     print_endline "enter handler";     print_endline (string_of_int (zstr_send pub_sock "hello"));     print_endline "end handler"; ;;  let () =     (try (         (* bind pub socket *)         let rc = zsocket_bind pub_sock "tcp://*:5556" in         if (rc < 0) then ( raise SocketBindFailure );          Sys.set_signal              Sys.sigalrm             (Sys.Signal_handle handler);          ignore              (Unix.setitimer                  Unix.ITIMER_REAL                  { Unix.it_interval = 0.01 ; Unix.it_value = 0.01 });          (* do some work *)     )     with      | SocketBindFailure -> raise SocketBindFailure)  ;; 

From the toplevel, this fails with the output:

enter handler 0 end handler Fatal error: exception Sys_blocked_io 

C code similar to the OCaml above works just fine. What is OCaml adding to the equation that is causing this exception?

like image 268
user1494672 Avatar asked May 20 '13 15:05

user1494672


1 Answers

There are two potential problems:

Inside a signal handler, you can only call asynchronous signal safe functions. Most functions are not async signal safe.

The reason for the restriction is that a function could be called in the middle of the same function's execution. Thus, internal state could be corrupted. Very few functions are async signal safe, and anything that allocates memory dynamically is not. In OCaml, many allocations happen "behind the scenes", so it is likely that your code is not async signal safe.

In your case, you are calling a function that writes to standard output. In C, this is never async signal safe, with one exception: the primitive write() function. This is the raw system call (which operates on a file descriptor) and is async signal safe for the simple reason that the kernel itself doesn't care you are in a signal handler, and will have fully cleaned up before returning control to you.

Calling an unsafe function from a signal handler, when the signal was asynchronous (the case here) and itself interrupted an unsafe function is undefined behavior in C. This means anything could happen -- including your program working correctly, but also including segmentation faults or other errors, as well as allowing an attacker to execute arbitrary code. This is normally associated with low-level languages like C, and is something that normally does not occur in OCaml.

OCaml uses a neat trick: when a signal is received for which a handler has been set in OCaml, it defers executing the handler until a safepoint. The result is that in a handler it is safe to set an unboxed quantity into a ref variable. However, other functions like print are possibly not reentrant, since they may have internal state. In general, within a signal handler you should try to avoid doing more than setting a flag and promptly returning. In OCaml, the flag should be a 31- or 63- bit integer, or a boolean, because these are unboxed. In C, the flag must be either volatile sig_atomic_t or (I am not sure about this) a C11 atomic type.

@TheCodeArtist gives the other possible reason for the error.

like image 112
Demi Avatar answered Oct 14 '22 04:10

Demi