Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Parasoft C/C++test 2021.2

Few programmers consider the issues around formatted I/O and typedefstype definitions. A programmer-defined integer type might be any type supported by the implementation, even a type larger than unsigned long long. For example, given an implementation that supports 128-bit unsigned integers and provides a uint_fast128_t type for them would allow a programmar to use them, a programmer may define the following type:

Code Block

typedef uint_fast128_t mytypedef_t;

Furthermore, the definition of user programmer-defined types may change (which may be one of the reasons the programmer-defined type was created to begin with). This creates a problem using these types , which creates a problem when these types are used with formatted output functions (, such as printf()) , and formatted input functions (, such as scanf()) . (see FIO00See FIO47-A. Take care when creating C. Use valid format strings.).

The C99 C intmax_t and uintmax_t types are capable of representing any types can represent any value representable by any other integer types of the same signedness. This allows conversion between user (See INT00-C. Understand the data model used by your implementation(s).) This capability allows conversion between programmer-defined integer types (of the same signedness) and intmax_t and uintmax_t. For example:

Code Block
languagecpp

mytypedef_t x;
uintmax_t temp;

temp = x; /* Always secure if mytypedef_t is unsigned*/

/* ... */
temp = x; /* always safeChange the value of temp ... */

if (temp <= MYTYPEDEF_MAX) {
  x = temp;
}

Formatted I/O functions can be used to input and output functions contain a length modifier which provides the above facilities for input/outputgreatest-width integer typed values. The j length modifier in a format string indicates that the following d, i, o, u, x, X, or n conversion specifier will apply to an argument with type intmax_t or uintmax_t. C99 C also specifies the z length modifier for use with arguments of type size_t, and the t length modifier for arguments of type ptrdiff_t.The C99 intmax_t and uintmax_t

can safely be used to perform formatted I/O with programmer-defined integer types. Convert signed programmer-defined integer types to intmax_t and unsigned In addition to programmer-defined integer types to uintmax_t then output using the j length modifier. Similarly, input programmer-defined integer types into variables of intmax_t or uintmax_t (whichever matches the signedness of the programmer-defined integer type) and then convert to the programmer-defined integer types using appropriate range checks.Similarly, there is no requirement that an implementation provide format-length modifiers for implementation-defined integer types. For example, a machine with a 16-bit word size with an implementation-defined 48-bit integer type might may not bother to provide format-length modifiers for the type. Such a machine would still have to have machine still must have a 64-bit long long, and with intmax_t would probably be that type. So, this solution can be applied even if there were no format length modifiers for the 48-bit integers.

...

being at least that large.

Noncompliant Code Example (printf())

There is no guarantee that this non-compliant This noncompliant code example prints the correct value of x. as an unsigned long long value even though the value is of a programmer-defined integer type:

Code Block
bgColor#FFcccc
langc

#include <stdio.h>
/* ... */
mytypedef_t x;

/* ... */

printf("%llu", (unsigned long long) x); 

This code example is non-compliant for two reasons: it assumes that x has type unsigned long long and that unsigned long long is large enough to represent xThere is no guarantee that this code prints the correct value of x, as x may be too large to represent as an unsigned long long.

Compliant Solution (printf())

The C intmax_t and uintmax_t can be safely used to perform formatted I/O with programmer-defined integer types by converting signed programmer-defined integer types to intmax_t and unsigned programmer-defined integer types to uintmax_t, then outputting these values using the j length modifier. Similarly, programmer-defined integer types can be input to variables of intmax_t or uintmax_t (whichever matches the signedness of the programmer-defined integer type) and then converted to programmer-defined integer types using appropriate range checks.

This compliant solution guarantees that the correct value of x is printed, regardless of its length, provided that mytypedef_t is an unsigned type.:

Code Block
bgColor#ccccff
langc

#include <stdio.h>
#include <inttypes.h>

mytypedef_t x;

/* ... */

printf("%ju", (uintmax_t) x);

Compliant Solution (Microsoft printf())

