Reputation: 19
If I free a pointer that was cast from one for a different type, I assume it will cause a memory leak; however, I couldn't find a definitive answer.
Example:
typedef struct ExampleStruct_s
{
uint32_t a;
uint32_t b;
uint32_t c;
} ExampleStruct_t;
void main(void)
{
ExampleStruct_t *p_struct = (ExampleStruct_t*)malloc(sizeof(ExampleStruct_t));
uint32_t *p_uint32 = (uint32_t*) p_struct;
free(p_uint32);
}
Upvotes: 1
Views: 183
Reputation: 23218
This:
int main(void)
{
ExampleStruct_t *p_struct = (ExampleStruct_t*)malloc(sizeof(ExampleStruct_t));
uint32_t *p_uint32 = (uint32_t*) p_struct;
free(p_uint32);
}
Is perfectly valid as the pointer returned by malloc() is of type void *
thus preserving proper alignment. (Even after a cast to a pointer of different type.) Additionally, because the address of p_uint32
will be precisely the same as the address of p_struct
, no memory leak will occur upon the call to free()
.
The only suggestions are to remove the cast and to use sizeof
the object being allocated, not its type.:
ExampleStruct_t *p_struct = malloc(sizeof(*p_struct));
...and use int main(void){...
rather than void main(void)
. (The standards do provide wiggle room here, but it is clearly more widely accepted as proper.)
Upvotes: 0
Reputation: 222753
Per C 2018 7.22.3.4, malloc
returns a void *
. Per 7.22.3.3, the parameter to free
is a void *
, and an argument to it is converted to void *
, per 6.5.2.2 7. So the parameter to free
is never a different type than the original pointer to the allocated space; it starts and ends as void *
.
There would only be a problem if the value were different. The rules for pointer conversions are in 6.3.2.3. Effectively, they allow conversions through pointers to different object types as long as the pointer is correctly aligned for the referenced type. Per 7.22.3 1, the value returned by malloc
is suitable for any fundamental alignment, which includes all the basic, enumerated, and pointer types and all pointers to arrays, structures, or unions whose elements or members have fundamental alignment requirements and all complete object types defined for the standard library. So, as long as you do not convert a pointer from malloc
to some implementation-defined extended type with a greater-than-fundamental alignment requirement or to a type that uses _Alignas
to specify a greater alignment, the conversions will effectively preserve the original value of the pointer returned from malloc
.
Upvotes: 4
Reputation: 223972
The main concern here is the cast from ExampleStruct_t *
to uint32_t *
. Undefined behavior will happen if the pointer is not correctly aligned. However since the pointer value was returned from malloc
it is properly aligned for any type, so that should be fine.
Given that, the conversion in the second line of main
is safe. So passing that pointer to free
(which was returned from malloc
) will properly free the memory.
Relevant quotes from the C standard:
6.3.2.3p1:
A pointer to
void
may be converted to or from a pointer to any object type. A pointer to any object type may be converted to a pointer tovoid
and back again; the result shall compare equal to the original pointer
6.3.2.3p7:
A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined.
Otherwise, when converted back again, the result shall compare equal to the original pointer. When a pointer to an object is converted to a pointer to a character type,the result points to the lowest addressed byte of the object. Successive increments of the result, up to the size of the object, yield pointers to the remaining bytes of the object.
7.22.3p1:
... The pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to a pointer to any type of object with a fundamental alignment requirement and then used to access such an object or an array of such objects in the space allocated (until the space is explicitly deallocated) ...
Upvotes: 0
Reputation: 51835
The value returned from a call to malloc
is a void*
pointer (which is a pointer to an unspecified type) - as is the argument passed in a call to free
. (See also: Do I cast the result of malloc?)
So, as long as you have not actually changed the value of the pointer (i.e. the address it contains), then there will be no issue with memory leaks in your code.
Upvotes: 2