...
Function | Successful Return | Error Return |
---|---|---|
| Pointer to space |
|
|
| Nonzero |
|
| Nonzero |
|
| Nonzero |
| Pointer to matching element |
|
| Pointer to matching element |
|
| Converted wide character |
|
| Number of bytes |
|
| Number of bytes |
|
| Pointer to space |
|
| Processor time |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| Nonzero |
|
|
|
|
|
|
| Character read |
|
|
| Nonzero, |
| Pointer to string |
|
| Wide character read |
|
| Pointer to stream |
|
|
| Nonzero |
| Number of characters (nonnegative) | Negative |
| Number of characters (nonnegative) | Negative |
| Character written |
|
| Nonnegative |
|
fputwc() | Wide character written | WEOF |
| Nonnegative |
|
| Elements read | Elements read |
| Pointer to stream |
|
|
| Nonzero |
| Number of conversions (nonnegative) |
|
| Number of conversions (nonnegative) |
|
|
| Nonzero |
|
| Nonzero, |
| File position |
|
| Number of wide characters (nonnegative) | Negative |
| Number of wide characters (nonnegative) | Negative |
| Elements written | Elements written |
| Number of conversions (nonnegative) |
|
| Number of conversions (nonnegative) |
|
| Character read |
|
| Character read |
|
| Pointer to string |
|
| Pointer to string |
|
| Pointer to string |
|
| Wide character read |
|
| Wide character read |
|
| Pointer to broken-down time |
|
| Pointer to broken-down time |
|
| Pointer to broken-down time |
|
| Pointer to broken-down time |
|
| Pointer to space |
|
| Number of bytes |
|
| Number of bytes or status |
|
| Number of bytes or status |
|
| Number of bytes or status |
|
| Number of bytes or status |
|
| Number of non-null elements |
|
|
| Nonzero |
| Number of non-null elements |
|
|
| Nonzero |
| Number of bytes |
|
| Pointer to located character |
|
| Calendar time |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| Number of characters (nonnegative) | Negative |
| Character written |
|
| Wide character written |
|
|
| Nonzero |
| Pointer to space |
|
|
| Nonzero |
|
| Nonzero |
| Pointer to string |
|
|
| Nonzero |
| Number of conversions (nonnegative) |
|
| Number of conversions (nonnegative) |
|
| Pointer to previous function |
|
| Number of characters that would be written (nonnegative) | Negative |
| Number of characters that would be written (nonnegative) | Negative |
| Number of non-null characters written | Negative |
| Number of non-null characters written | Negative |
| Number of conversions (nonnegative) |
|
| Number of conversions (nonnegative) |
|
| Pointer to located character |
|
|
| Nonzero |
| Number of non-null characters |
|
| Pointer to located character |
|
| Pointer to located character |
|
| Pointer to located string |
|
| Converted value |
|
| Converted value |
|
| Converted value |
|
| Pointer to first character of a token |
|
| Pointer to first character of a token |
|
| Converted value |
|
| Converted value |
|
| Converted value |
|
| Converted value |
|
| Converted value |
|
| Converted value |
|
| Length of transformed string |
|
| Number of non-null wide characters | Negative |
| Number of non-null wide characters | Negative |
| Number of conversions (nonnegative) |
|
| Number of conversions (nonnegative) |
|
|
|
|
|
|
|
|
|
|
|
|
|
| Calendar time |
|
| Base |
|
| Pointer to stream |
|
|
| Nonzero |
| Non-null pointer |
|
|
| Nonzero |
|
|
|
| Value of thread-specific storage |
|
|
|
|
| Character pushed back |
|
| Character pushed back |
|
| Number of characters (nonnegative) | Negative |
| Number of characters (nonnegative) | Negative |
| Number of conversions (nonnegative) |
|
| Number of conversions (nonnegative) |
|
| Number of wide characters (nonnegative) | Negative |
| Number of wide characters (nonnegative) | Negative |
| Number of conversions (nonnegative) |
|
| Number of conversions (nonnegative) |
|
| Number of characters (nonnegative) | Negative |
| Number of conversions (nonnegative) |
|
| Number of conversions (nonnegative) |
|
| Number of characters that would be written (nonnegative) | Negative |
| Number of characters that would be written (nonnegative) | Negative |
| Number of non-null characters (nonnegative) | Negative |
| Number of non-null characters (nonnegative) | Negative |
| Number of conversions (nonnegative) |
|
| Number of conversions (nonnegative) |
|
| Number of non-null wide characters | Negative |
| Number of non-null wide characters | Negative |
| Number of conversions (nonnegative) |
|
| Number of conversions (nonnegative) |
|
| Number of wide characters (nonnegative) | Negative |
| Number of conversions (nonnegative) |
|
| Number of conversions (nonnegative) |
|
| Number of bytes stored |
|
| Pointer to located wide character |
|
| Number of non-null wide characters |
|
| Pointer to located wide character |
|
| Pointer to located wide character |
|
| Number of non-null bytes |
|
|
| Nonzero |
| Pointer to located wide string |
|
| Converted value |
|
| Converted value |
|
| Converted value |
|
| Pointer to first wide character of a token |
|
| Pointer to first wide character of a token |
|
| Converted value |
|
| Converted value |
|
| Converted value |
|
| Number of non-null bytes |
|
|
| Nonzero |
| Converted value |
|
| Converted value |
|
| Converted value |
|
| Length of transformed wide string |
|
| Converted character |
|
| Number of bytes stored |
|
| Number of bytes stored |
|
| Valid argument to |
|
| Valid argument to |
|
| Pointer to located wide character |
|
| Number of wide characters (nonnegative) | Negative |
| Number of conversions (nonnegative) |
|
| Number of conversions (nonnegative) |
|
...
Compliant Solution (setlocale()
)
A compliant This 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 | ||||
---|---|---|---|---|
| ||||
#include <locale.h> #include <stdlib.h> 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 = (size_t)-1; } return n; } |
...
...
Noncompliant Code Example (signal()
)
...
Code Block | ||||
---|---|---|---|---|
| ||||
#include <signal.h> 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; } |
...
Compliant Solution (signal()
)
A compliant This 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 | ||||
---|---|---|---|---|
| ||||
#include <signal.h> 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 == (int)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; } |
...
Noncompliant Code Example (malloc()
)
...
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdlib.h>
#include <string.h>
typedef struct {
char sig_desc[32];
} signal_info;
void func(size_t num_of_records, size_t temp_num,
const char *tmp2) {
signal_info *point;
signal_info *start = (signal_info *)malloc(num_of_records *
sizeof(signal_info));
if (start == NULL) {
/* Handle allocation error */
}
point = start + temp_num - 1;
memcpy(point->sig_desc, tmp2, strlen(tmp2));
/* ... */
} |
Noncompliant Code Example (
...
realloc()
)
In this 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 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.)
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdlib.h>
#include <string.h>
void f(char *input_string) {
size_t size = strlen(input_string) + 1;
char *str = (char *)malloc(size);
strcpy(str, input_string);
/* ... */
}
|
...
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 ensure it is not null before referencing the pointer. Handle the error condition appropriately when the returned pointer is null. When recovery from the allocation failure is not possible, propagate the failure to the caller.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdlib.h>
#include <string.h>
int f(char *input_string) {
size_t size = strlen(input_string) + 1;
char *str = (char *)malloc(size);
if (str == NULL) {
/* Handle allocation failure and return error status */
return -1;
}
strcpy(str, input_string);
/* ... */
free(str);
return 0;
}
|
Noncompliant Code Example (realloc()
)
This noncompliant code example calls realloc()
to resize the memory referred to by p
. However, if calls realloc()
to resize the memory referred to by p
. However, if realloc()
fails, it returns a null pointer. Consequently, the connection between the original block of memory and p
is severed, resulting in a memory leak.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdlib.h> void *p; void func(size_t new_size) { p = realloc(p, new_size); if (p == NULL) { /* Handle error */ } } |
When using realloc()
, it is important to account for 0-byte allocations. (See MEM04-C. Do not perform zero-length allocations.)
...
Compliant Solution (realloc()
)
In this compliant solution, the result of realloc()
is assigned to the temporary pointer q
and validated before it is assigned to the original pointer p
:validated before it is assigned to the original pointer p
. This solution is also compliant with MEM04-C. Do not perform zero-length allocations.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdlib.h> void *p; void func(size_t new_size) { void *q; if (new_size == 0) { /* Handle error */ } q = realloc(p, new_size); if (q == NULL) { /* Handle error */ } else { p = q; } } |
...
According to the C Standard, the fseek()
function returns a nonzero value to indicate that an error occurred. 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 fails. 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.
...
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 must 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:.
Note that this solution uses the goto
statement, as suggested in MEM12-C. Consider using a goto chain when leaving a function on error when using and releasing resources.
Implementation Details
POSIX
In addition to the C standard library functions mentioned earlier, the following functions defined in POSIX require error checking (list is not all-inclusive)error when using and releasing resources.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdio.h> #include <stdlib.h> #include <string.h> extern void log_message(const char *); 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); } } |
Implementation Details
POSIX
In addition to the C standard library functions mentioned earlier, the following functions defined in POSIX require error checking (list is not all-inclusive).
Function | Successful Return | Error Return |
|
---|---|---|---|
| Pointer to a |
|
|
| Pointer to a |
|
|
|
| Nonzero | Unchanged |
...
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdio.h> #include <string.h> int main(int argc, char *argv[]) { FILE *out; FILE *in; size_t size; char *ptr; if (argc != 2) { /* Handle error */ } in = fmemopen(argv[1], strlen(argv[1]), "r"); if (in == NULL){ /* Handle error */ } /* Use in */ out = open_memstream(&ptr, &size); if (out == NULL){ /* Handle error */ } /* Use out */ return 0; } |
Exceptions
EXP12ERR33-EX1EX0: The exception from EXP12-C. Do not ignore values returned by functions still applies. If the return value is inconsequential or if any errors can be safely ignored, such as for functions called because of their side effects, the function should be explicitly cast to void
to signify programmer intent. For an example of this exception, see "Compliant Solution (Remove Existing Destination File)" under "Portable Behavior" in FIO10-C. Take care when using the rename() function.
ERR33-EX1: Ignore the return value of a function that cannot fail or whose return value cannot signify that an error condition need not be diagnosed. For example, strcpy()
is one such function.
...
[DHS 2006] | Handle All Errors Safely |
[Henricson 1997] | Recommendation 12.1, "Check for All Errors Reported from Functions" |
[ISO/IEC 9899:2011] | Subclause 7.21.7.10, "The ungetc Function" |
...