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, SIGSEGV, or any other implementation-defined value corresponding to such an exception) returns, then the behavior is undefined. (See undefined behavior 130.)

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 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"
Excerpt from SEI CERT C Coding Standard: Rules for Developing Safe, Reliable, and Secure Systems (2016 Edition) and SEI CERT C Coding Standard [https://cmu-sei.github.io/secure-coding-standards/sei-cert-c-coding-standard/rules/signals-sig/sig35-c], Copyright (C) 1995-2026 Carnegie Mellon University. See section 9.4. "3rd-Party Licenses" in the documentation for full details.

Possible Messages

Key

Text

Severity

Disabled

noreturn_computational_exception

Do not return from a computational exception signal handler.

None

False

Options

signal_names

signal_names : set[bauhaus.analysis.config.MacroName] = {'SIGBUS', 'SIGFPE', 'SIGILL', 'SIGSEGV'}

List of signal names that represent computational exceptions.