...
This code example is non-compliant 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 integer overflow by assigning the value UINT_MAX to max and testing if length + BLOCK_HEADER_SIZE > max. Because length is declared as size_t, however, the addition is performed as a 32-bit operation and can result in an integer overflow. The comparison with max in this example will always test false. If an overflow occurs, malloc() will allocate insufficient space for mBlock which could lead to a subsequent buffer overflow.
| Code Block | ||
|---|---|---|
| ||
enum { BLOCKSIZE = 16 };
unsigned long long max = UINT_MAX;
void *AllocateBlock(size_t length) {
struct memBlock *mBlock;
if (length + BLOCK_HEADER_SIZE > max) return NULL;
mBlock = malloc(length + BLOCK_HEADER_SIZE);
if (!mBlock) return NULL;
/* fill in block header and return data portion */
return mBlock;
}
|
...
In this compliant solution, the length operand is upcast to unsigned long long ensuring that the addition takes place in this size.
| Code Block | ||
|---|---|---|
| ||
enum { BLOCKSIZE = 16 };
unsigned long long max = UINT_MAX;
void *AllocateBlock(size_t length) {
struct memBlock *mBlock;
if ((unsigned long long)length + BLOCK_HEADER_SIZE > max) return NULL;
mBlock = malloc(length + BLOCK_HEADER_SIZE);
if (!mBlock) return NULL;
/* fill in block header and return data portion */
return mBlock;
}
|
This test for integer overflow is only effective 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 value, the result of the addition operation may not be representable as an unsigned long long value.
Non-Compliant Code Example
In this non-compliant code example, the programmer attempts to prevent integer overflow by allocating an unsigned long long integer called alloc and assigning it the result from cBlocks * 16.
| Code Block | ||
|---|---|---|
| ||
enum { BLOCKSIZE = 16 };
unsigned long long max = UINT_MAX;
...
void* AllocBlocks(size_t cBlocks) {
if (cBlocks == 0) return NULL;
unsigned long long alloc = cBlocks * 16;
return (alloc < UINT_MAX) ? malloc(cBlocks * 16) : NULL;
}
|
...