Can I execute free() or close() in a signal handler? [duplicate] - c

This question already has answers here:
How to avoid using printf in a signal handler?
(8 answers)
Closed 2 years ago.
I have a code that looks like this:
//global variables
void signal_handler() {
//deallocation of global variables
free(foo);
close(foo_2);
exit(0);
}
int main () {
signal(SIGINT, signal_handler);
//irrelevant code
}
As you can see, I changed the CTRL+C interruption to execute the signal_handler function once instead of killing the process right away. I read somewhere that some functions like might be free are not async-safe and would NOT execute in the signal_handler but I'm not sure about that.
Can I execute functions like free, close, exit or even pthread_join in a signal handler?

No. Only functions listed in man 7 signal-safety are safe to call inside a signal handler.
close is listed and should be safe. free is not. For reasons why you would have to look at its source code (it contains locks). exit is not safe because it can call arbitrary cleanup handlers. You have _exit which exits abruptly without the cleanup.

You techincally can compile a program that calls such functions in a signal handler, nothing stops you from doing that. However it will result in undefined behavior if the function you are trying to execute is not async-signal-safe. It's not like unsafe function would just "NOT execute" as you say, they very well could, but that'd still be undefined behavior.
A list of async-signal-safe functions is documented in man 7 signal-safety. The close() function is safe, while free() and phtread_join() are not. The exit() function is also not safe to call from a signal handler, if you wish to exit from such context you will have to do so using _exit() instead.
The only way to safely call a function that is not async-signal-safe when receiving a signal is to "remember" that you have to call it (for example setting a global variable) and then do so after returning from the signal handler.

Short answer is no:
7.1.4 Use of library functions
...
4 The functions in the standard library are not guaranteed to be reentrant and may modify
objects with static or thread storage duration.188)
188) Thus, a signal handler cannot, in general, call standard library functions
C 2011 Online Draft
Real-world example of the consequences - I worked on a system that communicated with an Access database. There was a signal handler that tried to write an error message to the console with fprintf, but somehow during the signal handling process stderr got mapped to the .mdb file that stored the database, overwriting the header and ruining the database beyond repair.
There's honestly not a whole lot you can do in a signal handler other than set a flag to be checked elsewhere.

Can I execute free() or close() in a signal handler?
You definitely should not. See signal(7) and signal-safety(7)
In practice, it might work like you want perhaps more than half of the time. IIRC, the GCC compiler is doing like you want to do, and it usually works.
A better approach is to use some write(2) to a pipe(7) (from inside your signal handler) and from time to time check that pipe (in your main program) with poll(2) or related things.
Or you could set some volatile sigatomic_t flag; (perhaps it should be also _Atomic) in your signal handler, and check that flag elsewhere (in the main program, outside of signal handlers).
Qt is explaining that better than I could do in a few minutes.
On Linux, see also signalfd(2) and eventfd(2).

Related

C write async unsafe code in signal handler

How can i run asynchrounous-unsafe code in a signal handler. I cant use a flag in my case. Could i use longjmp to jump to a different context?
In a signal handler you can only use a set of safe functions which in many cases is sufficient for complicated functionality started within a handler. You can check man pages for your system for 'signal-safety' or similar. Here is a pointer on the web: https://man7.org/linux/man-pages/man7/signal-safety.7.html
pthread synchronization functions are not on the list.
However, One of the function listed there is sem_post: https://man7.org/linux/man-pages/man3/sem_post.3.html
sem_post() is async-signal-safe: it may be safely called within a
signal handler.
So, you can implement mutex-like synchronization using semaphores within the signal handler.

What happen if an exit occur inside the atexit handler?

