...
In this noncompliant example, exit code is written for every instance in which the function can terminate prematurely. Notice how failing to allocate obj2 produces a memory leak and fails to close the opened file.
| Wiki Markup |
|---|
_Please note that these examples assume {{errno_t}} and {{NOERR}} to be defined, as requested by \[[DCL09-C. Declare functions that return an errno error code with a return type of errno_t|DCL09-C. Declare functions that return an errno error code with a return type of errno_t]\]. An equivalent compatible example would define {{errno_t}} as an {{int}} and {{NOERR}} as zero._ |
| Code Block | ||
|---|---|---|
| ||
typedef struct object { // A generic struct -- The contents don't matter
int propertyA, propertyB, propertyC;
} object_t;
errno_t do_something(void){
FILE *fin;
object_t *obj1, *obj2;
errno_t ret_val;
fin = fopen("some_file", "r");
if (fin == NULL){
return errno;
}
obj1 = malloc(sizeof(object_t));
if (obj1 == NULL){
ret_val = errno;
fclose(fin);
return ret_val;
}
obj2 = malloc(sizeof(object_t));
if (obj2 == NULL){
ret_val = errno;
fclose(fin);
return ret_val; // Forgot to free obj1 !!
}
// ... more code ...
fclose(fin);
free(obj1);
free(obj2);
return NOERR;
}
|
This is also just a small example; in much larger examples, errors like this would be even harder to detect.
...
In this revised version, we have used a goto-chain in replacement of each individual return segment. If there is no error, control flow will fall through to the SUCCESS label, release all of the resources and return NOERR. In the case of an error, the return value will be set to errno, control flow will jump to the proper failure label, and the appropriate resources will be released before returning. Please note that these examples assume {{errno_t}} and {{NOERR}} to be defined, as requested by \[[DCL09-C. Declare functions that return an errno error code with a return type of errno_t|DCL09-C. Declare functions that return an errno error code with a return type of errno_t]\]. An equivalent compatible example would define {{errno_t}} as an {{int}} and {{NOERR}} as zero.Wiki Markup
| Code Block | ||
|---|---|---|
| ||
// ... assume the same struct as above ...
errno_t do_something(void){
FILE *fin;
object_t *obj1, *obj2;
errno_t ret_val = NOERR; // Initially assume a successful return value
fin = fopen("some_file", "r");
if (fin == NULL){
ret_val = errno;
goto FAIL_FIN;
}
obj1 = malloc(sizeof(object_t));
if (obj1 == NULL){
ret_val = errno;
goto FAIL_OBJ1;
}
obj2 = malloc(sizeof(object_t));
if (obj2 == NULL){
ret_val = errno;
goto FAIL_OBJ2;
}
// ... more code ...
SUCCESS: // Free everything
free(obj2);
FAIL_OBJ2: // Otherwise, free only the objects we allocated
free(obj1);
FAIL_OBJ1:
fclose(fin);
FAIL_FIN:
return ret_val;
}
|
...