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 ...
FAIL_OBJ3:
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.
Recommendation |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
|---|---|---|---|---|---|
MEM86-C |
low |
probable |
medium |
P3 |
L3 |