...
In cases where the memory allocation functions return a non-null pointer, using this pointer results in undefined behavior. Typically the pointer refers to a zero-length block of memory consisting entirely of control structures. Overwriting these control structures will damage the data structures used by the memory manager.
Noncompliant Code Example (malloc()
)
Noncompliant Code Example
The result of calling malloc(0)
to allocate 0 bytes is implementation - defined. In this example, a dynamic array of integers is allocated to store size
elements. However, if size
is zero0, the call to malloc(size)
may return a reference to a block of memory of size 0 instead of a null
pointer. When (nonempty) data is copied to this location, a heap-buffer overflow occurs.
Code Block | ||
---|---|---|
| ||
size_t size; /* initialize size, possibly by user-controlled input */ int *list = (int *)malloc(size); if (list == NULL) { /* Handle Allocationallocation Errorerror */ } else { /* Continue Processingprocessing list */ } |
Compliant
...
Solution
To ensure that zero is never passed as a size argument to malloc()
, size
is checked to ensure it has a positive value.
Code Block | ||
---|---|---|
| ||
size_t size; /* initialize size, possibly by user-controlled input */ if (size == 0) { /* Handle Errorerror */ } int *list = (int *)malloc(size); if (list == NULL) { /* Handle Allocationallocation Errorerror */ } /* Continue Processingprocessing list */ |
Noncompliant Code Example realloc()
...
The realloc()
function deallocates the old object and returns a pointer to a new object of a specified size. If memory for the new object cannot be allocated, the realloc()
function does not deallocate the old object and its value is unchanged. If the realloc()
function returns NULL, failing to free the original memory will result in a memory leak. As a result, the following idiom is often recommended for reallocating memory:
Code Block | ||
---|---|---|
| ||
size_t nsize; = /* initialize nsize some value, possibly user supplied */; char *p2; char *p = (char *)malloc(100); if (p == NULL) { /* Handle Errorerror */ } /* ... */ if ((p2 = (char *)realloc(p, nsize)) == NULL) { free(p); p = NULL; return NULL; } p = p2; |
...
If this noncompliant code is compiled with GCC 3.4.6 and linked with libc 2.3.4, invoking realloc(p, 0)
returns a non-null pointer to a zero-sized object (the same as malloc(0)
). However, if the same code is compiled with either Microsoft Visual Studio Version 7.1 or GCC version 4.1.0 , realloc(p, 0)
returns a null pointer, resulting in a double-free vulnerability.
Compliant Solution
This compliant solution does not pass a size argument of zero to the realloc()
function.
Code Block | ||
---|---|---|
| ||
size_t nsize; /* initialize nsize */ char *p2; char *p = (char *)malloc(100); if (p == NULL) { /* Handle Errorerror */ } /* ... */ p2 = NULL; if (nsize != 0) { p2 = (char *)realloc(p, nsize); } if (p2 == NULL) { free(p); p = NULL; return NULL; } p = p2; |
...