CertC-INT05¶
Do not use input functions to convert character data if they cannot handle all possible inputs
Required inputs: IR
Do not use functions that input characters and convert them to integers if the
functions cannot handle all possible inputs. For example, formatted input
functions such as
scanf(),
fscanf(),
vscanf(), and
vfscanf() can be used to read string data from
stdin or (in the cases of
fscanf() and
vfscanf()) other input streams. These functions work fine for
valid integer values but lack robust error handling for invalid values.
Alternatively, input character data as a null-terminated byte string and
convert to an integer value using
strtol() or a related function. (See
ERR34-C.
Detect errors when converting a string to a number.)
Noncompliant Code Example
This noncompliant code example uses the
scanf() function to read a string from
stdin and convert it to a
long. The
scanf() and
fscanf() functions have
undefined
behavior if the value of the result of this operation cannot be represented
as an integer.
long num_long;
if (scanf("%ld", &num_long) != 1) {
/* Handle error */
}
In general, do not use
scanf() to parse integers or floating-point numbers from input
strings because the input could contain numbers not representable by the
argument type.
Compliant Solution (Linux)
This compliant example uses the Linux
scanf() implementation's built-in error handling to validate
input. On Linux platforms,
scanf() sets
errno to
ERANGE if the result of integer conversion cannot be represented
within the size specified by the format string [
Linux
2008]. Note that this solution is platform dependent, so it should be used
only where portability is not a concern.
long num_long;
errno = 0;
if (scanf("%ld", &num_long) != 1) {
/* Handle error */
}
else if (ERANGE == errno) {
if (puts("number out of range\n") == EOF) {
/* Handle error */
}
}
Compliant Solution
This compliant example uses
fgets() to input a string and
strtol() to convert the string to an integer. Error checking is
provided to make sure the value is a valid integer in the range of
long.
char buff[25];
char *end_ptr;
long num_long;
if (fgets(buff, sizeof(buff), stdin) == NULL) {
if (puts("EOF or read error\n") == EOF) {
/* Handle error */
}
} else {
errno = 0;
num_long = strtol(buff, &end_ptr, 10);
if (ERANGE == errno) {
if (puts("number out of range\n") == EOF) {
/* Handle error */
}
}
else if (end_ptr == buff) {
if (puts("not valid numeric input\n") == EOF) {
/* Handle error */
}
}
else if ('\n' != *end_ptr && '\0' != *end_ptr) {
if (puts("extra characters on input line\n") == EOF) {
/* Handle error */
}
}
}
Note that this solution treats any trailing characters, including whitespace characters, as an error condition.
Risk Assessment
Although it is relatively rare for a violation of this recommendation to result in a security vulnerability, it can easily result in lost or misinterpreted data.
| Recommendation | Severity | Likelihood | Remediation Cost | Priority | Level |
|---|---|---|---|---|---|
| INT05-C | Medium | Probable | High | P4 | L3 |
Related Guidelines
| SEI CERT C++ Coding Standard | VOID INT05-CPP. Do not use input functions to convert character data if they cannot handle all possible inputs |
| MITRE CWE |
CWE-192, Integer coercion error CWE-197, Numeric truncation error |
Bibliography
| [ Klein 2002] | |
| [ Linux 2008] |
scanf(3) |
Possible Messages
Key |
Text |
Severity |
Disabled |
|---|---|---|---|
scanf_conversion_to_number |
Potential numeric overflow: do not use functions of scanf() family to convert a string to number. |
None |
False |
Options¶
This rule shares the following common options: exclude_in_macros, exclude_messages_in_system_headers, excludes, extend_exclude_to_macro_invocations, includes, justification_checker, languages, post_processing, provider, report_at, severity
The following places define options that affect this rule: Stylechecks, Analysis-GlobalOptions
scanf_functions¶
scanf_functions
Members of the scanf family to check.Type: dict[bauhaus.analysis.config.QualifiedName, typing.Tuple[str, int, typing.Optional[int]]]
Default:
{ 'fscanf': ('scanf', 1, 2), 'scanf': ('scanf', 0, 1), 'sscanf': ('scanf', 1, 2), 'vfscanf': ('scanf', 1, None), 'vscanf': ('scanf', 0, None), 'vsscanf': ('scanf', 1, None) }