PDA

View Full Version : popen: safe to call in signal handler?



Elkvis
05-01-2012, 08:42 AM
if I use signal() or sigaction() to install a signal handler for SIGSEGV or other signals, is it safe to call popen() from inside the handler? it returns a FILE* so I'm guessing that it's a library function that calls pipe(), fdopen(), fork(), dup(), and exec*() on the back end, which are all legal calls inside a signal handler, so I'm guessing that it's ok. I am spawning the external program addr2line on a series of addresses obtained by calling backtrace(), and it appears to work fine, but I just want to make sure I'm not treading on undefined behavior territory.

Codeplug
05-01-2012, 09:26 AM
popen not in the list:
General Information (http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04_03_03)
https://www.kernel.org/doc/man-pages/online/pages/man7/signal.7.html

gg

Elkvis
05-01-2012, 11:11 AM
printf isn't on the list either, but every example that I see uses it. if you assume that the list is a hard-and-fast rule, then you also cannot call any user code from inside a signal handler, and that seems pretty unreasonable. wouldn't you agree? after looking at the source for a couple of implementations of popen, including glibc's implementation, I've confirmed that it is in fact typically calling pipe, (v)fork, dup/dup2, and exec*, which are all approved functions, guaranteed by POSIX to work correctly. would you say that if it's not explicitly on the list, that I can't use it? that seems like an unnecessarily strict interpretation to me.

Salem
05-01-2012, 11:31 AM
> would you say that if it's not explicitly on the list, that I can't use it?
Except you have no control over the implementation of popen(), so you can't be sure that it will be fine in future.

There's nothing to stop you using the POSIX API that is allowed to write a "popen" like function that does what you want.

If you want to write to a file in a signal handler, then it's a lot safer to use descriptors and write().

oogabooga
05-01-2012, 02:48 PM
The rule seems to be that it can't do any dynamic memory allocation/deallocation or use static/global data structures, since if it was interrupted the data structures could become inconsistent. One point here is that you're supposed to save/restore errno!

In the examples I've seen of signal handlers that call printf, they are just printing a string with nothing in the variable parameter list. That's probably what makes it safe since there would presumably be nothing extra behind-the-scenes in that scenario.

popen is apparently not guaranteed to make no use of such things.

Elkvis
05-02-2012, 08:57 AM
if I were to fork first, and then do what I need to do, and call exit() without returning, would that be a safe solution to this problem?

Codeplug
05-02-2012, 06:03 PM
When the application calls fork() from a signal handler and any of the fork handlers registered by pthread_atfork() calls a function that is not async-signal-safe, the behavior is undefined.
There's that risk.

Why not just let the default handler generate a core dump, then post-process the dump? Or fix the bugs ;)

gg

Elkvis
05-03-2012, 06:55 AM
There's that risk.

no risk in this case, as this program is single-threaded.


Why not just let the default handler generate a core dump, then post-process the dump?

it needs to happen in real time so that it can notify me by email that something went wrong.


Or fix the bugs ;)

that's why I'm generating a stack trace in the first place, to find the point at which the crash is happening, so that I can fix the bugs. this is a pretty large system (100k+ lines), going back more than 4 years, and some of the older code is lower quality, but in the absence of compiler warnings, it's difficult to proactively find bugs. I simply have to wait for the magic combination of circumstances that will make the program crash, and react to it after the fact.

Codeplug
05-03-2012, 07:19 AM
You'll have everything you need to debug the crash with a core dump. Why limit yourself to a manual stack trace?

>> it needs to happen in real time
So either monitor for the creation of a core dump, or signal something that a core dump is about to occur using this trick: How to handle SIGSEGV, but also generate a core dump - Alex on Linux (http://www.alexonlinux.com/how-to-handle-sigsegv-but-also-generate-core-dump)
But don't call printf like in the example since that's not in the list.

gg

Elkvis
05-03-2012, 08:55 AM
using this trick: How to handle SIGSEGV, but also generate a core dump - Alex on Linux (http://www.alexonlinux.com/how-to-handle-sigsegv-but-also-generate-core-dump)

I tried that, but even after setting ulimit -c unlimited, it still doesn't create core dumps. not sure where to go from there.

Codeplug
05-03-2012, 12:31 PM
Check all this type of stuff: How do I enable core dumps for everybody (http://www.akadia.com/services/ora_enable_core.html)
Can call getrlimit/setrlimit in the code as well: setrlimit(2): get/set resource limits - Linux man page (http://linux.die.net/man/2/setrlimit)

gg