- Assume an initial list of asynchronous-safe functions. This list would be specific to each OS, although POSIX does require a set of functions to be asynchronous-safe.
- Add all application-defined functions that satisfy the asynchronous-safe property to the asynchronous-safe function list. Functions satisfy the asynchronous-safe property if they (a) call only functions in the list of asynchronous-safe functions and (b) do not reference or modify external variables except to assign a value to a volatile static variable of
sig_atomic_ttype which can be written uninterruptedly. This handles the interprocedural case of calling a function in a signal handler that is itself, an asynchronous-safe function.
- Traverse the abstract syntax tree (AST) to identify function calls to the signal function
signal(int, void (*f)(int)).
- At each function call to
signal(int, void (*f)(int))get the second argument from the argument list. To make sure that this is not an overloaded function the function type signature is evaluated and/or the location of the declaration of the function is verified to be from the correct file (because this is not a link-time analysis it is not possible to test the library implementation). Any definition for
signal()in the application is suspicious, because it should be in a library.
- Perform a nested query on the registered signal handler to get the list of functions that are called. Verify that each function being called is in the list of asynchronous-safe functions. To avoid repeatedly reviewing each function, the result of the first test of the function should be stored.
- Report any violations detected.