I know that atexit is used to register a function handler. Then when an exit in the code occur that function is called. But what if an exit occur inside the function handler?
I was expecting an infinite loop but in reality the program exit normally. Why?
void handler(){
printf("exit\n");
exit(1);
}
int maint(int argc, char *argv[]) {
atexit(handler);
exit(1);
}
The behavior is undefined.
7.22.4.4 The exit function
2 The exit function causes normal program termination to occur. No
functions registered by the at_quick_exit function are called. If a
program calls the exit function more than once, or calls the
quick_exit function in addition to the exit function, the behavior is
undefined.
Calling exit in an at_exit handler (that is being run during the normal processing of exit) is definitely a second call to exit.
Exiting normally is a possible behavior, but seeing as anything can happen (the nature of the behavior being undefined), it could very well result in catastrophe. Best not to do it.
As you have been pointed to, the behaviour is undefined.... but despite of that, trying to justify your observed behaviour, the library writers normally tend to cope with strange programmer behaviours (like the at least strange of calling exit() while the program is in exit()) I'll say:
It is possible that the exit(3) function, before calling any of the exit handlers, just unregisters it from the list of signal handlers. This would make the exit(2) function to call each exit handler only once and not to call the handler recursively. Just try to register it again to see what happens would be a good exercise.
It is possible that the exit function, marks itself as being run and if called inside a handler, just return, as if nothing happens.
It is possible your expected behaviour that could lead to a stak overflow (no pun here :))
It is possible to ...
Whatever happens is part of the U.B. commented in other answers, but for a library that tries to extend on the standard and behave normally, the probably best behaviour is to avoid recursive calls in exit handlers in some of the ways proposed.
On the other side, you had better not to use this feature (let's call so) in your programs, because, as it is not endorsed by the standard, can lead you to trouble if you port your programs elsewhere in the future.
You probably think on exit(3) as a function that is never to be called twice (apart from recursively, like you expose) but think you have several threads on your program and two of them call the exit(3) function at the same time.
The probable best behaviour is to have some kind of semaphore that allows the handlers to be protected from mutual access... but the best way to have the list of handlers for short time compromised, is to unlink one handler from the list (let's consider the list a queue, where each thread comes and takes a handler) they get the handler, unlock the queue and then execute it. This can lead in each handler being executed by one thread of the ones that have called exit(). The first thing an implementor faces it how to deal with several threads calling exit() at the same time.
POSIX.1 says that the result of calling exit(3) more than once (i.e., calling exit(3) within a function registered using atexit()) is undefined. On some systems (but not Linux), this can result in an infinite recursion; portable programs should not invoke exit(3) inside a function registered using atexit().
found here

(f)printf() thread-safe but not signal-handler safe

We recently had a discussion at work about signal handlers in C (Unix enviornment).
Someone mentioned that
(f)printf() is certainly thread-safe but not signal-handler safe.
What does the above statement mean? What aspect of (f)printf() make it not signal-handler safe? Is it because it accesses the stdout and stdin which are global and hence the function is not re-entrant?
Or is there some other aspect which I am missing?
There is actually fairly little that is legal to do in a signal handler directly. Instead, one must usually set some flag or trigger to do the real work outside the signal handling context. While handling a signal, the only functions you can call are those which are "async signal safe," which is described in detail here: What constitutes asynchronous-safeness
As mentioned in here: http://www.gnu.org/software/libc/manual/html_node/Nonreentrancy.html#Nonreentrancy
If a function uses and modifies an object that you supply, then it is
potentially non-reentrant; two calls can interfere if they use the
same object.
In your case that object is stdout. When a signal arrives in the middle of a (f)printf() and if you use (f)printf in handler, both data could be corrupted as they operate on the same stream, stdout. Reentrancy is the root cause in that case. Even if you use the stream in just signal handler, two signal handlers can interfere.

What constitutes asynchronous-safeness

It is said that you should only call asynchronous-safe functions inside a signal handler. My question is, what constitutes asynchronous-safeness? A function which is both reentrant and thread safe is asynchronous-safe I guess? Or No?
Re-entrance and thread safety has a little or nothing to do with this. Side effects, state and interruption of those functions are facts that matter.
asynchronous-safe function [GNU Pth]
A function is asynchronous-safe,
or asynchronous-signal safe, if it can be called safely and without
side effects from within a signal handler context. That is, it must be
able to be interrupted at any point to run linearly out of sequence
without causing an inconsistent state. It must also function properly
when global data might itself be in an inconsistent state. Some
asynchronous-safe operations are listed here:
call the signal() function to reinstall a signal handler
unconditionally modify a volatile sig_atomic_t variable (as
modification to this type is atomic)
call the _Exit() function to
immediately terminate program execution
invoke an asynchronous-safe
function, as specified by your implementation
Few functions are
portably asynchronous-safe. If a function performs any other
operations, it is probably not portably asynchronous-safe.
A rule of thumb is this - only signal some condition variable from signal handler (such as futex/pthread condition, wake up epoll loop etc.).
UPDATE:
As EmployedRussian suggested, even calling pthread_cond_signal is a bad idea. I've checked the source code of the recent eglibc and it has lock/unlock pair in there. Thus, introducing a possibility for a deadlock. This leaves us with few options to signal other threads:
Using eventfd.
Changing global atomic variable and hope that SA_RESTART is not set and other threads will check our atomic.
For your own code, yes, re-entrant and thread-safe are the characteristics you need, as, depending on how you set up your signal handling mechanism, your signal handler may itself be interrupted by another signal. In general, try to do as little work as possible inside the signal handler. Setting flags to trigger special code in your normal program flow is probably all you should be doing.
For functions in the OS that you might call, check out man 7 signal for a list of what is safe to call. Note that malloc() and free() are not on the list. The pthread synchronization APIs are not on the list either, but I would think that some would have to be safe to call, so you can set a global flag safely in a signal handler.

What happens if during a signal handling in UNIX, the same signal gets sent to the program?

Any ideas on this? Is there some kind of a signal queue, or does it get dropped?
While we are at this question, is it true that signal handlers should do as minimal work as possible?
I read somewhere that a signal handler should use a pipe and just write one byte to it, indicating what the program should do. Then somewhere else the program periodically checks the pipe, and dispatches based on byte in it. (I might have misunderstood it)
Thanks, Boda Cydo.
To answer the second part of your question, "is it true that signal handlers should do as minimal work as possible?" the answer is yes, because there is a very minimal set of functions that are "async signal safe" and therefore able to be called from signal handlers. Async signal safety is kind of an enhanced form of re-entrancy. If foo() is async signal safe, that means that it's safe to call foo() within a signal handler, even if foo() was already executing when the signal was raised.
You can get the full list of async signal safe functions by looking that the section 7 man page for signal (man 7 signal). Calling any function other than one of these from within a signal handler, directly or indirectly, invokes undefined behavior.
The "write a byte to a pipe" approach is a great way to deal with signals without being restricted to async signal safe functions, especially if your program is already oriented around a select loop.
To answer the first part of your question, the default is as follows: If it's the same signal as the one currently being handled, the new signal is blocked (held in a queue) and delivered when the handler returns. If some other signal arrives, the handler for the new signal is called. c.f. the glibc manual.

Resources