Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Renamed, added examples, and Other Languages section linking to the C++ counterpart.

Many functions will either return a valid value or a value of the correct return type that indicates an error (for example, -1 or a null pointer). It is important that these function return values are checked to ensure that an error has not occurred. Otherwise, unpredictable results are possible.

Non-Compliant Code Example

Assuming that all calls to such functions will succeed and failing to check the return value for an indication of an error is a dangerous practice that may lead to unexpected or undefined behavior when an error occurs. Therefore, it is essential that programs detect and appropriately handle all errors in accordance with an error handling policy as discussed in ERR00-C. Adopt and implement a consistent and comprehensive error-handling policy.

Anchor
nce_setlocale
nce_setlocale

Noncompliant Code Example (setlocale())

In the noncompliant example below, the function utf8_to_ucs() attempts to convert a sequence of UTF-8 characters to UCS. It first invokes setlocale() to set the global locale to "en_US.UTF-8" but it fails to check for failure. setlocale() will fail by returning a null pointer, for example when the locale is not installed (the function may fail for other reasons as well, such as the lack of resources). Depending on the sequence of characters pointed to by utf8 the subsequent call to mbstowcs() may fail or result in the function storing an unexpected sequence of wide characters in the supplied buffer ucs.

Code Block
bgColor#FFcccc

size_t utf8_to_ucs(wchar_t *ucs, size_t n, const char *utf8) {
  setlocale(LC_CTYPE, "en_US.UTF-8");
  return mbstowcs(ucs, utf8, n);
}

Anchor
cs_setlocale
cs_setlocale

Compliant Solution Example (setlocale())

A compliant solution checks the value returned by setlocale() and avoids calling mbstowcs() if the function fails. The function also takes care to restore the locale to its initial setting before returning control to the caller.

Code Block
bgColor#ccccFF

size_t utf8_to_ucs(wchar_t *ucs, size_t n, const char *utf8) {
  const char *save;
  save = setlocale(LC_CTYPE, "en_US.UTF-8");
  if (NULL == save) {
    /* Propagate error to caller */
    return (size_t)-1;
  }

  n = mbstowcs(ucs, utf8, n);
  if (NULL == setlocale(LC_CTYPE, save))
    n = -1;

  return n;
}

Anchor
nce_signal
nce_signal

Noncompliant Code Example (signal())

In the noncompliant example below the function signal() is invoked to install a handler for the SIGINT signal. signal() returns a pointer to the previously installed handler on success and the value SIG_ERR on failure. However, since the caller fails to check for errors, when signal() fails the function may proceed with the lengthy computation without the ability to interrupt it.

Code Block
bgColor#FFcccc

volatile sig_atomic_t interrupted;

void handle_interrupt(int signo) {
  interrupted = 1;
}

int f() {
  int result = 0;

  signal(SIGINT, handle_interrupt);

  while (0 == result && 0 == interrupted) {
    /* Perform a lengthy computation */
  }

  /* Indicate success or failure */
  return interrupted ? -1 : result;
}

Anchor
cs_signal
cs_signal

Compliant Solution (signal())

A compliant solution checks the value returned by the signal() function and avoids performing the lengthy computation when signal() fails. The calling function also takes care to restore the disposition for the SIGINT signal to its initial setting before returning control to the caller.

Code Block
bgColor#ccccFF

volatile sig_atomic_t interrupted;

void handle_interrupt(int signo) {
  interrupted = 1;
}

int f() {
  int result = 0;
  void (*saved_handler)(int);
  saved_handler = signal(SIGINT, handle_interrupt);

  if (SIG_ERR == saved_handler) {
    /* Indicate failure */
    return -1;
  }

  while (0 == result && 0 == interrupted) {
    /* Perform a lengthy computation */
  }

  if (SIG_ERR == signal(SIGINT, saved_handler))
    return -1;

  /* Indicate success or failure */
  return interrupted ? -1 : result;
}

Anchor
nce_malloc
nce_malloc

Noncompliant Code Example (malloc())

In this noncompliant code In this example, input_string is copied into dynamically allocated memory referenced by str. However, the result of malloc(input_string_size) is not checked before str is referenced. Consequently, if malloc() fails, the program will abnormally terminatehas undefined behavior (see undefined behavior 103 in Annex J). In practice, this typically leads to an abnormal termination of the process, thusproviding an opportunity for a denial-of-service attack. In some cases it may be the source of other vulnerabilities as well (see the #Related Vulnerabilities section).

See also MEM32-C. Detect and handle memory allocation errors.

Code Block
bgColor#FFcccc
void f(char *strinput_string) {
  size_t size = (char*)malloc(strlen(input_string) + 1;
  char *str = (char *)malloc(size);
  strcpy(str, input_string);
  /* What if malloc() fails? ... */
}

Anchor
cs_malloc
cs_malloc

Compliant Solution (malloc())

The malloc() function , as well as the other memory allocation functions, returns either a null pointer or a pointer to the allocated space. Always test the returned pointer to make sure ensure it is not equal to zero (NULL) before referencing the pointer. Handle the error condition appropriately when the returned pointer is equal to zero NULL. When recovery from the allocation failure isn't possible, propagate the failure to the caller.

Code Block
bgColor#ccccff
int f(char *strinput_string) {
  size_t size = (char*)malloc(strlen(input_string) + 1;
  char *str = (char *)malloc(size);
  if (str == NULL) {
    /* Handle Allocation Errorallocation failure and return error status */
    return -1;
  }
  strcpy(str, input_string);
  /* ... */
  free(str);
  return 0;
}

Risk Assessment

Failing to detect error conditions can lead to unpredictable results, including abnormal program termination and denial-of-service attacks or, in some situations, could even allow an attacker to run arbitrary code.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

ERR30-C

3 (high)

3 (likely)

2 (medium)

P18

L1

Related Coding Practices

Other Languages

This rule appears in the C++ Secure Coding Standard as ERR10-CPP. Check for error conditions.

References

Wiki Markup
\[[CWE|AA. References#CWE]\] [CWE-252|http://cwe.mitre.org/data/definitions/252.html]: Unchecked Return Value
\[[CWE|AA. References#CWE]\] [CWE-253|http://cwe.mitre.org/data/definitions/253.html]: Incorrect Check of Function Return Value
\[[CWE|AA. References#CWE]\] [CWE-390|http://cwe.mitre.org/data/definitions/390.html]: Detection of Error Condition Without Action
\[[CWE|AA. References#CWE]\] [CWE-391|http://cwe.mitre.org/data/definitions/391.html]: Unchecked Error Condition
\[[Henricson 97|AA. References#Henricson 97]\] Recommendation 12.1 Check for all errors reported from functions

...