Versions Compared

Key

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

All standard library functions, including input/output functions and memory allocation functions, return either a valid value or a value of the correct return type that indicates an error (for example, −1 or a null pointer). 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. 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.

...

The successful completion or failure of each of the standard library functions listed in the following table below shall be determined either by comparing the function’s return value with the value listed in the column labeled “Error Return” or by calling one of the library functions mentioned in the footnotes to the same column.

Function

Successful Return

Error Return

aligned_alloc()

pointer Pointer to space

NULL

asctime_s()

zero0

nonzeroNonzero

at_quick_exit()

zero0

nonzeroNonzero

atexit()

zero0

nonzeroNonzero

bsearch()

pointer Pointer to matching element

NULL

bsearch_s()

pointer Pointer to matching element

NULL

btowc()

converted Converted wide character

WEOF

c16rtomb()

number Number of bytes

(size_t)(-1)

c32rtomb()

number Number of bytes

(size_t)(-1)

calloc()

pointer Pointer to space

NULL

clock()

processor Processor time

(clock_t)(-1)

cnd_broadcast()

thrd_success

thrd_error

cnd_init()

thrd_success

thrd_nomem or thrd_error

cnd_signal()

thrd_success

thrd_error

cnd_timedwait()

thrd_success

thrd_timedout or thrd_error

cnd_wait()

thrd_success

thrd_error

ctime_s()

zero0

nonzeroNonzero

fclose()

zero0

EOF (negative)

fflush()

zero0

EOF (negative)

fgetc()

character Character read

EOF2

fgetpos()

zero0

nonzeroNonzero

fgets()

pointer Pointer to string

NULL

fgetwc()

wide Wide character read

WEOF2

fopen()

pointer Pointer to stream

NULL

fopen_s()

zero0

nonzeroNonzero

fprintf()

number Number of characters (nonnegative)

negativeNegative

fprintf_s()

number Number of characters (nonnegative)

negativeNegative

fputc()

character Character written

EOF1

fputs()

nonnegativeNonnegative

EOF (negative)

fputws()

nonnegativeNonnegative

EOF (negative)

fread()

elements Elements readelements

Elements read

freopen()

pointer Pointer to stream

NULL

freopen_s()

zero0

nonzeroNonzero

fscanf()

number Number of conversions (nonnegative)

EOF (negative)

fscanf_s()

number Number of conversions (nonnegative)

EOF (negative)

fseek()

zero0

nonzeroNonzero

fsetpos()

zero0

nonzeroNonzero

ftell()

file File position

−1L

fwprintf()

number Number of wide characters (nonnegative)

negativeNegative

fwprintf_s()

number Number of wide characters (nonnegative)

negativeNegative

fwrite()

elements Elements writtenelements

Elements written

fwscanf()

number Number of conversions (nonnegative)

EOF (negative)

fwscanf_s()

number Number of conversions (nonnegative)

EOF (negative)

getc()

character Character read

EOF2

getchar()

character Character read

EOF2

getenv()

pointer Pointer to string

NULL

getenv_s()

pointer Pointer to string

NULL

gets_s()

pointer Pointer to string

NULL

getwc()

wide Wide character read

WEOF

getwchar()

wide Wide character read

WEOF

gmtime()

pointer Pointer to broken-down time

NULL

gmtime_s()

pointer Pointer to broken-down time

NULL

localtime()

pointer Pointer to broken-down time

NULL

localtime_s()

pointer Pointer to broken-down time

NULL

malloc()

pointer Pointer to space

NULL

mblen(), s != NULL

number Number of bytes

−1

mbrlen(), s != NULL

number Number of bytes or status

(size_t)(-1)

mbrtoc16()

number Number of bytes or status

(size_t)(-1), errno == EILSEQ

mbrtoc32()

number Number of bytes or status

(size_t)(-1), errno == EILSEQ

mbrtowc(), s != NULL

number Number of bytes or status

(size_t)(-1), errno == EILSEQ

mbsrtowcs()

number Number of non-null elements

(size_t)(-1), errno == EILSEQ

mbsrtowcs_s()

zero0

nonzeroNonzero

mbstowcs()

number Number of non-null elements

(size_t)(-1)

mbstowcs_s()

zero0

nonzeroNonzero

mbtowc(), s != NULL

number Number of bytes

−1

memchr()

