...
This is just a small example; in much larger examples, errors like this are even harder to detect.
Compliant Solution (POSIX, Nested Ifs)
This compliant solution uses nested if statements to properly close files and free memory in the case that any error occurs. When the number of resources to manage is small (3 in this example), nested if statements will be simpler than a goto chain.
Code Block | ||||
---|---|---|---|---|
| ||||
/* ... Assume the same struct used previously ... */
errno_t do_something(void) {
FILE *fin1, *fin2;
object_t *obj;
errno_t ret_val = NOERR; /* Initially assume a successful return value */
if ((fin1 = fopen("some_file", "r")) != NULL) {
if ((fin2 = fopen("some_other_file", "r")) != NULL) {
if ((obj = malloc(sizeof(object_t))) != NULL) {
/* ... More code ... */
/* Clean-up & handle errors */
free(obj);
} else {
ret_val = errno;
}
fclose(fin2);
} else {
ret_val = errno;
}
fclose(fin1);
} else {
ret_val = errno;
}
return ret_val;
} |
Compliant Solution (POSIX, Goto Chain)
Occasionally, the number of resources to manage in one function will be too large to permit using nested ifs to manage them.
In this revised version, a a goto
chain replaces chain replaces each individual return segment. If no error occurs, control flow falls through to the the SUCCESS
label label, releases all of the resources, and returns returns NOERR
. If an error occurs, the return value is set to to errno
, control flow jumps to the proper failure label, and the appropriate resources are released before returning.
...