Resource cleanup releases allocated memory and restores execution state when an operation succeeds, fails, or terminates. Robust C functions preserve errno when reporting errors and ensure that acquired resources are not abandoned. section 15.6
One cleanup path for several failures
A number-printing function allocates a buffer, may enlarge it with realloc, and can fail because allocation, size limits, or output operations fail. The optimized version routes failures to a shared CLEANUP label, where the allocated buffer is released. This keeps free reachable even when an output or reallocation error occurs. Saving errno on entry and restoring it through error_cleanup prevents intermediate operations from changing the reported error state. section 15.6
Reliable cleanup follows explicit rules:
- Save global error state before operations that might modify it, and restore errno while returning the failure code. section 15.6
- Free successfully allocated memory on every error path, including failures detected after output or buffer growth. section 15.6
- Use a common cleanup block when several later operations can fail and each must release the same resources. section 15.6
- Prefer normal return or exit so the runtime can perform established library cleanups; reserve alternative termination functions for cases that require bypassing them. section 8.8
void sayGoodBye(void) {
if (errno) perror("terminating with error condition");
fputs("Good Bye\n", stderr);
}
int main(int argc, char* argv[argc+1]) {
atexit(sayGoodBye);
...
}
An atexit handler can perform termination cleanup, such as freeing memory or writing a final log timestamp, after normal program completion. section 8.8





