...
Compliance with this rule and SIG31-C. Do not access or modify shared objects in signal handlers can be checked using structural static analysis checkers using the following algorithm:
- Assume an initial list of async-safe functions. This list would be specific to each OS, although POSIX does require a set of functions to be async-safe.
- All Add all application defined functions that satisfy the async-safe property in that to the async-safe function list. Functions satisfy the async-safe property if they (a) only call functions in the list of async-safe functions or modifies only and (b) do not reference or modify external variables except to assign a value to a volatile static variable of
sig_atomic_t
variables are added to the async-safe function list type which can be written uninterruptedly. This handles the interprocedural case of calling a function in a signal handler that was is itself, an async-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 forsignal()
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 async-safe functions. To avoid repeatedly reviewing each function, the result of the first test of the function should be stored.
- Perform a nested query (can be combined with the one in the previous step) to identify all referenced objects with static storage duration. Verify that none of these objects are referenced as an rvalue, and that for each object referenced as an lvalue, the type is
sig_atomic_t
or can be stripped away to a type for whichsig_atomic_t
is the base type (this handles the case of layers oftypedef
hiding that a variable may be typedsig_atomic_t
, but just not obviously so. The result from this analysis could be stored in the same location as the information from the previous step. - If a violation is detected in either of the preceding two steps, report a violation (either a call to a non-asynch safe function or modification of a variable that was not
sig_atomic_t
)Report any violations detected.
References
Wiki Markup |
---|
\[[Dowd 06|AA. C References#Dowd 06]\] Chapter 13, "Synchronization and State" \[[ISO/IEC 03|AA. C References#ISO/IEC 03]\] Section 5.2.3, "Signals and interrupts" \[[ISO/IEC 9899-1999:TC2|AA. C References#ISO/IEC 9899-1999TC2]\] Section 7.14, "Signal handling <signal.h>" \[[Open Group 04|AA. C References#Open Group 04]\] [longjmp|http://www.opengroup.org/onlinepubs/000095399/functions/longjmp.html] \[OpenBSD\] [{{signal()}} Man Page|http://www.openbsd.org/cgi-bin/man.cgi?query=signal] \[[Zalewski 01|AA. C References#Zalewski 01]\] |