If ptr
was allocated with an alignment returned from Do not invoke realloc()
to modify the size of allocated objects that have stricter alignment requirements than those guaranteed by malloc()
. Storage allocated by a call to the standard aligned_alloc()
and if realloc()
reallocates memory with a different alignment then, the behavior is undefined. This rule only applies to compilers that conform to the (emerging) C1X standard \[[Jones 09|AA. C References#Jones 09]\]. function, for example, can have stricter than normal alignment requirements. The C standard requires only that a pointer returned by Wiki Markup realloc()
be suitably aligned so that it may be assigned to a pointer to any type of object with a fundamental alignment requirement.
Noncompliant Code Example
This noncompliant code example aligns ptr
returns a pointer to allocated memory that has been aligned to a 4096-byte boundary whereas . If the resize
argument to the realloc()
function aligns the memory to a different alignment (assuming that the sizeof(double) = 8
and sizeof(float) = 4
.)is larger than the object referenced by ptr
, then realloc()
will allocate new memory that is suitably aligned so that it may be assigned to a pointer to any type of object with a fundamental alignment requirement but may not preserve the stricter alignment of the original object.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdlib.h> void func(void) { size_t sizeresize = 161024; size_t alignment = 1<<121 << 12; float int *ptr; double int *ptr1; ptr =if aligned_alloc(alignNULL , size); ptr1== (ptr = realloc(ptr, size); |
...
int *)aligned_alloc( |
...
Compliant Solution
This compliant example checks that aligned_alloc()
has the same alignment as the alignment realloc()
function enforces on the memory pointed to by ptr
(again assuming that the sizeof(double) = 8
and sizeof(float) = 4
).
Code Block | ||
---|---|---|
| ||
size_t size = 16; size_t alignment = 1<<12; float *ptr; double *ptr1; ptr = aligned_alloc(align , size); if(align == alignof(ptr1alignment, sizeof(int)))) { /* Handle error */ } if (NULL == (ptr1 = (int *)realloc(ptr, resize))) { ptr1 = realloc(ptr, size); } |
Implementation Details
Another noncompliant example that has been implemented on the x86_64-redhat-linux platform and compiled with gcc version 4.1.2 is as follows:
/* Handle error */
}
} |
Implementation Details
When compiled with GCC 4.1.2 and run on the x86_64 Red Hat Linux platform, the following code produces the following output:
CODE
Code Block |
---|
#include <stdlib.h>
#include <stdio |
Code Block |
#include<stdlib.h> #include<stdio.h> int main(void) { size_t size = 16; size_t resize = 101024; size_t align = 1 << 12; floatint *ptr; doubleint *ptr1; if (posix_memalign((void **)&ptr, align , 4size); if((ptr1 = realloc((int *)ptr, size)) == NULL) { exit(0); } ptr[0] = 12.5; ptr[1] = 25.5; != 0) { exit(EXIT_FAILURE); } printf("memory aligned to %d%zu bytes\n\n", align); printf("ptr[0] : %p = %f = %p\n\n",ptr, ptr[0]); printf("ptr[1] : %p = %f\n\n",&ptr[1], ptr[1]); printf if ((ptr1 = (int*) realloc((int *)ptr, resize)) == NULL) { exit(EXIT_FAILURE); } puts("After realloc(): \n"); printf("ptr1[0] := %p = %lf\n", ptr1, ptr[0]); printffree("ptr1[1] : %p = %lf\n\n",&ptr1[1], ptr1[1]); printf("The value at ptr[1] remains the same after realloc()\n"); printf("ptr[1] : %p = %f\n",((float *)ptr1+1),*((float *)ptr1+1)); free(ptr1); return 0; } |
The noncompliant example produces the following (unexpected) output.
Code Block |
---|
memory aligned to 4096 bytes
ptr[0] : 0xb43c000 = 12.500000
ptr[1] : 0xb43c004 = 25.500000
After realloc():
ptr1[0] : 0xb43c000 = 12.500000
ptr1[1] : 0xb43c008 = 0.000000
The value at ptr[1] remains the same after realloc()
ptr[1] : 0xb43c004 = 25.500000
|
Risk Assessment
ptr1);
return 0;
}
|
OUTPUT
Code Block |
---|
memory aligned to 4096 bytes
ptr = 0x1621b000
After realloc():
ptr1 = 0x1621a010
|
ptr1
is no longer aligned to 4096 bytes.
Compliant Solution
This compliant solution allocates resize
bytes of new memory with the same alignment as the old memory, copies the original memory content, and then frees the old memory. This solution has implementation-defined behavior because it depends on whether extended alignments in excess of _Alignof (max_align_t)
are supported and the contexts in which they are supported. If not supported, the behavior of this compliant solution is undefined.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdlib.h>
#include <string.h>
void func(void) {
size_t resize = 1024;
size_t alignment = 1 << 12;
int *ptr;
int *ptr1;
if (NULL == (ptr = (int *)aligned_alloc(alignment,
sizeof(int)))) {
/* Handle error */
}
if (NULL == (ptr1 = (int *)aligned_alloc(alignment,
resize))) {
/* Handle error */
}
if (NULL == memcpy(ptr1, ptr, sizeof(int))) {
/* Handle error */
}
free(ptr);
} |
Compliant Solution (Windows)
Windows defines the _aligned_malloc()
function to allocate memory on a specified alignment boundary. The _aligned_realloc()
[MSDN] can be used to change the size of this memory. This compliant solution demonstrates one such usage:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <malloc.h>
void func(void) {
size_t alignment = 1 << 12;
int *ptr;
int *ptr1;
/* Original allocation */
if (NULL == (ptr = (int *)_aligned_malloc(sizeof(int),
alignment))) {
/* Handle error */
}
/* Reallocation */
if (NULL == (ptr1 = (int *)_aligned_realloc(ptr, 1024,
alignment))) {
_aligned_free(ptr);
/* Handle error */
}
_aligned_free(ptr1);
} |
The size
and alignment
arguments for _aligned_malloc()
are provided in reverse order of the C Standard aligned_alloc()
function.
Risk Assessment
Improper alignment can lead to arbitrary memory locations being accessed and written toImproper alignment could lead to accessing arbitrary memory locations and write into it.
Recommendation | Severity | Likelihood | Remediation Cost | Priority | Level |
---|
MSC36-C
medium
probable
medium
P8
L2
References
MEM36-C | Low | Probable | High | P2 | L3 |
Automated Detection
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
Astrée |
| Supported, but no explicit checker | |||||||
Axivion Bauhaus Suite |
| CertC-MEM36 | Fully implemented | ||||||
CodeSonar |
| BADFUNC.REALLOC | Use of realloc | ||||||
Cppcheck Premium |
| premium-cert-mem36-c | Fully implemented | ||||||
Helix QAC |
| C5027 C++5034 | |||||||
Klocwork |
| AUTOSAR.STDLIB.MEMORY | |||||||
LDRA tool suite |
| 44 S | Enhanced enforcement | ||||||
Parasoft C/C++test |
| CERT_C-MEM36-a | Do not modify the alignment of objects by calling realloc() | ||||||
| CERT C: Rule MEM36-C | Checks for alignment change after memory allocation (rule fully covered) |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Bibliography
[ISO/IEC 9899:2024] | 7.24.3.1, "The aligned_alloc Function" |
[MSDN] | aligned_malloc() |
...
\[[Jones 09|AA. C References#Jones 09]\] Section 7.21.3 Wiki Markup