According to Section the C Standard, 7.14.1.1 (signals) of the C Standard paragraph 3 [ISO/IEC 9899:20112024], returning from a SIGSEGV
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 SIGFPE
signal handler is undefined behavior:
, or any other implementation-defined value corresponding to such an exception) returns, then the behavior is undefined. (See undefined behavior 130.)SIGSEGV
When a signal occurs and func points to a function, it is implementation-defined whether the equivalent of signal (sig, SIG_DFL); is executed or the implementation prevents some implementation- defined set of signals (at least including sig) from occurring until the current signal handling has completed; in the case of SIGILL, the implementation may alternatively define that no action is taken. Then the equivalent of (*func)(sig); is executed. If and when the function returns, if the value of sig is SIGFPE, SIGILL, SIGSEGV, or any other implementation-defined value corresponding to a computational exception, the behavior is undefined; otherwise , the program will resume execution at the point it was interrupted.
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
, orSIGSEGV
signal 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 SIGSEGV
SIGBUS
on POSIX systems, regardless of how the signal was generatedFurthermore, SIGFPE
may not be caught for a significant number of instructions after the floating-point instruction that creates it.
Noncompliant Code Example
In this noncompliant code example, if the given user input is 0, the division operation sends 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:.)
Code Block | ||||
---|---|---|---|---|
| ||||
#include<signal#include <errno.h> #include <limits.h> #include<stddef#include <signal.h> #include<stdlib#include <stdlib.h> volatile sig_atomic_t denom; void sighandle(int s) { /* Fix the offending volatile */ if (denom == 0) { denom = 1; } /* Everything is ok */ return; } int main(int argc, char *argv[]) { int result = 0; if (argc < 2) { return 0; } denomchar *end = NULL; long temp = (int)strtol(argv[1], &end, 10); (char **)NULL, 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; } |
The When compiled with some implementations, this noncompliant code example will loop infinitely on if given the input 0
when compiled with GCC 4.3 or GCC 3.4. 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
In the compliant solution, the The only portably safe way to leave a SIGFPE
, SIGILL
, or SIGSEGV
handler is through abortto invoke abort()
, quick_exit()
, or /_Exit()
. In the case of SIGFPE
, the default handler calls abort()
action is abnormal termination, so no user-defined handler is actually needed. The handler shown is only for consistency.required:
Code Block | ||||
---|---|---|---|---|
| ||||
#include<signal#include <errno.h> #include<stddef#include <limits.h> #include<stdlib#include <signal.h> volatile sig_atomic_t denom; void sighandle(int s){ /* No recovery */ abort(); } #include <stdlib.h> int main(int argc, char *argv[]) { int result = 0; if (argc < 2) { return 0; } char *end = NULL; long denom = (int)strtol(argv[1], (char **)NULL&end, 10); if (end == argv[1] || 0 != *end || signal(SIGFPE,(*sighandle)); ((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. Sun 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
Code that attempts to handle SIGSEGV
, SIGILL
, or SIGFPE
signals is rare. However, code that does rely on handling these signals will usually require a redesign to fix the problem.
Returning from a computational exception signal handler is undefined behavior.
Rule |
---|
Severity | Likelihood | Remediation Cost | Priority | Level | |
---|---|---|---|---|---|
SIG35-C |
Low |
Unlikely |
High | P1 | L3 |
Automated Detection
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
Axivion Bauhaus Suite |
| CertC-SIG35 | |||||||
CodeSonar |
| LANG.STRUCT.RFCESH | Return from Computational Exception Signal Handler | ||||||
Cppcheck Premium | 24.9.0 | premium-cert-sig35-c | Fully implemented | ||||||
Helix QAC |
| DF4846, DF4847, DF4848 | |||||||
Klocwork |
| CERT.STDLIB.SIGNAL | |||||||
LDRA tool suite |
| 44 S | Enhanced enforcement | ||||||
Parasoft C/C++test |
| CERT_C-SIG35-a | Do not return from a computational exception signal handler | ||||||
PC-lint Plus |
| 2671, 2764 | Fully supported | ||||||
| CERT C: Rule SIG35-C | Checks for return from computational exception signal handler (rule fully covered) |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Bibliography
...
Giri Mandalika | Mandalika's Scratchpad |
[IEEE Std 1003.1:2013] | 2.4.1, Signal Generation and Delivery |
[ISO/IEC 9899:2024] | Subclause 7.14.1.1, "The signal Function" |
...
...