pointer Pointer to located character

NULL

mktime()

calendar Calendar time

(time_t)(-1)

mtx_init()

thrd_success

thrd_error

mtx_lock()

thrd_success

thrd_error

mtx_timedlock()

thrd_success

thrd_timedout or thrd_error

mtx_trylock()

thrd_success

thrd_busy or thrd_error

mtx_unlock()

thrd_success

thrd_error

printf_s()

number Number of characters (nonnegative)

negativeNegative

putc()

character Character written

EOF1

putwc()

wide Wide character written

WEOF

raise()

zero0

nonzeroNonzero

realloc()

pointer Pointer to space

NULL

remove()

zero0

nonzeroNonzero

rename()

zero0

nonzeroNonzero

setlocale()

pointer Pointer to string

NULL

setvbuf()

zero0

nonzeroNonzero

scanf()

number Number of conversions (nonnegative)

EOF (negative)

scanf_s()

number Number of conversions (nonnegative)

EOF (negative)

signal()

pointer Pointer to previous function

SIG_ERR, errno > 0

snprintf()

number Number of characters that would be written (nonnegative)

negativeNegative

snprintf_s()

number Number of characters that would be written (nonnegative)

negativeNegative

sprintf()

number Number of non-null characters written

negativeNegative

sprintf_s()

number Number of non-null characters written

negativeNegative

sscanf()

number Number of conversions (nonnegative)

EOF (negative)

sscanf_s()

number Number of conversions (nonnegative)

EOF (negative)

strchr()

pointer Pointer to located character

NULL

strerror_s()

zero0

nonzeroNonzero

strftime()

number Number of non-null characters

zero0

strpbrk()

pointer Pointer to located character

NULL

strrchr()

pointer Pointer to located character

NULL

strstr()

pointer Pointer to located string

NULL

strtod()

converted Converted value

zero0, errno == ERANGE

strtof()

converted Converted value

zero0, errno == ERANGE

strtoimax()

converted Converted value

INTMAX_MAX or INTMAX_MIN, errno == ERANGE

strtok()

pointer Pointer to first character of a token

NULL

strtok_s()

pointer Pointer to first character of a token

NULL

strtol()

converted Converted value

LONG_MAX or LONG_MIN, errno == ERANGE

strtold()

converted Converted value

zero0, errno == ERANGE

strtoll()

converted Converted value

LLONG_MAX or LLONG_MIN, errno == ERANGE

strtoumax()

converted Converted value

UINTMAX_MAX, errno == ERANGE

strtoul()

converted Converted value

ULONG_MAX, errno == ERANGE

strtoull()

converted Converted value

ULLONG_MAX, errno == ERANGE

strxfrm()

length Length of transformed string

>= n

swprintf()

number Number of non-null wide characters

negativeNegative

swprintf_s()

number Number of non-null wide characters

negativeNegative

swscanf()

number Number of conversions (nonnegative)

EOF (negative)

swscanf_s()

number Number of conversions (nonnegative)

EOF (negative)

thrd_create()

thrd_success

thrd_nomem or thrd_error

thrd_detach()

thrd_success

thrd_error

thrd_join()

thrd_success

thrd_error

thrd_sleep()

zero0

negative

time()

calendar Calendar time

(time_t)(-1)

timespec_get()

baseBase

zero0

tmpfile()

pointer Pointer to stream

NULL

tmpfile_s()

zero0

nonzeroNonzero

tmpnam()

nonNon-null pointer

NULL

tmpnam_s()

zero0

nonzeroNonzero

tss_create()

thrd_success

thrd_error

tss_get()

value Value of thread-specific storage

zero0

tss_set()

thrd_success

thrd_error

ungetc()

character Character pushed back

EOF (negative; see below)

ungetwc()

character Character pushed back

WEOF (negative)

vfprintf()

number Number of characters (nonnegative)

negativeNegative

vfprintf_s()

number Number of characters (nonnegative)

negativeNegative

vfscanf()

number Number of conversions (nonnegative)

EOF (negative)

vfscanf_s()

number Number of conversions (nonnegative)

EOF (negative)

vfwprintf()

number Number of wide characters (nonnegative)

negativeNegative

vfwprintf_s()

number Number of wide characters (nonnegative)

negativeNegative

vfwscanf()

number Number of conversions (nonnegative)

