atexit considered harmful? - c

Are there inherent dangers in using atexit in large projects such as libraries?
If so, what is it about the technical nature behind atexit that may lead to problems in larger projects?

The main reason I would avoid using atexit in libraries is that any use of it involves global state. A good library should avoid having global state.
However, there are also other technical reasons:
Implementations are only required to support a small number (32, I think) of atexit handlers. After that, it's possible that all calls to atexit fail, or that they succeed or fail depending on resource availability. Thus, you have to deal with what to do if you can't register your atexit handler, and there might not be any good way to proceed.
Interaction of atexit with dlopen or other methods of loading libraries dynamically is not defined. A library which has registered atexit handlers cannot safely be unloaded, and the ways different implementations deal with this situation can vary.
Poorly written atexit handlers could have interactions with one another, or just bad behaviors, that prevent the program from properly exiting. For instance, if an atexit handler attempts to obtain a lock that's held in another thread and that can't be released due to the state at the time exit was called.

Secure CERT has an entry about atexit when not used correctly:
ENV32-C. All atexit handlers must return normally
https://www.securecoding.cert.org/confluence/display/seccode/ENV32-C.+All+atexit+handlers+must+return+normally

Related

Runtime-detecting nommu Linux unobtrusively

I'm looking for a reliable, unobtrusive runtime check a process can make for whether it's running on Linux without mmu. By unobtrusive, I mean having minimal or no side effects on process state. For example, getting EINVAL from fork would be one indication, but would create a child process if the test failed. Attempting to cause a fault and catch a signal is out of the question since it involves changing global signal dispositions. Anything involving /proc or /sys would be unreliable since they may not be mounted/visible (e.g. in chroot or mount namespace).
Failure of mprotect with ENOSYS seems to be reliable, and can be done without any side effects beyond the need to map a test page to attempt it on. But I'm not sure if it's safe to rely on this.
Are there any better/recommended ways to go about this?
Before anyone tries to challenge the premise and answer that this is known statically at compile time, no, it's not. Assuming you build a position-independent executable for an ISA level supported by both mmu-ful and mmu-less variants of the architecture, it can run on either. (I'm the author of the kernel commit that made this work.)

how to reset handlers registered by pthread_atfork

Some libraries might register some handlers with pthread_atfork(). I don't need them as I only use fork() together with exec(). Also, they can cause trouble in some cases. So, is there a way to reset the registered handler list?
Related: calling fork() without the atfork handlers, fork() async signal safety.
POSIX does not document any mechanism for fork handlers installed by pthread_atfork() to be removed, short of termination of the process or replacing the process image. If you don't want them, then don't install them. If they are installed by a third-party library, as you describe, then your options are to find a way to avoid that behavior of the library (possibly by avoiding the library altogether) or to live with it.

How are trap handlers, exception handlers, and interrupt handlers different from system calls?

Considering Linux environment, what is the difference between them?
How is a system call different from a normal function call?
According to wikipedia, a TRAP is an exception. Exceptions are defined differently depending on who you talk to. In a generic form, interrupts are exceptions. Exceptions could be a page fault (code or data), an alignment, an undefined instruction, divide by zero, etc.
Generally, they are all very similar. They will switch context to the OS to handle the issue resulting in registers saves (a user-space to OS context switch) and a possible process context switch depending on the request or circumstance. When you transition to the OS, different MMU protection (the CPU view of memory) are in effect and a different stack is used. In most cases, the instruction that caused the fault is the one that was executing when the switch happens.
The interrupt is different in that any user-space instruction could be interrupted. For most others, there are only specific classes of instructions that may cause a fault. This has ramification for compilers and libraries that need to do things atomically (to the thread, process or to the system globally). More details really depend on the CPU in use.
Difference between library and system calls
Considering Linux environment, what is the difference between them?
This is almost unanswerable in a definite way. Linux versions, CPU versions and your definition of what these are would influence the answer. However, I think the above is a good conceptual guide.
How is a system call different from a normal function call?
A normal function call doesn't transition to 'kernel space'. Many access permissions change when entering kernel space. Usually this has some physical hard wiring into the CPU. However the Linux 'mm' and 'io' layers are most definitely different and code maybe required to make it so. It can also depend on what the 'system call' does. In some cases, Linux has been optimize so the system call isn't needed (from one version to the next). See for example the vdso man page. In other cases, the C libraries or other mechanism might avoid the system call; for instance DNS name caching, etc.

aio_read inside signal handler

