Versions Compared

Key

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

...

Code Block
bgColor#FFCCCC
typedef struct object {   // A generic struct -- The contents don't matter
  int propertyA, propertyB, propertyC;
} object_t;


interrno_t do_something(void){
  FILE *fin;
  object_t *obj1, *obj2;
  errno_t ret_val;
  
  fin = fopen("some_file", "r");
  if (fin == NULL){
    return -1errno;
  }

  obj1 = malloc(sizeof(object_t));
  if (obj1 == NULL){
    ret_val = errno;
    fclose(fin);
    return -1ret_val;
  }

  obj2 = malloc(sizeof(object_t));
  if (obj2 == NULL){
    ret_val = errno;
    fclose(fin);
    return -1ret_val;  // Forgot to free obj1 !!
  }

  // ... more code ...
}

...

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 RET_SUCCESS NOERR. In the case of an error, the return value will be set to RET_ERROR errno, control flow will jump to the proper failure label, and the appropriate resources will be released before returning.

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#CCCCFF
// ... assume the same struct as above ...

#define RET_SUCCESS  0
#define RET_ERROR   -1

int errno_t do_something(void){
  FILE *fin;
  object_t *obj1, *obj2;
  interrno_t ret_val = RET_SUCCESSNOERR; // Initially assume a successful return value

  fin = fopen("some_file", "r");
  if (fin == NULL){
    ret_val = RET_ERRORerrno;
    goto FAIL_FIN;
  }

  obj1 = malloc(sizeof(object_t));
  if (obj1 == NULL){
    ret_val = RET_ERRORerrno;
    goto FAIL_OBJ1;
  }

  obj2 = malloc(sizeof(object_t));
  if (obj2 == NULL){
    ret_val = RET_ERRORerrno;
    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;
}

...