...
Non-Compliant Code Example
In this code as example the main function exits two functions registered with function exit1() is registered by atexit() are called. Given the define statement exitearly=1 the program calls exit within the first function called in the atexit() cycle. The behavior that follows is undefined: some implementations will ignore the second call to exit and just continue calling the atexit functions in the appropriate order. Other implementations will enter an infinite loop with the atexit functions being called repeatedlyso upon program termination exit1() is called and certain cleanup and maintenance functions can occur. If some failure case <expr> evaluates as true though the program attempts to fully exit before the cleanup code can be processed. In these cases where expr evaluates to true exit() will be called twice and the behavior is undefined. Some compilers will simply ignore the exit() call as it in is a function registered by atexit().
Code Block | ||
---|---|---|
| ||
#include <stdio.h> #include <stdlib.h> #define exitearly 1 void exit1(void) { if(expr) puts("Exit second.\n"); } void exit2(void) { puts("Exit first.\n"); if (exitearly) { exit(); //clean up and ready program for closing exit(1); }... } int main (void) { if (expr) { atexit(exit1); atexit(exit2);... exit(1); } else { exit2(); } //program code return 0; } |
Compliant Code
To have functionality where the program can quit from within a function registered by at_exit() it is necessary to use a function used for abnormal termination such as _Exit() or abort().
<include _Exit() description>a c99 defined function is described as follows:
The function _exit terminates the calling process "immediately". Any open file descriptors belonging to the process are closed; any children of the process are inherited by process 1, init, and the process's parent is sent a SIGCHLD signal. The value status is returned to the parent process as the process's exit status, and can be collected using one of the wait family of calls. The function _Exit is equivalent to _exit.
Code Block | ||
---|---|---|
| ||
#include <stdio.h> #include <stdlib.h> #define exitearly 1#include <stdio.h> #include <stdlib.h> void exit1(void) { printf("Exit second.\n"); } void exit2 (void) { printf("Exit first.\n"); if (exitearly) { { if(expr) _Exit(); //clean up and ready program for closing _Exit(1); }... } int main (void) { if (expr) { atexit(exit1); atexit(exit2); exit(1); } else { exit2(); } ... //program code return 0; } |
All functions registered by the atexit()
function are called, in the reverse order of their registration.
...
The call to _Exit() will immediately terminate the program and no undefined behavior will happen like in the non compliant example.
Risk Assessment
Multiple calls to exit in code are likely to be rare but if exist can cause denial of service and abnormal program termination.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
MSC31-C | 1 (low) | 1 (unlikely) | 3(low) | P6 | L2 |
...