Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: REM Cost Reform

Integer types in C have two metrics associated with them, a both a size and a width precision. The size indicates the number of bytes used by a variable, an object and can be retrieved for any variable object or type using the sizeof operator, while the width indicates the .  The precision of an integer type is the number of bits that are actually used to encode the integer's value. The C standard permits an integer to contain internal padding bits; these it uses to represent values, excluding any sign and padding bits.

Padding bits contribute to the integer's size, but not to its widthprecision. Consequently, inferring the precision of an integer type may have a size that could be used to incorrectly assume its width is larger than it actually is.  Do from its size may result in too large a value, which can then lead to incorrect assumptions about the numeric range of these types.  Programmers should use correct integer precisions in their code, and in particular, should not use the sizeof operator to compute the width precision of an integer type on architectures that use padding bits or in strictly conforming (that is, portable) programs.

Noncompliant Code Example

This noncompliant code example illustrates a function that produces 2 raised to the power of the function argument. To prevent undefined behavior , (See undefined behavior 48.) in compliance with INT34-C. Do not shift an expression by a negative number of bits or more bits than by greater than or equal to the number of bits that exist in the operand, the function ensures that the argument is less than the number of bits used to store an a value of type unsigned int.

 

Code Block
bgColor#ffcccc
lang
languagec
#include <limits.h>
 
unsigned int pow2(unsigned int exp) {
  if (exp >= sizeof(
unsigned int) * CHAR_BIT) {
    /* 
handle
Handle error */
  }
  return 1 << exp;
}

However, if this code runs on a platform where unsigned int has one or more padding bits, it can still accept result in values for exp that are too large. For instanceexample, on a platform that stores unsigned int in 64 bits, but uses only 48 width bits could perform bits to represent the value, a left shift on an illegal value of 56 bits would result in undefined behavior (See undefined behavior 48.).

Compliant Solution (popcount())

This compliant solution uses a popcount() function, which counts the number of bits set on any unsigned integer. This allows , allowing this code to count determine the number of width bits used by the unsigned int typeprecision of any integer type, signed or unsigned.

Code Block
bgColor#ccccff
langc
#include <stddef.h>
#include <stdint.h>
 
/* Returns the number of set bits */
size_t popcount(uintmax_t num) {
  size_t widthprecision = 0;
  while (num != 0) {
    if (num % 2 == 1) {
      widthprecision++;
    }
    num >>= 1;
  }
  return width;
}

precision;
}
#define PRECISION(umax_value) popcount(umax_value) 

Implementations can replace the PRECISION() macro with a type-generic macro that returns an integer constant expression that is the precision of the specified type for that implementation. This return value can then be used anywhere an integer constant expression can be used, such as in a static assertion. (See DCL03-C. Use a static assertion to test the value of a constant expression.) The following type generic macro, for example, might be used for a specific implementation targeting the IA-32 architecture:

Code Block
bgColor#ccccff
langc
#define PRECISION(value)  _Generic(value, \
  unsigned char : 8, \
  unsigned short: 16, \
  unsigned int : 32, \
  unsigned long : 32, \
  unsigned long long : 64, \
  signed char : 7, \
  signed short : 15, \
  signed int : 31, \
  signed long : 31, \
  signed long long : 63)

The revised version of the pow2() function uses the PRECISION() macro to determine the precision of the unsigned type:

Code Block
bgColor#ccccff
langc
#include <stddef.h>
#include <stdint.h>
#include <limits.h>
extern size_t popcount(uintmax_t);
#define PRECISION(umax_value) popcount(umax_value)  
unsigned int pow2(unsigned int exp) {
  if (exp >= popcountPRECISION( UINT_MAX)) {
    /* handleHandle error */
  }
  return 1 << exp;
}

Implementation Details

Modulo behavior resulting from left-shifting an unsigned integer type is permitted by this standard.

The computation of the correct width of any integer type can be nontrivial. On machines with no padding bits, the width can be computed directly from the integer's size:

 

size_t width = sizeof(unsigned int) * CHAR_BIT;

 

Some platforms provide a population count operation, which counts the number of bits that are set. This can be used to compute the width:

 

size_t width = _popcount(UINT_MAX);

 

Some platforms, such as the Cray Linux Environment (CLE; supported on Cray XT CNL compute nodes), provide a _popcnt instruction that can substitute for the popcount() function.

Code Block
bgColor#ccccff
langc
#define PRECISION(umax_value) _popcnt(umax_value)

Compliant Solution (C23)

The C23 standard provides various *_WIDTH macros that define the number of width bits for each integer type. This is effectively the size of the type (multiplied by 8) less the number of padding bits. The following compliant solution uses the UINT_WIDTH  type to obtain the width of an un

