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)
Excerpt from SEI CERT C Coding Standard: Rules for Developing Safe, Reliable, and Secure Systems (2016 Edition) and SEI CERT C Coding Standard [https://cmu-sei.github.io/secure-coding-standards/sei-cert-c-coding-standard/recommendations/integers-int/int05-c], Copyright (C) 1995-2026 Carnegie Mellon University. See section 9.4. "3rd-Party Licenses" in the documentation for full details.

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

scanf_functions

scanf_functions

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)
}
Members of the scanf family to check.