You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 9 Next »

According to section 7.14.1.1 (signals) of the C standard; returning from a SIGSEGV, SIGILL, or SIGFPE signal handler is undefined behavior:

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.

Furthermore, 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 in a SIGFPE signal being sent to the program.

#include<signal.h>
#include<stddef.h>
#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;
  }
  denom = (int)strtol(argv[1], (char **)NULL, 10);
    
  signal(SIGFPE,(*sighandle));

  result = 100/denom;
  return 0;
}

The noncompliant code example will loop infinitely on input 0 when compiled with gcc 4.3 or gcc 3.4. This 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 abort() or /_Exit(). In the case of SIGFPE, the default handler calls abort(), so no user defined handler is actually needed. The handler shown is only for consistency.

#include<signal.h>
#include<stddef.h>
#include<stdlib.h>

volatile sig_atomic_t denom;

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

int main(int argc, char *argv[]){
  int result = 0;
    
  if (argc < 2) {
    return 0;
  }
  denom = (int)strtol(argv[1], (char **)NULL, 10);
    
  signal(SIGFPE,(*sighandle));

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

Recommendation

Severity

Likelihood

Remediation Cost

Priority

Level

SIG35-C

low

unlikely

high

P3

L3

References

http://technopark02.blogspot.com/2005/10/handling-sigfpe.html
[[ISO/IEC 9899:1999]] 7.14.1.1

  • No labels