Versions Compared

Key

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

Integer constants are often used as masks or specific bit values. Frequently, these constants are expressed in hexadecimal form to indicate to the programmer how the data might be represented in the machine. However, Hexadecimal hexadecimal integer constants are frequently used in a non-portable nonportable manner.

Noncompliant Code Example

The In this pedagogical noncompliant code example attempts to take two's complement of a value of type unsigned long using a mask, the flipbits() function complements the value stored in x by performing a bitwise exclusive OR against a mask with all bits set to 1. For implementations where unsigned long is represented by a 32-bit value, each bit of x is correctly complemented.

Code Block
bgColor#FFCCCC
langc
/* (Incorrect) Set all bits in mask to 1 */
const unsigned long mask = 0xFFFFFFFF;  

unsigned long x;

/* Initializeflipbits(unsigned long x) */{

x  =return (x ^ mask) + 1;
}

This code produces the two's complement of x for implementations where unsigned long have a precision of 32 bits. HoweverHowever, on implementations where values of type unsigned long are represented by greater than 32 bits, mask will have leading 0s. For example, on implementations where values of type unsigned long has a precision of are 64 bits , this code does not produce the two's complement of x. Because long, mask is assigned the value 0x00000000FFFFFFFF. Consequently, only the lower-order 32- bits are set, the resulting value of mask is 0x00000000FFFFFFFFof x are complemented.

Compliant Solution

...

(−1)

In this compliant solution, the integer constant -1 is used and safer) way to set all the bits on in an integer constant mask to 1. The integer constant -1 is of type signed int. Because -1 cannot be represented by a variable of type unsigned long, it is to define a constant with a value of ~0converted to a representable number according to the rule in subclause 6.3.1.3, paragraph 2, of the C Standard [ISO/IEC 9899:2011]:

[If the value can't be represented by the new type and] if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.

"One more than the maximum value that can be represented in the new type," ULONG_MAX + 1, is added to -1, resulting in a right-side value of ULONG_MAX. The representation of ULONG_MAX is guaranteed to have all bits set to 1 by subclause 6.2.6.2, paragraph 1:

For unsigned integer types other than unsigned char, the bits of the object representation shall be divided into two groups: value bits and padding bits (there need not be any of the latter). If there are N valuebits, each bit shall represent a different power of 2 between 1 and 2N − 1, so that objects of that type shall be capable of representing values from 0 to 2N − 1 using a pure binary representation; this shall be known as the value representation. The values of any padding bits are unspecified.

By the same reasoning, -1 is suitable for setting all bits to one of any unsigned integer variable. Subclause 6.2.6.1, paragraph 3, guarantees the same results for unsigned char:

Values stored in unsigned bit-fields and objects of type unsigned char shall be represented using a pure binary notation.

Code Block
bgColor#CCCCFF
langc
/* (Correct) Set all bits in mask to 1 */
const unsigned long mask = ~0-1;

unsigned long x;

/* Initializeflipbits(unsigned long x) */{

x  =return (x ^ mask) + 1;
}

This compliant solution sets all the bits in the value regardless of representation.

Noncompliant Code Example

In this noncompliant code example, a programmer is attempting attempts to set the most significant bit. :

Code Block
bgColor#FFCCCC
langc

const unsigned long mask = 0x80000000;
unsigned long x;

/* Initialize x */

x |= (x ^ mask) + 1;

This code has the desired effect for implementations where unsigned long have has a precision of 32 bits but not on for implementations where unsigned long has a precision of 64 bits.

Compliant Solution

A portable (and safer) way of setting the high-order bit is to use a shift expression, as in this compliant solution.:

Code Block
bgColor#CCCCFF
langc

const unsigned long mask =  (1 << ((sizeof(unsigned long) * CHAR_BIT) -~(ULONG_MAX >> 1));
unsigned long x;

/* Initialize x */

x |= (x ^ mask) + 1;

Risk Assessment

Vulnerabilities are frequently introduced while porting code. A buffer overflow vulnerability may result, for example, if an incorrectly defined integer constant is used to determine the size of a buffer. It is always best to write portable code, especially when there is no performance overhead for doing so.

Recommendation

Severity

Likelihood

Detectable

Remediation Cost

Repairable

Priority

Level

INT17-C

High

high

Probable

probable

No

low

No

P6

L3

Automated Detection

Tool

Version

Checker

Description

Axivion Bauhaus Suite

Include Page
Axivion Bauhaus Suite_V
Axivion Bauhaus Suite_V

CertC-INT17
L2

Related Vulnerabilities

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

Other Languages

...

Related Guidelines

...

...

...

Bibliography

...

[

...

Dewhurst 2002]Gotcha #25, "#define Literals"
[ISO/IEC 9899:2011]Subclause 6.2.6, "Representations of Types"
Subclause 6.3.1.3, "Signed and Unsigned Integers"


...

Image Added Image Added 9899-1999|AA. Bibliography#ISO/IEC 9899-1999]] Section 6.4.4.1, "Integer constants"Image Removed      04. Integers (INT)      Image Modified