An object of type void *
is a generic data pointer. It can point to any data object. For any incomplete or object type T
, C permits implicit conversion from T *
to void *
or from void *
to T *
. The standard C library uses void *
to declare parameters and return types of functions designed to work for objects of different types. Such is the case with the standard C Standard memory allocation functions aligned_alloc()
, malloc()
, calloc()
, and realloc()
use void *
to declare parameters and return types of functions designed to work for objects of different types.
For example, the C Library library declares malloc()
as
Code Block |
---|
void *malloc(size_t); |
Calling malloc(s)
allocates memory for an object whose size is s
and returns either a null pointer or a pointer to the allocated memory. A program can implicitly convert the pointer that malloc()
returns into a different pointer type.
Because objects returned by the C Standard memory allocation functions are implicitly converted into any object type, we recommend casting the results of these functions into a pointer of the allocated type because it increases the chances that the compiler will catch and diagnose a mismatch between the intended type of the object and the actual type of the object.
Noncompliant Code Example
The argument to malloc()
can be any value of (unsigned) type size_t
. If the program uses the allocated storage to represent an object (possibly an array) whose size is greater than the requested size, the behavior is undefined. The implicit pointer conversion lets this slip by without complaint from the compiler.
...
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdlib.h> typedef struct gadget gadget; struct gadget { int i; double d; }; typedef struct widget widget; struct widget { char c[10]; int i; double d; }; widget *p; /* ... */ p = malloc(sizeof(gadget)); /* imminentImminent problem */ if (p != NULL) { p->i = 0; /* undefinedUndefined behavior */ p->d = 0.0; /* undefinedUndefined behavior */ } |
An implementation may add padding to a gadget or widget so that sizeof(gadget)
equals sizeof(widget)
, but this is highly unlikely. More likely, sizeof(gadget)
is less than sizeof(widget)
. In that case,
Code Block | ||||
---|---|---|---|---|
| ||||
p = malloc(sizeof(gadget)); /* imminentImminent problem */ |
quietly assigns p
to point to storage too small for a widget. The subsequent assignments to p->i
and p->d
will most likely produce memory overruns.
...
Code Block | ||||
---|---|---|---|---|
| ||||
widget *p; /* ... */ p = (gadget *)malloc(sizeof(gadget)); /* invalidInvalid assignment */ |
This lets the compiler detect the invalid assignment because it attempts to convert a gadget *
into a widget *
.
Compliant Solution (Hand
...
Coded)
This compliant solution repeats the same type in the sizeof
expression and the pointer cast:
...
Code Block | ||||
---|---|---|---|---|
| ||||
widget *p;
/* ... */
p = MALLOC(widget); /* OK */
if (p != NULL) {
p->i = 0; /* OK */
p->d = 0.0; /* OK */
}
|
...
A small collection of macros can provide secure implementations for common uses for the standard memory allocation functions. The omission of a REALLOC()
macro is intentional . (See MEM08see EXP39-C. Use realloc() only to resize dynamically allocated arrays.)Do not access a variable through a pointer of an incompatible type).
Code Block | ||||
---|---|---|---|---|
| ||||
/* allocatesAllocates a single object using malloc(). */ #define MALLOC(type) ((type *)malloc(sizeof(type))) /* allocatesAllocates an array of objects using malloc(). */ #define MALLOC_ARRAY(number, type) \ ((type *)malloc((number) * sizeof(type))) /* * allocatesAllocates a single object with a flexible * array member using malloc(). */ #define MALLOC_FLEX(stype, number, etype) \ ((stype *)malloc(sizeof(stype) \ + (number) * sizeof(etype))) /* allocatesAllocates an array of objects using calloc(). */ #define CALLOC(number, type) \ ((type *)calloc(number, sizeof(type))) /* reallocatesReallocates an array of objects using realloc(). */ #define REALLOC_ARRAY(pointer, number, type) \ ((type *)realloc(pointer, (number) * sizeof(type))) /* reallocates * Reallocates a single object with a flexible * array member using realloc(). */ #define REALLOC_FLEX(pointer, stype, number, etype) \ ((stype *)realloc(pointer, sizeof(stype) \ + (number) * sizeof(etype))) |
...
If one or more of the operands to the multiplication operations used in many of these macro definitions can be influenced by untrusted data, these operands should be checked for overflow before the macro is invoked . (See see INT32-C. Ensure that operations on signed integers do not result in overflow).)
The use of type-generic function-like macros is an allowed exception (PRE00-C-EX4) to PRE00-C. Prefer inline or static functions to function-like macros.
Exception
Exceptions
MEM02-C-EX1: Do not immediately cast the results of malloc()
for code that will be compiled using a C90-conforming compiler When compiling a 64-bit application on an LP64 or LLP64 platform, this recommendation should not be used because it is possible for the cast to hide a bug. If stdlib.h
is not properly included, the compiler will assume the declaration of malloc
() to be int malloc()
. When sizeof(int)
on the platform is 4, the resulting pointer could be truncated due to the compiler assuming malloc()
returns a 32-bit integer. Additionally, casting the results of malloc()
to a pointer on these platforms can also sign extend a negative 32-bit integer to an invalid pointer.
Code Block | ||||
---|---|---|---|---|
| ||||
/* #include <stdlib.h> is missing */
int main() {
int i;
for (i = 0; i < 100; ++i) {
char *ptr = (char*)malloc(0x10000000); /* int malloc() assumed */
*ptr = 'a';
}
return 0;
}
|
On an LLP64/LP64 platform, such as Microsoft Windows, the above code will eventually cause an access violation when dereferencing ptr in the loopmore critical defect (see DCL31-C. Declare identifiers before using them for a code example that uses malloc()
without first declaring it).
Risk Assessment
Failing to cast the result of a memory allocation function call into a pointer to the allocated type can result in inadvertent pointer conversions. Code that follows this recommendation will compile and execute equally well in C++.
Recommendation | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
MEM02-C |
Low |
Unlikely |
Low | P3 | L3 |
Automated Detection
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
Astrée |
| alloc-without-cast | Partially checked | ||||||
Axivion Bauhaus Suite |
| CertC-MEM02 | Fully implemented | ||||||
Compass/ROSE |
Can detect some violations of this recommendation when checking EXP36-C. Do not |
ECLAIR |
|
CC2.MEM02 | Fully implemented |
Fortify SCA
5.0
Can detect violations of this rule with CERT C Rule Pack
Helix QAC |
| C0695 | |||||||
Parasoft C/C++test |
| CERT_C-MEM02-a | The result of the memory allocation function should be cast immediately | ||||||
PC-lint Plus |
| 908 | Assistance provided: reports implicit conversions from void* to another type | ||||||
Polyspace Bug Finder |
| Checks for wrong allocated object size for cast (rule fully covered) | |||||||
RuleChecker |
| alloc-without-cast | Partially checked |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
SEI CERT C++ |
Coding Standard | VOID MEM02-CPP. Immediately cast the result of a memory allocation function call into a pointer to the allocated type |
Bibliography
...
...