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 userprogrammer-defined integer type might be any type supported by the implementation, even a type larger than unsigned long long, for example. For example, given an implementation that supports 128-bit unsigned integers and provides a uint_fast128_t type, a programmer may define the following type:

Code Block

typdef mytypedeftypedef uint_fast128_t uint_fast128mytypedef_t;

Furthermore, the definition of user programmer-defined types may change (which may be one of the reasons the user-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 pointer to 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 user-defined integer types. Convert user-defined integer types of the same signedness to intmax_t and uintmax_t and then output using the j length modifier. Similarly, input user defined types of the same signedness into variables of intmax_t and uintmax_t and then convert to the user-defined integer types using appropriate range checks.

Similarly, In addition to programmer-defined types, 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())

This noncompliant code example prints the 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); 

There is no guarantee that this non-compliant code example 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
lang#FFccccc
#include <stdio.h>
#include <inttypes.h>

mytypedef_t x;

/* ... */

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

Compliant Solution (Microsoft printf())

This compliant solution uses the correct format for the type being usedVisual 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())

There is no guarantee that this non-compliant code example prints the correct value of x. This 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("%lu%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 uses the correct format for the type being usedguarantees 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-C

High

Unlikely

Medium

P6

L2

Automated Detection

Tool

Version

Checker

Description

Axivion Bauhaus Suite

Include Page
Axivion Bauhaus Suite_V
Axivion Bauhaus Suite_V

CertC-INT15
-A

low

unlikely

high

P1

L3

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 Image Added04. Integers (INT)      04. Integers (INT)       INT01-A. Use rsize_t or size_t for all integer values representing the size of an object