Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Noncompliant Code Example

This noncompliant code example is noncompliant on systems where size_t is an unsigned 32-bit value and long long is a 64-bit value. In this example, the programmer tests for wrapping by comparing SIZE_MAX to length + BLOCK_HEADER_SIZE. Because length is declared as size_t, the addition is performed as a 32-bit operation and can result in wrapping. The comparison with SIZE_MAX will always test false. If any wrapping occurs, malloc() will allocate insufficient space for mBlock, which can lead to a subsequent buffer overflow.

Code Block
bgColor#FFcccc
langc
enum { BLOCK_HEADER_SIZE = 16 };

void *AllocateBlock(size_t length) {
  struct memBlock *mBlock;

  if (length + BLOCK_HEADER_SIZE > (unsigned long long)SIZE_MAX)
    return NULL;
  mBlock = (struct memBlock *)malloc(
    length + BLOCK_HEADER_SIZE
  );
  if (!mBlock) return NULL;

  /* fillFill in block header and return data portion */

  return mBlock;
}

...

Code Block
bgColor#ccccff
langc
enum { BLOCK_HEADER_SIZE = 16 };

void *AllocateBlock(size_t length) {
  struct memBlock *mBlock;

  if ((unsigned long long)length + BLOCK_HEADER_SIZE > SIZE_MAX) {
    return NULL;
  }
  mBlock = (struct memBlock *)malloc(
    length + BLOCK_HEADER_SIZE
  );
  if (!mBlock) return NULL;

  /* fillFill in block header and return data portion */

  return mBlock;
}

This test for wrapping is effective only when the sizeof(unsigned long long) > sizeof(size_t). If both size_t and unsigned long long types are represented as a 64-bit unsigned valuevalues, the result of the addition operation may not be representable as an unsigned long long value.

...

In this compliant solution, length is subtracted from SIZE_MAX, ensuring that wrapping cannot occur. See INT30-C. Ensure that unsigned integer operations do not wrap.

Code Block
bgColor#ccccff
langc
enum { BLOCK_HEADER_SIZE = 16 };

void *AllocateBlock(size_t length) {
  struct memBlock *mBlock;

  if (SIZE_MAX - length < BLOCK_HEADER_SIZE) return NULL;
  mBlock = (struct memBlock *)malloc(
    length + BLOCK_HEADER_SIZE
  );
  if (!mBlock) return NULL;
  /* fillFill in block header and return data portion */

  return mBlock;
}

...

Code Block
bgColor#FFcccc
langc
void *AllocBlocks(size_t cBlocks) {
  if (cBlocks == 0) return NULL;
  unsigned long long alloc = cBlocks * 16;
  return (alloc < UINT_MAX) ? malloc(cBlocks * 16) : NULL;
}

There are two problems with Two problems occur in this noncompliant code example. The first problem is that this code assumes an implementation where unsigned long long has at least 4 more bits than size_t. The second problem, assuming an implementation where size_t is a 32-bit value and unsigned long long is represented by a 64-bit value, is that to be compliant with C, multiplying two 32-bit numbers in this context must yield a 32-bit result. Any wrapping resulting from this multiplication will remain undetected by this code, and the expression alloc < UINT_MAX will always be true.

...

Failure to cast integers before comparing or assigning them to a larger integer size can result in software vulnerabilities that can allow the execution of arbitrary code by an attacker with the permissions of the vulnerable process.

...

Tool

Version

Checker

Description

Compass/ROSE

 

 

Can detect violations of this rule. It should look for patterns of (a op1 b) op2 c where:

    • c has a bigger type than a or b
    • Neither a nor b are is typecast to c's type
    • op2 is assignment or comparison
Coverity6.5OVERFLOW_BEFORE_WIDENFully Implemented

Fortify SCA

5.0

 

Can detect violations of this rule with CERT C Rule Pack

PRQA QA-C
Include Page
PRQA_V
PRQA_V

1890
1891
1892
1893
1894
1895
2790 (C)

Partially implemented

...