EOF (negative)

vfwscanf_s()

number Number of conversions (nonnegative)

EOF (negative)

vprintf_s()

number Number of characters (nonnegative)

negativeNegative

vscanf()

number Number of conversions (nonnegative)

EOF (negative)

vscanf_s()

number Number of conversions (nonnegative)

EOF (negative)

vsnprintf()

number Number of characters that would be written (nonnegative)

negativeNegative

vsnprintf_s()

number Number of characters that would be written (nonnegative)

negativeNegative

vsprintf()

number Number of non-null characters (nonnegative)

negativeNegative

vsprintf_s()

number Number of non-null characters (nonnegative)

negativeNegative

vsscanf()

number Number of conversions (nonnegative)

EOF (negative)

vsscanf_s()

number Number of conversions (nonnegative)

EOF (negative)

vswprintf()

number Number of non-null wide characters

negativeNegative

vswprintf_s()

number Number of non-null wide characters

negativeNegative

vswscanf()

number Number of conversions (nonnegative)

EOF (negative)

vswscanf_s()

number Number of conversions (nonnegative)

EOF (negative)

vwprintf_s()

number Number of wide characters (nonnegative)

negativeNegative

vwscanf()

number Number of conversions (nonnegative)

EOF (negative)

vwscanf_s()

number Number of conversions (nonnegative)

EOF (negative)

wcrtomb()

number Number of bytes stored

(size_t)(-1)

wcschr()

pointer Pointer to located wide character

NULL

wcsftime()

number Number of non-null wide characters

zero0

wcspbrk()

pointer Pointer to located wide character

NULL

wcsrchr()

pointer Pointer to located wide character

NULL

wcsrtombs()

number Number of non-null bytes

(size_t)(-1), errno == EILSEQ

wcsrtombs_s()

zero0

nonzeroNonzero

wcsstr()

pointer Pointer to located wide string

NULL

wcstod()

converted Converted value

zero0, errno == ERANGE

wcstof()

converted Converted value

zero0, errno == ERANGE

wcstoimax()

converted Converted value

INTMAX_MAX or INTMAX_MIN, errno == ERANGE

wcstok()

pointer Pointer to first wide character of a token

NULL

wcstok_s()

pointer Pointer to first wide character of a token

NULL

wcstol()

converted Converted value

LONG_MAX or LONG_MIN, errno == ERANGE

wcstold()

converted Converted value

zero0, errno == ERANGE

wcstoll()

converted Converted value

LLONG_MAX or LLONG_MIN, errno == ERANGE

wcstombs()

number Number of non-null bytes

(size_t)(-1)

wcstombs_s()

zero0

nonzeroNonzero

wcstoumax()

converted Converted value

UINTMAX_MAX, errno == ERANGE

wcstoul()

converted Converted value

ULONG_MAX, errno == ERANGE

wcstoull()

converted Converted value

ULLONG_MAX, errno == ERANGE

wcsxfrm()

length Length of transformed wide string

>= n

wctob()

converted Converted character

EOF

wctomb(), s != NULL

number Number of bytes stored

−1

wctomb_s(), s != NULL

number Number of bytes stored

−1

wctrans()

valid Valid argument to towctrans

zero0

wctype()

valid Valid argument to iswctype

zero0

wmemchr()

pointer Pointer to located wide character

NULL

wprintf_s()

number Number of wide characters (nonnegative)

negativeNegative

wscanf()

number Number of conversions (nonnegative)

EOF (negative)

wscanf_s()

number Number of conversions (nonnegative)

EOF (negative)

When FIO35-C. Use feof() and ferror() to detect end-of-file and file errors when sizeof(int) == sizeof(char) applies, callers shall determine the success or failure of the functions above in this table as follows:

  1. Anchor
    use_ferror
    use_ferror
     by By calling ferror
  2. Anchor
    use_feof_or_ferror
    use_feof_or_ferror
     by By calling ferror and feof

Anchor
ungetc
ungetc
The ungetc() function does not set the error indicator even when it fails, so it is not possible to check for errors reliably unless it is known that the argument is not equal to EOF. C99 The C Standard [ISO/IEC 9899:2011] states that "one character of pushback is guaranteed," so this should not be an issue if at most one character is ever pushed back before reading again. (See FIO13-C. Never push back anything other than one read character.)

...

