Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Updated references from C11->C23

According to section the C Standard, 7.14.1.1 (signals) of the C standard; returning from a SIGSEGV, SIGILL, or SIGFPE signal handler is undefined behavior:paragraph 3 [ISO/IEC 9899:2024], 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, SIGSEGV, or any other implementation-defined value corresponding to such an exception) returns, then the behavior is undefined. (See undefined behavior 130.)

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, or SIGSEGV signal that was not generated by kill(), sigqueue(), or raise().

Do not return from SIGFPE, SIGILL, SIGSEGV, or any other implementation-defined value corresponding to a computational exception, such as SIGBUS on POSIX systems, regardless of how the signal was generatedFurthermore, SIGFPE may not be caught for a significant amount of instructions after the floating-point instruction which creates it.

Noncompliant Code Example

In this noncompliant code example, if the given user input is '0', the division operation results 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 being sent to the program.)

Code Block
bgColor#ffcccc
langc
#include <errno.h>
#include <limits
#include<signal.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], (char **)NULL, 10);
    
  signal(SIGFPE,(*sighandle)) &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;
}

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. This . 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 through to 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
bgColor#ccccff
langc
#include <errno
#include<signal.h>
#include<stddef#include <limits.h>
#include<stdlib#include <signal.h>

volatile sig_atomic_t denom;

void sighandle(int s){
  /* No recovery */
  abort();
}

int #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. And . 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. An example of implementation-defined computational exceptions are the SIGTRAP, SIGBUS, and SIGEMT signals in Sun environments.

Risk Assessment

Attempting 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.

Returning from a computational exception signal handler is undefined behavior.

Rule

Recommendation

Severity

Likelihood

Remediation Cost

Priority

Level

SIG35-C

low

Low

unlikely

Unlikely

high

High

P3

P1

L3

References

...

Automated Detection

Tool

Version

Checker

Description

Axivion Bauhaus Suite

Include Page
Axivion Bauhaus Suite_V
Axivion Bauhaus Suite_V

CertC-SIG35
CodeSonar
Include Page
CodeSonar_V
CodeSonar_V

LANG.STRUCT.RFCESH

Return from Computational Exception Signal Handler

Cppcheck Premium
24.9.0

premium-cert-sig35-c

Fully implemented

Helix QAC

Include Page
Helix QAC_V
Helix QAC_V

DF4846, DF4847, DF4848


Klocwork
Include Page
Klocwork_V
Klocwork_V

CERT.STDLIB.SIGNAL


LDRA tool suite
Include Page
LDRA_V
LDRA_V
44 SEnhanced enforcement
Parasoft C/C++test

Include Page
Parasoft_V
Parasoft_V

CERT_C-SIG35-aDo not return from a computational exception signal handler
PC-lint Plus

Include Page
PC-lint Plus_V
PC-lint Plus_V

2671, 2764

Fully supported

Polyspace Bug Finder

Include Page
Polyspace Bug Finder_V
Polyspace Bug Finder_V

CERT C: Rule SIG35-CChecks 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

[IEEE Std 1003.1:2013]

2.4.1, Signal Generation and Delivery

[ISO/IEC 9899:2024]Subclause 7.14.1.1, "The signal Function"


...

Image Added Image Added Image Added