Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 4.0

No atexit() registered handler should terminate in any way other than by returning. It is important and potentially safety-critical for all the atexit() handlers to be allowed to perform their cleanup actions. This is particularly true because the application programmer does not always know about handlers that may have been installed by support libraries. Two specific issues include nested calls to exit() and terminating a call to an atexit() registered handler by invoking longjmp.

The C99 exit() function is used for normal program termination. (See recommendation ERR04-C. Choose an appropriate termination strategy.) Nested calls to exit() result in undefined behavior. (See also undefined behavior #172 in Annex J.) This can only occur when exit() is invoked from a function registered with atexit(), or when exit() is called from within a signal handler. (See rule SIG30-C. Call only asynchronous-safe functions within signal handlers.)

If a call to the longjmp function is made that would terminate the call to a function registered with atexit(), the behavior is undefined.

Noncompliant Code Example

In this noncompliant code example, the exit1() and exit2() functions are registered by atexit() to perform required cleanup upon program termination. However, if condition evaluates to true, exit() is called a second time, resulting in undefined behavior.

Code Block
bgColor#FFcccc
langc
#include <stdio.h>
#include <stdlib.h>

void exit1(void) {
  /* ...cleanup code... */
  return;
}

void exit2(void) {
  if (/* condition */) {
    /* ...more cleanup code... */
    exit(0);
  }
  return;
}

int main(void) {
  if (atexit(exit1) != 0) {
    /* Handle error */
  }
  if (atexit(exit2) != 0) {
    /* Handle error */
  }
  /* ...program code... */
  exit(0);
}

Because all functions registered by the atexit() function are called in the reverse order of their registration, if exit2() exits in any way other than by returning, exit1() will not be executed. This may also be true for atexit() handlers installed by support libraries.

Compliant Solution

A function that is registered as an exit handler by atexit() must exit by returning, and not in any other manner.

Code Block
bgColor#ccccFF
langc
#include <stdio.h>
#include <stdlib.h>

void exit1(void) {
  /* ...cleanup code... */
  return;
}

void exit2(void) {
  if (/* condition */) {
    /* ...more cleanup code... */
  }
  return;
}

int main(void) {
  if (atexit(exit1) != 0) {
    /* Handle error */
  }
  if (atexit(exit2) != 0) {
    /* Handle error */
  }
  /* ...program code... */
  exit(0);
}

Noncompliant Code Example

The function exit1() is registered by atexit(), so upon program termination, exit1() is called. Execution will jump back to main() and return, with undefined results.

Code Block
bgColor#FFcccc
langc
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>

jmp_buf env;
int val;

void exit1(void) {
  /* ... */
  longjmp(env, 1);
}

int main(void) {
  if (atexit(exit1) != 0) {
    /* Handle error */
  }
  /* ... */
  if (setjmp(env) == 0) {
    exit(0);
  }
  else {
    return 0;
  }
}

Compliant Solution

Careful thought about program flow is the best prevention for an invalid call to longjmp(). After the exit function has been called, avoid using longjmp() where it will cause a function to terminate.

Code Block
bgColor#ccccFF
langc
#include <stdlib.h>

void exit1(void) {
  /* ... */
  return;
}

int main(void) {
  if (atexit(exit1) != 0) {
    /* Handle error */
  }
  /* ... */
  exit(0);
}

Risk Assessment

Terminating a call to an atexit() registered handler in any way other than by returning results in undefined behavior and may result in abnormal program termination or other unpredictable behavior. It may also prevent other registered handlers from being invoked.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

ENV32-C

medium

likely

medium

P12

L1

Automated Detection

Tool

Version

Checker

Description

Section

Compass/ROSE

 

 

Section

can detect violations of this rule. In particular, it ensures that all functions registered with atexit() do not call functions such as exit()

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

Related Guidelines

CERT C++ Secure Coding Standard: ENV32-CPP. All atexit handlers must return normally

ISO/IEC 9899:1999 Section 7.20.4.3, "The exit function"

ISO/IEC TR 24772 "EWD Structured Programming" and "REU Termination Strategy"

MITRE CWE: CWE ID 705, "Incorrect Control Flow Scoping"

Bibliography


      10. Environment (ENV)      11. Signals (SIG)