Calling OCaml-wrapped ZeroMQ code from signal handler

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.

Leave a Comment