I just found out that someone is calling - from a signal handler - a definitely not async-signal-safe function that I wrote.
So, now I'm curious: how to circumvent this situation from happening again? I'd like to be able to easily determine if my code is running in signal handler context (language is C, but wouldn't the solution apply to any language?):
int myfunc( void ) {
if( in_signal_handler_context() ) { return(-1) }
// rest of function goes here
return( 0 );
}
This is under Linux. Hope this isn't an easy answer, or else I'll feel like an idiot.
Apparently, newer Linux/x86 (probably since some 2.6.x kernel) calls signal handlers from the
vdso
. You could use this fact to inflict the following horrible hack upon the unsuspecting world:SCNR.
I guess you need to do the following. This is a complex solution, which combines the best practices not only from coding, but from software engineering as well!
sighnd
, likesighndInterrupt
.backtrace()
.sighnd...
. If it does, then congratulations, you're inside a signal handler!There are two proper ways to deal with this:
Have your co-workers stop doing the wrong thing. Good luck pulling this off with the boss, though...
Make your function re-entrant and async-safe. If necessary, provide a function with a different signature (e.g. using the widely-used
*_r
naming convention) with the additional arguments that are necessary for state preservation.As for the non-proper way to do this, on Linux with GNU libc you can use
backtrace()
and friends to go through the caller list of your function. It's not easy to get right, safe or portable, but it might do for a while:In my opinion, it might just be better to quit rather than be forced to write code like this.
If we can assume your application doesn't manually block signals using
sigprocmask()
orpthread_sigmask()
, then this is pretty simple: get your current thread ID (tid
). Open/proc/tid/status
and get the values forSigBlk
andSigCgt
.AND
those two values. If the result of thatAND
is non-zero, then that thread is currently running from inside a signal handler. I've tested this myself and it works.You could work out something using sigaltstack. Set up an alternative signal stack, get the stack pointer in some async-safe way, if within the alternative stack go on, otherwise abort().
for code optimized at -O2 or better (istr) have found need to add -fno-omit-frame-pointer
else gcc will optimize out the stack context information