the goto-cleanup pattern
/ goto: "GOH-too" /
Imagine leaving a building with several doors, but the rule is everyone exits through the same back door where the lights, alarm, and locks all get handled in one place. You do not turn off the lights at each door individually; you head to the one exit and the shutdown happens there, correctly, every time. The goto-cleanup pattern applies this idea to a C function: instead of scattering cleanup code at every early return, you jump to a single cleanup section at the bottom and release resources there.
Concretely, you label sections at the end of the function and use C's goto to jump to them on failure. As you acquire resources, you arrange the cleanup labels in reverse order of acquisition, so that jumping to the right label undoes exactly what has been acquired so far. A typical skeleton: open a file; if a later malloc() fails, goto close_file; if a still-later step fails, goto free_buf (which then falls through to close_file). The cleanup labels are stacked so each one does its own release and then falls through into the next, releasing things in the reverse order they were taken. This is the main reason you will see goto - normally discouraged - used and even recommended in idiomatic C, including throughout the Linux kernel. It directly solves the cleanup problem: there is one place that frees each resource, so it is easy to verify nothing leaks and nothing is freed twice.
Why it matters: C has no automatic cleanup, no destructors, no 'finally' block. Without this pattern, error handling degenerates into deeply nested if-else or copy-pasted cleanup at every return, which is exactly where double-frees and leaks breed. The honest caveat: goto-cleanup is disciplined, structured use of goto (always jumping forward, only to cleanup labels) - it is not a licence for spaghetti jumps. And it needs care: variables must be initialised to safe 'nothing acquired yet' values (a pointer to NULL, a descriptor to -1) before the first possible goto, so that the cleanup code can tell what was actually acquired and skip releasing what was not.
int f(void) { int rc = -1; char *buf = NULL; int fd = open("x", O_RDONLY); if (fd < 0) goto out; buf = malloc(1024); if (buf == NULL) goto close_fd; /* ... work ...; rc = 0; */ free(buf); close_fd: close(fd); out: return rc; } - the labels release in reverse order of acquisition, and each early exit skips releasing what it never got.
One cleanup chain at the bottom; jump in at the point matching how far you got.
Initialise resource variables to a 'not acquired' sentinel (NULL, -1) before any goto, or the cleanup may free a garbage pointer or close descriptor 0. goto-cleanup is structured (forward-only, to labels); it is not an invitation to jump around freely.