When developing new code, declare functions that return errno
with a return type of errno_t
. Many existing functions that return an errno
error code are declared as returning a value of type int
. It is semantically unclear by looking at inspecting the function declaration or prototype if these functions return an error status or a value or, worse, some combination of the two. (see See ERR02-AC. Avoid in-band error indicators.).
C11 Annex K introduced TR 24731-1 introduces the new type errno_t
that is defined to be type int
in errno.h
and elsewhere. Many of the functions defined in TR 24731-1 C11 Annex K return values of this type. The errno_t
type should be used as the type of an object that may contain only contain values that might be found in errno
. For example, a function that returns the value of errno
should be declared as having the return type errno_t
.
This recommendation depends on TR 24731-1 and advocates using errno_t
in new code where appropriate.
Non-Compliant Code Example
C11 Annex K being implemented. The following code can be added to remove this dependency:
Code Block | ||
---|---|---|
| ||
#ifndef __STDC_LIB_EXT1__
typedef int errno_t;
#endif |
Noncompliant Code Example
This noncompliant This non-compliant code example shows a function called opener()
that returns errno
error codes. However, the function is declared as returning an int
. Consequently, the meaning of the return value is not as clear as it could bereadily apparent.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <errno.h> #include <stdio.h> enum { NO_FILE_POS_VALUES = 3 }; int opener( FILE *file, intsize_t *width, intsize_t *height, intsize_t *data_offset ) { intsize_t file_w; intsize_t file_h; intsize_t file_o; fpos_t offset; if (file == NULL) { return EINVAL; } errno = 0; if (fgetpos(file, &offset) != 0) { return errno; } if (fscanf(file, "%i%zu %i%zu %i%zu", &file_w, &file_h, &file_o) != NO_FILE_POS_VALUES) { return EIO-1; } errno = 0; if (fsetpos(file, &offset) != 0) { return errno; } if (width != NULL) { *width = file_w; } if (height != NULL) { *height = file_h; } if (data_offset != NULL) { *data_offset = file_o; } return 0; } |
This non-compliant noncompliant code example , however, does comply with nevertheless complies with ERR30-C. Set errno to zero before calling a function, and use it only after the function returns a value indicating failureTake care when reading errno.
Compliant Solution (POSIX)
In this compliant solution, the opener()
function returns a value of type errno_t
, providing a clear indication that this function returns an error code.:
Code Block | ||||
---|---|---|---|---|
| ||||
#define __STDC_WANT_LIB_EXT1__ 1 #include <errno.h> #include <stdio.h> #include <stdlib.h> enum { NO_FILE_POS_VALUES = 3 }; errno_t opener( FILE *file, intsize_t *width, intsize_t *height, intsize_t *data_offset ) { intsize_t file_w; intsize_t file_h; intsize_t file_o; fpos_t offset; if (fileNULL == NULLfile) { return EINVAL; } errno = 0; if (fgetpos(file, &offset) != 0 ) { return errno; } if (fscanf(file, "%i%zu %i%zu %i%zu", &file_w, &file_h, &file_o) != NO_FILE_POS_VALUES) { return EIO; } errno = 0; if (fsetpos(file, &offset) != 0 ) { return errno; } if (width != NULL) { *width = file_w; } if (height != NULL) { *height = file_h; } if (data_offset != NULL) { *data_offset = file_o; } return 0; } |
NOTE: This compliant solution is categorized as a POSIX solution because it returns EINVAL and
, which are not defined in C99, but they are available in most implementations and are defined in POSIXdefined by POSIX (IEEE Std 1003.1, 2013 Edition) but not by the C Standard.EIO
Risk Assessment
Failing to test for error conditions can lead to vulnerabilities of varying severity. Declaring functions that return an errno
with a return type of errno_t
will not eliminate this problem , but may reduce errors caused by programmers' misunderstanding the purpose of a return value.
Recommendation | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
DCL09- |
C |
Low |
Unlikely |
Low | P3 | L3 |
Automated Detection
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
Axivion Bauhaus Suite |
| CertC-DCL09 | |||||||
LDRA tool suite |
| 634 S | Partially Implemented |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
References
Wiki Markup |
---|
\[[ISO/IEC 9899:1999|AA. C References#ISO/IEC 9899-1999]\] Section 6.7.5.3, "Function declarators (including prototypes)"
\[[ISO/IEC PDTR 24772|AA. C References#ISO/IEC PDTR 24772]\] "NZN Returning error status"
\[[ISO/IEC TR 24731-1:2007|AA. C References#ISO/IEC TR 24731-1-2007]\]
\[[MISRA 04|AA. C References#MISRA 04]\] Rule 20.5
\[[Open Group 04|AA. C References#Open Group 04]\] |
Related Guidelines
SEI CERT C++ Coding Standard | VOID DCL09-CPP. Declare functions that return errno with a return type of errno_t |
ISO/IEC TR 24772:2013 | Ignored Error Status and Unhandled Exceptions [OYB] |
Bibliography
...
02. Declarations and Initialization (DCL) DCL10-A. Maintain the contract between the writer and caller of variadic functions