...
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 | ||||
---|---|---|---|---|
| ||||
#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); } |
...
A function that is registered as an exit handler by atexit()
must exit by returning, and not in any other manner.
Code Block | ||||
---|---|---|---|---|
| ||||
#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); } |
...
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 | ||||
---|---|---|---|---|
| ||||
#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; } } |
...
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 | ||||
---|---|---|---|---|
| ||||
#include <stdlib.h> void exit1(void) { /* ... */ return; } int main(void) { if (atexit(exit1) != 0) { /* Handle error */ } /* ... */ exit(0); } |
...