Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

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
bgColor#FFCCCC
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. Wiki MarkupPlease 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
bgColor#CCCCFF
// ... 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;
}

...