The title maybe confusing. Suppose str
is a pointer allocated by malloc
. ptr
, of type int*
, is assigned to it and is freed as shown by the code snippet below:
char* str = malloc(64);
int* ptr = str;
free(ptr);
I've tried to compile the above code. It just gives a warning:
source_file.c: In function ‘main’:
source_file.c:10:16: warning: initialization from incompatible pointer type
int* ptr = str;
^
Does the above code invoke Undefined Behavior?
Does the above code snippet free the memory allocated by malloc
for str
?
Does the above code invoke Undefined Behavior?
It depends.
From C11 draft 6.3.2.3/7:
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.
As the alignment for a char
might be different from an int
, that is probably less restrictive, assigning a char * pc
to an int * pi
might lead to pi
being misaligned.
However for the specific example given by the OP:
char * pc = malloc(64);
int * pi = pc;
the behaviour would be defined, as (See Alter Mann's comment) malloc()
is guaranteed to return a block of memory properly aligned.
From C11 draft 7.22.3:
The
pointer returned [by aligned_alloc, calloc, malloc, and realloc] 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 ...
An example which would lead to undefined behaviour, due to misalignment, is:
char * pc = malloc(64);
int * pi = pc + 1;
Does the above code snippet free the memory allocated by malloc for str?
In case the former assignment would have introduced undefined behaviour this question is irrelevant, as anything could happen with UB having been invoked already.
If else the prior assignment wouldn't have invoked UB, the call to free()
would perfectly de-allocate the block of memory referenced, as converting back the pointer value from int *
to void *
, as originally provided by malloc()
, is well defined.
From C11 draft 6.3.2.3/7 (cont/):
Otherwise, when converted back again, the result shall compare equal to the
original pointer
and
From C11 draft 6.3.2.3/1:
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 to void and back again; the result shall
compare equal to the original pointer
No. It doesn't invoke undefined behaviour. The warning is simply about incompatible types which you could cast.
char* str = malloc(64);
int* ptr = (int*) str;
free(ptr);
free
does take a void pointer and the above has no problems. However, using the result of such a value may invoke undefined behaviour due to alignment of int type and char type. As such the conversion of char*
to int*
itself doesn't lead to undefined.
Does the above code invoke Undefined Behavior?
No.
Does the above code snippet free the memory allocated by malloc for str?
Yes.
Just for clarification, some notes on UB regarding dynamic allocation:
Memory returned by malloc
is aligned to take any possible value. Such memory has no declared type and its effective type is set through storage.
If you do
*ptr = 42;
the first sizeof (int)
bytes of the memory block will now be of type int
and may only be read as such, ie
float val = *(float *)ptr;
will be UB.
However,
*(float *)ptr = 42.0;
would be legal as it re-sets the effective type, now in turn making reads through *ptr
invalid.
In addition, it is always legal to access any object through pointers of type char
or unsigned char
.
It may invoke UB, based on endianness, alignments or such int vs char typecasting when accessed. When you do malloc all it does is return a void*
which can be of any data type(and in some cases may require typecasting). It doesn't make a difference if you put a pointer in char* to int*, but there would be difference in access units, i.e in case of ints 4 bytes at a time vs in char 1 byte at a time. So, that code in your question wouldn't invoke UB, but memory accesses might.
As for second question, yes calling free on ptr
will cause memory pointed by str
also to be freed. Now, str
would be a dangling pointer.