...
In the following non-compliant code example, cBlocks is multiplied by 16 and the result is stored in the unsigned long long int alloc. The result of this multiplication can overflow because it is a 32 bit operation and the resulting value stored in alloc is invalid.
| Code Block |
|---|
void* AllocBlocks(size_t cBlocks) { if (cBlocks == 0) return NULL; unsigned long long alloc = cBlocks * 16; return (alloc < UINT_MAX) ? malloc(cBlocks * 16) : NULL; } |
Compliant Solution 1
On architectures where {{unsigned long long int is guaranteed to have 2x the number of bits as size_tupcast the variable used in the multiplication to a 64-bit value. This ensures the multiplication operation is performed
|
If size_t is implemented as a unsigned int type, the result of this multiplication can overflow because the multiplication is performed between two values of size int} and the resulting value stored in {{alloc is invalid.
If, on the other hand, size_t is implemented as an unsigned long long type, the result of the multiplication operation may not be representable as an unsigned long long value.
Compliant Solution 1
Upcasting only works when a size is represented using a smaller type. Because we recommend that all sizes be represented using size_t, upcasting is never a good idea. Instead, check to make sure the multiplication does not overflow using standard methods:
| Code Block |
|---|
void * |
| Code Block |
void* AllocBlocks(size_t cBlocks) { size_t alloc; if (cBlocks == 0) return NULL; unsigned long longsize_t alloc = (unsigned long long)multsize_t(cBlocks *, 16); returnif (alloc < UINT_MAX) ? malloc(cBlocks * 16) : NULL; } |
The assumption concerning the relationship of unsigned long long int and size_t must be document in the header for each file that depends upon this assumption for correct execution.
errno) {
return NULL;
}
else {
return malloc(alloc);
}
} /* end AllocBlocks */
|
References
...
- 1999 Section 7.20.3 Memory Management Functions
- Seacord 05 Chapter 4 Dynamic Memory Management