Code Block
bgColor#ccccff
langc
#include <limits.h>

unsigned int pow2(unsigned int exp) {
  if (exp >= UINT_WIDTH) {
    /* Handle error */
  }
  return 1 << exp;
}

Risk Assessment

Mistaking an integer's size for its precision can permit invalid precision arguments to operations such as bitwise shifts, resulting in undefined behavior

GCC has no options to handle shifts by negative amounts or by amounts outside the width of the type predictably or trap on them; they are always treated as undefined. Processors may reduce the shift amount modulo the width of the type. For example, 32-bit shifts are implemented using the following instructions on IA-32:

 

sa[rl]l   %cl, %eax

 

The sa[rl]l instructions take a bit mask of the least significant 5 bits from %cl to produce a value in the range [0, 31] and then shift %eax that many bits:

 

64 bit shifts become
sh[rl]dl  %eax, %edx
sa[rl]l   %cl, %eax

 

where %eax stores the least significant bits in the doubleword to be shifted, and %edx stores the most significant bits.

Risk Assessment

Although shifting a negative number of bits or more bits than exist in the operand is undefined behavior in C, the risk is generally low because processors frequently reduce the shift amount modulo the width of the type.


Rule

Severity

Likelihood

Detectable

Remediation Cost

Repairable

Priority

Level

INT34

INT35-C

Low

low

Unlikely

unlikely

No

medium

No

P2

P1

L3

Automated Detection

ToolVersionCheckerDescription

Compass/ROSE

 

 

Can detect violations of this rule. Unsigned operands are detected when checking for INT13-C. Use bitwise operators only on unsigned operands

ECLAIR1.2CC2.INT34Partially implemented

Fortify SCA

5.0

 

Can detect violations of this rule with CERT C Rule Pack

LDRA tool suite

8.5.4

403 S

Partially implemented

PRQA QA-C8.1

0499
0500
0501
2790
2791 (D)
2792 (A)
2793 (S)

Partially implemented

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

Related Guidelines

CERT C Secure Coding StandardINT13-C. Use bitwise operators only on unsigned operands
INT32-C. Ensure that operations on signed integers do not result in overflow
Astrée
Include Page
Astrée_V
Astrée_V

Supported: Astrée reports overflows due to insufficient precision.
CodeSonar
Include Page
CodeSonar_V
CodeSonar_V

LANG.ARITH.BIGSHIFT

Shift Amount Exceeds Bit Width

Cppcheck Premium

Include Page
Cppcheck Premium_V
Cppcheck Premium_V

premium-cert-int35-c
Helix QAC

Include Page
Helix QAC_V
Helix QAC_V

C0582

C++3115


Parasoft C/C++test

Include Page
Parasoft_V
Parasoft_V

CERT_C-INT35-a

Use correct integer precisions when checking the right hand operand of the shift operator

Polyspace Bug Finder

Include Page
Polyspace Bug Finder_V
Polyspace Bug Finder_V

CERT C: Rule INT35-CChecks for situations when integer precisions are exceeded (rule fully covered)

 

Related Guidelines

Key here (explains table format and definitions)

Taxonomy

Taxonomy item

Relationship

CWE 2.11CWE-681, Incorrect Conversion between Numeric Types

2017-10-30:MITRE:Unspecified Relationship

2018-10-18:CERT:Partial Overlap

CERT-CWE Mapping Notes

Key here for mapping notes

CWE-190 and INT35-C

Intersection( INT35-C, CWE-190) = Ø

INT35-C used to map to CWE-190 but has been replaced with a new rule that has no overlap with CWE-190.

CWE-681 and INT35-C

Intersection(INT35-C, CWE-681) = due to incorrect use of integer precision, conversion from one data type to another causing data to be omitted or translated in a way that produces unexpected values

CWE-681INT35-C = list2, where list2 =

  • conversion from one data type to another causing data to be omitted or translated in a way that produces unexpected values, not involving incorrect use of integer precision

INT35-C - CWE-681= list1, where list1 = 

  • incorrect use of integer precision not related to conversion from one data type to another
CERT C++ Secure Coding StandardINT34-CPP. Do not shift a negative number of bits or more bits than exist in the operandISO/IEC TR 24772:2013Arithmetic Wrap-around Error [FIF]

Bibliography

[Dowd 2006]Chapter 6, "C Language Issues"
[C99 Rationale 2003]
Subclause
6.5.7, "Bitwise Shift Operators"
[Seacord 2013]Chapter 5, "Integer Security"[Viega 2005]Section 5.2.7, "Integer Overflow"

A test program for this rule is available at www.securecoding.cert.org.

 



Image Removed Image Removed Image RemovedImage Added  Image Added   Image Added