Visual Studio 2012 and earlier versions do not support the standard j length modifier and do not have a nonstandard analog. Consequently, the programmer must hard code the knowledge that intmax_t is int64_t and uintmax_t is uint64_t for Microsoft Visual Studio versions.

Code Block
bgColor#ccccff
langc
#include <stdio.h>
#include <inttypes.h>

mytypedef_t x;

/* ... */

#ifdef _MSC_VER
  printf("%llu", (uintmax_t) x);
#else
  printf("%ju", (uintmax_t) x);

...

#endif  

A feature request has been submitted to Microsoft to add support for the j length modifier to a future release of Microsoft Visual Studio.

Noncompliant Code Example (scanf())

This non-compliant code example will result in a "buffer overflow", if the size of mytypedef_t is smaller than unsigned long long or it may result in an incorrect value if the size of mytypedef_t is larger than unsigned long long.noncompliant code example reads an unsigned long long value from standard input and stores the result in x, which is of a programmer-defined integer type:

Code Block
bgColor#FFcccc
langc

#include <stdio.h>
/* ... */
mytypedef_t x;
/* ... */
if (scanf("%llu", &x);
 != 1) {
  /* Handle error */
}

This noncompliant code example can result in a buffer overflow if the size of mytypedef_t is smaller than unsigned long long, or it might result in an incorrect value if the size of mytypedef_t is larger than unsigned long long.  Moreover, scanf() lacks the error checking capabilities of alternative conversion routines, such as strtol(). For more information, see INT06-C. Use strtol() or a related function to convert a string token to an integer.

Compliant Solution (

...

strtoumax())

This compliant solution guarantees that a correct value in the range of mytypedef_t is read, or an error condition is detected, assuming the value of MYTYPEDEF_MAX is correct as the largest value representable by mytypedef_t:  The strtoumax() function is used instead of scanf() as it provides enhanced error checking functionality.  The fgets() function is used to read input from stdin.

Code Block
bgColor#ccccff
langc

#include <stdio.h>
#include <inttypes.h>
/*#include <errno...h> */

mytypedef_t x;
uintmax_t temp;

/* ... */
scanf("%ju", &temp);
if (
if (fgets(buff, sizeof(buff), stdin) == NULL) {
  if (puts("EOF or read error\n") == EOF) {
    /* Handle error */
  }
} else {
  /* Check for errors in the conversion */
  errno = 0;
  temp = strtoumax(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 */
    }
  }
  
  /* No conversion errors, attempt to store the converted value into x */
  if (temp > MYTYPEDEF_MAX) {
    /* handleHandle error */
  } else {
    x = temp;
  }
}

Risk Assessment

Failure to use an appropriate conversion specifier when inputting or outputting programmer-defined integer types can result in buffer overflow and lost or misinterpreted data.

Recommendation

Severity

Likelihood

Remediation Cost

Priority

Level

INT15-

A

C

low

High

likely

Unlikely

medium

Medium

P6

L2

Automated Detection

Tool

Version

Checker

Description

Axivion Bauhaus Suite

Include Page
Axivion Bauhaus Suite_V
Axivion Bauhaus Suite_V

CertC-INT15
Compass/ROSE



Can catch violations of this rule by scanning the printf() and scanf() family of functions. For each such function, any variable that corresponds to a %d qualifier (or any qualifier besides %j) and that is not one of the built-in types (char, short, int, long, long long) indicates a violation of this rule. To catch violations, ROSE would also have to recognize derived types in expressions, such as size_t

LDRA tool suite

Include Page
LDRA_V
LDRA_V

586 S

Enhanced Enforcement

Parasoft C/C++test

Include Page
Parasoft_V
Parasoft_V

CERT_C-INT15-aUse intmax_t or uintmax_t for formatted IO on programmer-defined integer types

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 7.18.1.5, "Greatest-width integer types," and Section 7.19.6, "Formatted input/output functions"

Related Guidelines

Bibliography

[Saks 2007c]Standard C's Pointer Difference Type


...

Image Added Image Added INT14-A. Avoid performing bitwise and arithmetic operations on the same data      04. Integers (INT)       Image Modified