Versions Compared

Key

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

...

This noncompliant code example consists of two application-independent functions f() and g(). The f() function is part of the external API for the module; the g() function is an internal function.

Code Block
bgColor#ffcccc
langc
void g(void) {
  /* ... */
  if (something_really_bad_happens) {
    fprintf(stderr, "Something really bad happened!\n");
    abort();
  }
  /* ... */
}

void f(void) {
  g();
  /* ... do the rest of f ... */
}

...

One way to indicate errors is to return a value indicating success or failure. This compliant solution ensures each function returns a value of type errno_t, where 0 indicates that no error has occurred.

Code Block
bgColor#ccccff
langc
const errno_t ESOMETHINGREALLYBAD = 1;

errno_t g(void) {
  /* ... */
  if (something_really_bad_happens) {
    return ESOMETHINGREALLYBAD;
  }
  /* ... */
  return 0;
}

errno_t f(void) {
  errno_t status = g();
  if (status != 0) return status;

  /* ... do the rest of f ... */

  return 0;
}

...

Instead of encoding status indicators in the return value, each function can take a pointer as an argument, which is used to indicate errors. In the following example, each function uses a errno_t\ * argument to report errors.

Code Block
bgColor#ccccff
langc
const errno_t ESOMETHINGREALLYBAD = 1;

void g(errno_t * err) {
  if (err == NULL) {
    /* Handle null pointer */
  }
  /* ... */
  if (something_really_bad_happens) {
    *err = ESOMETHINGREALLYBAD;
  } else {
    /* ... */
    *err = 0;
  }
}

void f(errno_t * err) {
  if (err == NULL) {
    /* Handle null pointer */
  }
  g(err);
  if (*err == 0) {
    /* ... do the rest of f ... */
  }
  return 0;
}

...

The original errno variable was the Standard C library's implementation of error handling using this approach.

Code Block
bgColor#ccccff
langc
errno_t my_errno; /* also declared in a .h file */
const errno_t ESOMETHINGREALLYBAD = 1;

void g(void) {
  /* ... */
  if (something_really_bad_happens) {
    my_errno = ESOMETHINGREALLYBAD;
    return;
  }
  /* ... */
}

void f(void) {
  my_errno = 0;
  g();
  if (my_errno != 0) {
    return;
  }
  /* ... do the rest of f ... */
}

...

The following example uses setjmp() and longjmp() to ensure that control flow is disrupted in the event of error, and also uses the my_errno indicator from the previous example. See recommendation MSC22-C. Use the setjmp(), longjmp() facility securely for more info on setjmp() and longjmp().

Code Block
bgColor#ccccff
langc
#include <setjmp.h>

const errno_t ESOMETHINGREALLYBAD = 1;

jmp_buf exception_env;

void g(void) {
  /* ... */
  if (something_really_bad_happens) {
    longjmp(exception_env, ESOMETHINGREALLYBAD);
  }
  /* ... */
}

void f(void) {
  g();
  /* ... do the rest of f ... */
}

/* ... */
if (setjmp(exception_env) != 0) {
  /* if we get here, an error occurred; do not continue processing */
}
/* ... */
f();
/* if we get here, no errors occurred */
/* ... */

...