In this noncompliant example, 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 does not 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#ccccff
langc
signal_info * start = malloc(num_of_records * sizeof(signal_info));
if (start == NULL) {
  /* Handle Allocationallocation Errorerror */
}
signal_info * point = (signal_info *)start;
point = start + temp_num - 1; 
memcpy(point->sig_desc, tmp2, strlen(tmp2));
/* ... */ 

...

In this noncompliant code example, input_string is copied into dynamically allocated memory referenced by str. However, the result of malloc() is not checked before str is referenced. Consequently, if malloc() fails, the program has undefined behavior. (See undefined behavior 109behavior 109 in Annex J of the C Standard.) In practice, an abnormal termination of the process typically occurs, providing 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.

...

In this noncompliant code example, the fseek() function is used to set the file position to a location offset in the file referred to by file prior to reading a sequence of bytes from the file. However, if an I/O error occurs during the seek operation the subsequent read will read will fill the buffer with the wrong contents.

...

Compliant Solution (fseek())

According to the C standardStandard, the fseek() function returns a non-zero nonzero value to indicate that an error occurred [ISO/IEC 9899:2011]. Testing for this condition before proceeding to read from the file eliminates the chance of operating on the wrong portion of the file if fseek() failed. Always test the returned value to make sure an error did not occur before operating on the file. If an error does occur, handle it appropriately.

Code Block
bgColor#ccccff
langc
size_t read_at(FILE *file, long offset, void *buf, size_t nbytes) {
  if (fseek(file, offset, SEEK_SET) != 0) {
    /* Indicate error to caller. */
    return 0;
  }
  return fread(buf, 1, nbytes, file);
}

...

In the following noncompliant code example, snprinf() is assumed to succeed. However, if the call fails (for example, because of insufficient memory, as described in GNU libc bug 441945), the subsequent call to log_message() is likely to result in undefined behavior since the character buffer is not initialized and need not be NUL null-terminated.

Code Block
bgColor#ffcccc
langc
extern void log_message(const char*);

void f(int i, int width, int prec) {
  char buf[40];
  snprintf(buf, sizeof buf, "i = %*.*i", width, prec, i);
  log_message(buf);
  /* ... */
}

...

A compliant solution avoids assuming that snprintf() succeeds regardless of its arguments and tests the return value of the function before using the buffer the function was passed to format output into. In addition, a compliant solution takes care to NULnull-terminate the formatted string in case the provided buffer wasn't large enough for snprintf() to append the terminating NULnull.

Code Block
bgColor#ccccff
langc
extern void log_message(const char*);

void f(int i, int width, int prec) {
  char buf[40];
  int n;
  n = snprintf(buf, sizeof buf, "i = %*.*i", width, prec, i);
  if (n < 0) {
    /* Handle snprintf() error */
    strcpy(buf, "unknown error");
  }

  /* NULNull-terminate buffer in case of overflow */
  buf[sizeof buf - 1] = '\0';    
  log_message(buf);
}

When the length of the formatted string is unbounded, it is best to invoke the function twice, once with a NULL buffer to determine the size of output, then dynamically allocate a buffer of sufficient size, and finally call snprintf() again to format the output into the dynamically allocated buffer. Even with this approach the success of all calls still needs to be tested, and any errors still need to be appropriately handled. A possible optimization is to first attempt to format the string into a reasonably small buffer allocated on the stack and only when the buffer turns out to be too small allocate one of a sufficient size dynamically. This approach is shown in the following compliant solution below.

Code Block
bgColor#ccccff
langc
void f(int i, int width, int prec) {
  char buffer[20];
  char *buf = buffer;
  int n  = sizeof buffer;
  const char fmt[] = "i = %*.*i";

  n = snprintf(buf, n, fmt, width, prec, i);
  if (n < 0) {
    /* Handle snprintf() error */
    strcpy(buffer, "unknown error");
    goto write_log;
  }

  if (n < sizeof buffer)
    goto write_log;

  buf = (char*)malloc(n + 1);
  if (NULL == buf) {
    /* Handle malloc() error */
    strcpy(buffer, "unknown error");
    goto write_log;
  }

  n = snprintf(buf, n, fmt, width, prec, i);
  if (n < 0) {
    /* Handle snprintf() error */
    strcpy(buffer, "unknown error");
  }

write_log:
  log_message(buf);

  if (buf != buffer)
    free(buf);
}

