CertC-SIG35¶
Do not return from a computational exception signal handler
Required inputs: IR
According to the C Standard, 7.14.1.1 [
ISO/IEC
9899:2011], if a signal handler returns when it has been entered as a
result of a computational exception (that is, with the value of its argument
of
SIGFPE,
SIGILL,
, or any other implementation-defined value
corresponding to such an exception) returns, then the behavior is
undefined.
(See
undefined
behavior 130.)
SIGSEGV
The Portable Operating System Interface (POSIX®), Base
Specifications, Issue 7 [
IEEE
Std 1003.1:2013], adds
SIGBUS to the list of computational exception signal handlers:
The behavior of a process is undefined after it returns normally from a signal-catching function for a
SIGBUS,SIGFPE,SIGILL, orSIGSEGVsignal that was not generated bykill(),sigqueue(), orraise().
Do not return from
SIGFPE,
SIGILL,
, or any other implementation-defined value
corresponding to a computational exception, such as
SIGSEGVSIGBUS on POSIX systems, regardless of how the signal was
generated.
Noncompliant Code Example
In this noncompliant code example, the division operation has undefined
behavior if
denom equals
0. (See
INT33-C.
Ensure that division and remainder operations do not result in divide-by-zero
errors) and may result in a
SIGFPE signal to the program.)
#include <errno.h>
#include <limits.h>
#include <signal.h>
#include <stdlib.h>
volatile sig_atomic_t denom;
void sighandle(int s) {
/* Fix the offending volatile */
if (denom == 0) {
denom = 1;
}
}
int main(int argc, char *argv[]) {
if (argc < 2) {
return 0;
}
char *end = NULL;
long temp = strtol(argv[1], &end, 10);
if (end == argv[1] || 0 != *end ||
((LONG_MIN == temp || LONG_MAX == temp) && errno == ERANGE)) {
/* Handle error */
}
denom = (sig_atomic_t)temp;
signal(SIGFPE, sighandle);
long result = 100 / (long)denom;
return 0;
}
When compiled with some implementations, this noncompliant code example will
loop infinitely if given the input
0. It illustrates that even when a
SIGFPE handler attempts to fix the error condition while obeying
all other rules of signal handling, the program still does not behave as
expected.
Compliant Solution
The only portably safe way to leave a
SIGFPE,
SIGILL, or
SIGSEGV handler is to invoke
abort(),
quick_exit(), or
_Exit(). In the case of
SIGFPE, the default action is
abnormal
termination, so no user-defined handler is required:
#include <errno.h>
#include <limits.h>
#include <signal.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
if (argc < 2) {
return 0;
}
char *end = NULL;
long denom = strtol(argv[1], &end, 10);
if (end == argv[1] || 0 != *end ||
((LONG_MIN == denom || LONG_MAX == denom) && errno == ERANGE)) {
/* Handle error */
}
long result = 100 / denom;
return 0;
}
Implementation Details
Some implementations define useful behavior for programs that return from one
or more of these signal handlers. For example, Solaris provides the
sigfpe() function specifically to set a
SIGFPE handler that a program may safely return from.
Oracle also provides platform-specific computational
exceptions for the
SIGTRAP,
SIGBUS, and
SIGEMT signals. Finally, GNU libsigsegv takes advantage of the
ability to return from a
SIGSEGV handler to implement page-level memory management in user
mode.
Risk Assessment
Returning from a computational exception signal handler is undefined behavior.
| Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
|---|---|---|---|---|---|
| SIG35-C | Low | Unlikely | High | P1 | L3 |
Bibliography
| [ IEEE Std 1003.1:2013] | 2.4.1, Signal Generation and Delivery |
| [ ISO/IEC 9899:2011] | Subclause 7.14.1.1, "The
signal Function"
|
Possible Messages
Key |
Text |
Severity |
Disabled |
|---|---|---|---|
noreturn_computational_exception |
Do not return from a computational exception signal handler. |
None |
False |
Options¶
This rule shares the following common options: exclude_in_macros, exclude_messages_in_system_headers, excludes, extend_exclude_to_macro_invocations, includes, justification_checker, languages, post_processing, provider, report_at, severity
The following places define options that affect this rule: Stylechecks, Analysis-GlobalOptions
signal_names¶
signal_names : set[bauhaus.analysis.config.MacroName] = {'SIGBUS', 'SIGFPE', 'SIGILL', 'SIGSEGV'}