When you have a choice of two functions to accomplish the same task, prefer the one with better error checking and reporting.
The following table shows a list of C standard library functions that provide limited or no error checking and reporting along with preferable alternatives:
Function |
Preferable |
Comments |
|---|---|---|
|
|
No error indication, undefined behavior on error. |
|
|
No error indication, undefined behavior on error. |
|
|
No error indication, undefined behavior on error. |
|
|
No error indication, undefined behavior on error. |
|
|
No error indication, silent failure on error. |
|
|
No error indication, silent failure on error. |
atoi())This noncompliant code example converts the string token stored in the static array buff to a signed integer value using the atoi() function.
int si;
if (argc > 1) {
si = atoi(argv[1]);
}
|
The atoi(), atol(), and atoll() functions convert the initial portion of a string token to int, long int, and long long int representation, respectively. Except for the behavior on error, they are equivalent as follows:
Call |
Equivalent on Success |
|---|---|
|
|
|
|
|
|
Unfortunately, atoi() and related functions lack a mechanism for reporting errors for invalid values. Specifically, the atoi(), atol(), and atoll() functions
errno on an error.See also rule MSC34-C. Do not use deprecated or obsolescent functions.
strtol())The strtol(), strtoll(), strtoul(), and strtoull() functions convert a null-terminated byte string to long int, long long int, unsigned long int, and unsigned long long int representation, respectively.
This compliant solution uses strtol() to convert a string token to an integer and ensures that the value is in the range of int.
long sl;
int si;
char *end_ptr;
if (argc > 1) {
errno = 0;
sl = strtol(argv[1], &end_ptr, 10);
if ((sl == LONG_MIN || sl == LONG_MAX)
&& errno != 0)
{
perror("strtol error");
}
else if (end_ptr == argv[1]) {
if (puts("error encountered during conversion") == EOF) {
/* Handle Error */
}
}
else if (sl > INT_MAX) {
printf("%ld too large!\n", sl);
}
else if (sl < INT_MIN) {
printf("%ld too small!\n", sl);
}
else if ('\0' != *end_ptr) {
if (puts("extra characters on input line\n") == EOF) {
/* Handle Error */
}
}
else {
si = (int)sl;
}
}
|
Both the non-compliant code example and compliant solution are taken from recommendation INT06-C. Use strtol() or a related function to convert a string token to an integer.
rewind())This noncompliant code example sets the file position indicator of an input stream back to the beginning using rewind().
char *file_name;
FILE *fp;
/* initialize file_name */
fp = fopen(file_name, "r");
if (fp == NULL) {
/* Handle open error */
}
/* read data */
rewind(fp);
/* continue */
|
However, it is impossible to determine if rewind() succeeded.
fseek())This compliant solution uses fseek() instead of rewind() and checks to see if the operation succeeded.
char *file_name;
FILE *fp;
/* initialize file_name */
fp = fopen(file_name, "r");
if (fp == NULL) {
/* Handle open error */
}
/* read data */
if (fseek(fp, 0L, SEEK_SET) != 0) {
/* Handle repositioning error */
}
/* continue */
|
Both the noncompliant code example and compliant solution are taken from recommendation FIO07-C. Prefer fseek() to rewind().
setbuf())This noncompliant code example calls setbuf() with a buf argument of NULL.
FILE *file; /* Setup file */ setbuf(file, NULL); /* ... */ |
It is not possible to determine if the call to setbuf() succeeded.
On 4.2BSD and 4.3BSD systems, setbuf() always uses a suboptimal buffer size and should be avoided.
setvbuf())This compliant solution calls setvbuf(), which returns nonzero if the operation failed.
FILE *file;
char *buf = NULL;
/* Setup file */
if (setvbuf(file, buf, buf ? _IOFBF : _IONBF, BUFSIZ) != 0) {
/* Handle error */
}
/* ... */
|
Both the non-compliant code example and compliant solution are taken from recommendation FIO12-C. Prefer setvbuf() to setbuf().
While it is rare for a violation of this rule to result in a security vulnerability, it can easily result in lost or misinterpreted data.
Recommendation |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
|---|---|---|---|---|---|
ERR07-C |
medium |
probable |
medium |
P8 |
L2 |
This rule in general cannot be detected, although various examples can be detected by simply scanning for functions that have equivalent functions with better error handling.
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
ISO/IEC 9899:1999 Section 7.20.1.4, "The strtol, strtoll, strtoul, and strtoull functions," Section 7.20.1.2, "The atoi, atol, and atoll functions," Section 7.19.6.7, "The sscanf function," Section 7.19.5.5, "The setbuf function", Section 7.19.9.2, "The fseek function"; 7.19.9.5, and "The rewind function"
MITRE CWE: CWE-676, "Use of Potentially Dangerous Function"
MITRE CWE: CWE-20, "Insufficient Input Validation"
\[[Klein 2002|AA. Bibliography#Klein 02]\] |
12. Error Handling (ERR) ERR31-C. Don't redefine errno