...

Function

Successful Return

Error Return

errno

fmemopen()

pointer to a FILE object

NULL

ENOMEM

open_memstream()

pointer to a FILE object

NULL

ENOMEM

posix_memalign()

0

non-zero Nonzero #2

unchanged #2

  1. Anchor
    1
    1
     Setting errno is a POSIX [ISO/IEC 9945:2008] extension to the C standardStandard.
  2. Anchor
    2
    2
     On error, posix_memalign() returns a value that corresponds to one of the constants defined in the <errno.h> header. The function does not set errno. The posix_memalign() function is optional and is not required to be provided by conforming implementations.

...

In the following noncompliant code example, fmemopen() and open_memstream() are assumed to succeed. However, if the calls fails, the two file pointers in and out will out will be NULL and the program has undefined behavior.

Code Block
bgColor#ffcccc
langc
int main(int argc, char *argv[])
{
FILE *out, *in;
 
if (argc != 2) {
	/* Handle Errorerror */
}
 
in = fmemopen(argv[1], strlen(argv[1]), "r"); /* violation */
/* Use in */
 
out = open_memstream(&ptr, &size); /* violation */
/* Use out */
 
}

Compliant Solution (POSIX)

A compliant solution avoids assuming that fmemopen() and open_memstream() succeed regardless of its arguments and tests the return value of the function before using the file pointers in and out.

Code Block
bgColor#ccccff
langc
int main(int argc, char *argv[])
{
FILE *out, *in;
 
if (argc != 2) {
	/* Handle Errorerror */
}
 
in = fmemopen(argv[1], strlen(argv[1]), "r");


if (in == NULL){
	/* Handle Errorerror */
}
/* Use in */
 
out = open_memstream(&ptr, &size);

if (out == NULL){
	/* Handle Errorerror */

}
/* Use out */
 
}

Exceptions

...

Function

Successful Return

Error Return

printf()

number Number of characters (nonnegative)

negativeNegative

putchar()

character Character written

EOF

puts()

nonnegativeNonnegative

EOF (negative)

putwchar()

wide Wide character written

WEOF

vprintf()

number Number of characters (nonnegative)

negativeNegative

vwprintf()

number Number of wide characters (nonnegative)

negativeNegative

wprintf()

number Number of wide characters (nonnegative)

negativeNegative

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.

...

Tool

Version

Checker

Description

Compass/ROSE

  

Can detect violations of this recommendation when checking for violations of EXP12-C. Do not ignore values returned by functions and EXP34-C. Do not dereference null pointers.

Coverity

Coverity

Include Page
Coverity_V
Coverity_V

CHECKED_RETURN

Finds inconsistencies in how function call return values are handled. Coverity Prevent cannot discover all violations of this recommendation, so further verification is necessary.

Fortify SCA

5.0Compass/ROSE

 

 Can detect violations of this recommendation when checking for violations of EXP12-C. Do not ignore values returned by functions and EXP34-C. Do not dereference null pointers..

LDRA tool suite

Include Page
LDRA_V
LDRA_V

80 D

Partially implemented.
PRQA QA-C
Include Page
PRQA_V
PRQA_V

3200

Partially implemented.

Fortify SCA

V. 5.0

 

 

Related Coding Practices

Related Coding Practices

...

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

Related Guidelines

...

...

FIO04-CPP. Detect and handle input and output errors
ISO/IEC TR 17961 (Draft)Failing to detect and handle standard library errors [liberr]
MITRE CWE

...

...

Unchecked return value

...


...

...

Incorrect check of function return value

...


...

...

...

Detection of error condition without action

...


...

...

...

Unchecked error condition

...

Bibliography

ISO/IEC 9899:2011 Sections 7.21.3, "Files," 7.21.4, "Operations on files," and 7.21.9, "File positioning functions"

[DHS 2006]Handle All Errors Safely
[Henricson 1997]Recommendation 12.1, "Check for All Errors Reported from Functions"
[

...

]Section 7.

...

21.7.

...

10, "

...

The ungetc Function"

ISO/IEC TR 17961 (Draft) Failing to detect and handle standard library errors [liberr]

Bibliography

[DHS 2006]. Handle All Errors Safely.
[Henricson 1997] Recommendation 12.1, Check for all errors reported from functions