Many functions require the allocation of multiple objects. Failing and returning somewhere in the middle of this function without freeing all of the allocated memory could produce a memory leak. It is a common error to forget to free one (or all) of the objects in this manner, so a goto-chain is the simplest and cleanest way to organize exits when order is preserved.
Noncompliant Code Example
int do_something(void){ // ... definitions ... obj1 = malloc(...); if (!obj1){ return -1; } obj2 = malloc(...); if (!obj2){ free(obj1); return -1; } obj3 = malloc(...); if (!obj3){ free(obj2); return -1; // Forgot to free obj1 -- Memory leak } // ... more code ... }
Notice how there is a memory leak if obj3 cannot be allocated. This is also just a small example; in much larger examples, errors like this would be even harder to detect. Hence, the goto-chain...
Compliant Solution
int do_something(void){ // ... definitions ... obj1 = malloc(...); if (!obj1){ goto FAIL_OBJ1; } obj2 = malloc(...); if (!obj2){ goto FAIL_OBJ2; } obj3 = malloc(...); if (!obj3){ goto FAIL_OBJ3; } // ... more code ... SUCCESS: // Return normally return 0; FAIL_OBJ3: // Otherwise, free objects in order free(obj2); FAIL_OBJ2: free(obj1); FAIL_OBJ1: return -1; }
This code is guaranteed to clean up properly whenever an allocation fails. It is cleaner and prevents rewriting of similar code upon every function error.
Rule |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
---|---|---|---|---|---|
MEM37-C |
low |
probable |
medium |
P3 |
L3 |
References
[[ISO/IEC 9899:1999]] Section 7.20.3, "Memory management functions"
[[Seacord 05]] Chapter 4, "Dynamic Memory Management"