I'm going to use aio for async read. When aio completes and signal handler is triggered, I may need to do another aio_read call and proceed.
aio_read isn't mentioned among safe functions (in man signal). Ordinary read is, though.
What are the dangers of doing subsequent aio_read calls inside aio signal handler?
As the author of proposed Boost.AFIO which can make use of POSIX AIO, I strongly recommend against using POSIX AIO at all. I am hardly alone in this opinion, #arvid is similarly against: http://blog.libtorrent.org/2012/10/asynchronous-disk-io/. The API itself is poorly designed and as a result scales poorly with load unless you use OS-specific alternatives or extensions to AIO like BSD kqueues. POSIX AIO is essentially useless as-is.
Additionally, AIO calls are not signal safe on Linux, which you are probably using. This is because on Linux they are implemented in userspace using an emulation based on a threadpool. On BSD, AIO calls have a proper kernel syscall interface, but in the kernel turn into - yes you guessed it - a threadpool based emulation unless O_DIRECT is turned on.
You are therefore much better off on POSIX of simply always using a threadpool unless all your i/o is with O_DIRECT on. If O_DIRECT is indeed always on, Linux provides a custom kernel API detailed at http://man7.org/linux/man-pages/man2/io_submit.2.html which is fairly effective, and on BSD if you replace signal driven handling with BSD kqueues (https://www.freebsd.org/cgi/man.cgi?kqueue, see EVFILT_AIO) then with O_DIRECT things can also scale well, better than a threadpool anyway.
Use of signal based completion handling on ANY POSIX platform has dreadful performance. AFIO v2 provides a generic POSIX AIO backend, and it is dreadful, dreadful, dreadful. Avoid like the plague.
Note that a threadpooled synchronous API design is portable, scales well for most use cases, and is what I (and indeed arvid) would recommend to anybody without highly specialised needs like writing a database backend where you need very tight control over the physical storage layer, and anything but O_DIRECT|O_SYNC isn't an option.
Ok, all that said, if you really really want to use signal driven aio, I assume this is because you want to multiplex your file i/o with non-file i/o stuff and you therefore can't use aio_suspend() which is the proper API for doing this. The way AFIO v2 handles this is to use a realtime signal to interrupt aio_suspend() when something not aio related needs to be processed, it can then be handled and aio_suspend() restarted. You need to be very careful in handling races and deadlocks, and you'll need to carefully mask and unmask the signal for the thread calling aio_suspend() lest the realtime signal gets lost and you get a lost wakeup. All in all, it's not worth it for the typically much lower i/o performance you get over a threadpool + synchronous APIs.

Signals and libraries

Are there any conventions/design pattern for using signals and signal handlers in a library code? Because signals are directed to the whole process and not to specific thread or library, i feel there may be some issues.
Let's say i m writing a shared library which will be used by other applications and i want to use alarm, setitimer functions and trap SIGALRM signal to do some processing at specific time.
I see some problems with it:
1) If application code (which i have no control of) also uses SIGALRM and i install my own signal handler for it, this may overwrite the application's signal handler and thus disable it's functionality. Of course i can make sure to call previous signal handler (retrieved by signal() function) from my own signal handler, but then there is still a reverse problem when application code can overwrite my signal handler and thus disable the functionality in my library.
2) Even worse than that, application developer may link with another shared library from another vendor which also uses SIGALRM, and thus nor me nor application developer would have any control over it.
3) Calling alarm() or setitimer() will overwrite the previous timer used by the process, so application could overwrite the timer i set in the library or vice versa.
I m kinda a novice at this, so i m wondering if there is already some convention for handling this? (For example, if every code is super nice, it would call previous signal handler from their own signal handler and also structure the alarm code to honor previous timers before overwriting them with their own timer)
Or should i avoid using signal handlers and alarm()s in a library alltogether?
Or should i avoid using signal handlers and alarm()s in a library alltogether?
Yes. For the reasons you've identified, you can't depend on signal disposition for anything, unless you control all code in the application.
You could document that your library requires that the application not use SIGALRM, nor call alarm, but the application developer may not have any control over that anyway, and so it's in your best interest to avoid placing such restrictions in the first place.
If your library can work without SIGALRM (perhaps with reduced functionality), you can also make this feature optional, perhaps controlled by some environment variable. Then, if it is discovered that there is some code that interferes with your signal handling, you can tell the end-user to set your environment variable to disable that part of your library (which beats having to rebuild and supply a new version of it).
P.S. Your question and this answer applies to any library, whether shared or archive.

Resources