...
Function | Successful Return | Error Return |
|
---|---|---|---|
| pointer to a FILE object |
|
|
| pointer to a FILE object |
|
|
| 0 | non-zero #2 | unchanged #2 |
SettingAnchor 1 1 errno
is a POSIX [ISO/IEC 9945:2008] extension to the C standard.
On error,Anchor 2 2 posix_memalign()
returns a value that corresponds to one of the constants defined in the<errno.h>
header. The function does not seterrno
. Theposix_memalign()
function is optional and is not required to be provided by conforming implementations.
Anchor | ||||
---|---|---|---|---|
|
Noncompliant Code Example (setlocale()
)
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
.
...
Anchor | ||||
---|---|---|---|---|
|
Compliant Solution (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.
...
Anchor | ||||
---|---|---|---|---|
|
Noncompliant Code Example (signal()
)
In this noncompliant example, 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, because 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 | ||||
---|---|---|---|---|
| ||||
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 | ||||
---|---|---|---|---|
|
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.
...
Anchor | ||||
---|---|---|---|---|
|
Noncompliant Code Example (malloc()
)
In this noncompliant code example, temp_num
, tmp2
, and num_of_records
are under the control of a malicious user. The attacker can easily cause malloc()
to fail by providing a large value for num_of_records
.
...
When malloc()
fails, it returns a null pointer that is assigned to start
. If start
is a null, an attacker can provide a value for temp_num
that, when scaled by the the sizeof signal_info
, references a writable address to which control is eventually transferred. The contents of the string referenced by tmp2
can then be used to overwrite the address, resulting in an arbitrary code execution vulnerability.
Compliant Solution (malloc()
)
To correct this error, ensure the pointer returned by malloc()
is not null. This also ensures compliance with MEM32-C. Detect and handle memory allocation errors.
Code Block | ||||
---|---|---|---|---|
| ||||
signal_info * start = malloc(num_of_records * sizeof(signal_info)); if (start == NULL) { /* Handle Allocation Error */ } signal_info * point = (signal_info *)start; point = start + temp_num - 1; memcpy(point->sig_desc, tmp2, strlen(tmp2)); /* ... */ |
Noncompliant Code Example (malloc()
)
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 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 ERR33-C. Detect and handle standard library 2errors Related Vulnerabilities section.) See also MEM32-C. Detect and handle memory allocation errors.
Code Block | ||||
---|---|---|---|---|
| ||||
void f(char *input_string) { size_t size = strlen(input_string) + 1; char *str = (char *)malloc(size); strcpy(str, input_string); /* ... */ } |
Anchor | ||||
---|---|---|---|---|
|
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 | ||||
---|---|---|---|---|
| ||||
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 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.
...
Anchor | ||||
---|---|---|---|---|
|
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
.
Code Block | ||||
---|---|---|---|---|
| ||||
void *p; void *q; size_t new_size= /* nonzero size */; q = realloc(p, new_size); if (q == NULL) { /* Handle error */ } else { p = q; } |
Noncompliant Code Example (fseek
)
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.
Code Block | ||||
---|---|---|---|---|
| ||||
size_t read_at(FILE *file, long offset, void *buf, size_t nbytes) { fseek(file, offset, SEEK_SET); return fread(buf, 1, nbytes, file); } |
Compliant Solution (fseek
)
According to the C standard, the fseek()
function returns a non-zero 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 | ||||
---|---|---|---|---|
| ||||
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); } |
Noncompliant Code Example (snprintf
)
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 terminated.
Code Block | ||||
---|---|---|---|---|
| ||||
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); /* ... */ } |
Compliant Solution (snprintf
)
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 NUL-terminate the formatted string in case the provided buffer wasn't large enough for snprintf()
to append the terminating NUL.
...
Note that this solution correctly handles memory allocation errors in accordance with MEM32-C. Detect and handle memory allocation errors and 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.
Exceptions
EXP12-EX1: 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.
...
Function | Successful Return | Error Return |
---|---|---|
printf() | number of characters (nonnegative) | negative |
putchar() | character written | EOF |
puts() | nonnegative | EOF (negative) |
putwchar() | wide character written | WEOF |
vprintf() | number of characters (nonnegative) | negative |
vwprintf() | number of wide characters (nonnegative) | negative |
wprintf() | number of wide characters (nonnegative) | negative |
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 |
---|---|---|---|---|---|
ERR33-C | high | likely | medium | P18 | L1 |
Automated Detection
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
| 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. | |||||||
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.. | ||||||||
| 80 D | Partially implemented. | |||||||
PRQA QA-C |
| 3200 | Partially implemented | ||||||
Fortify SCA | V. 5.0 |
|
Related Coding Practices
Coding Practice | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
medium | unlikely | medium | P2 | L3 | |
low | probable | high | P2 | L3 | |
FLP32-C. Prevent or detect domain and range errors in math functions | medium | probable | medium | P8 | L2 |
high | likely | medium | P18 | L1 | |
medium | probable | high | P4 | L3 | |
FIO33-C. Detect and handle input output errors resulting in undefined behavior | high | probable | medium | P12 | L1 |
low | unlikely | medium | P2 | L3 | |
ERR00-C. Adopt and implement a consistent and comprehensive error-handling policy | medium | probable | high | P4 | L3 |
low | unlikely | high | P1 | L3 | |
medium | probable | high | P4 | L3 | |
API04-C. Provide a consistent and usable error-checking mechanism | medium | unlikely | medium | P2 | L3 |
low | likely | medium | P6 | L2 | |
low | likely | medium | P6 | L2 |
Related Vulnerabilities
The vulnerability in Adobe Flash [VU#159523] arises because Flash neglects to check the return value from calloc()
. Even when calloc()
returns NULL
, Flash writes to an offset from the return value. Dereferencing NULL
usually results in a program crash, but dereferencing an offset from NULL
allows an exploit to succeed without crashing the program.
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
CERT C++ Secure Coding Standard: ERR10-CPP. Check for error conditions
...
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
...