I know void *
and function pointers cannot be safely converted either way.
My question is the below code.
#include <stdio.h>
#include <stdlib.h>
void f(void *);
void g(void) {
printf("hello world\n");
}
int main(void) {
void (*p)(void) = g;
void (**pp)(void) = malloc(sizeof(void (*)(void)));
pp = &p;
f(pp);
free(pp); //segfault
return EXIT_SUCCESS;
}
void f(void *p) {
(*(void (**)(void))p)();
}
It compiles well in gcc with -Wall -Wextra -pedantic -std=c99
, but fails in runtime when the program calls free
. What is wrong in this case? Is a pointer to function pointer not a data pointer?
Afterthought:
The correct code is this,
int main(void) {
void (*p)(void) = g;
f(&p);
return EXIT_SUCCESS;
}
I have no idea why I got confused :/
There is a bug in your code:
You first allocate space for a function pointer and store the address in
pp
.Then you immediately overwrite that with the address of a local function function
p
:You call
f()
, which in turn calls the function pointer at the address passed.Finally you attempt to
free
the address of the local variable, this is undefined behaviour, a crash on your environment.Instead of
pp = &p;
, you probably meant to store the value ofp
in the allocated object:Your remark on converting
void *
and function pointers is correct:void *
pointers cannot be safely converted tovoid(*)()
nor vice versa. Object pointers and function pointers may have different incompatible representations.In your case, you implicitly convert the
void *
return value frommalloc()
to a pointer to a function pointervoid (**)()
. This conversion is correct sincemalloc
is defined as returning a pointer suitable for storing any object type (provided enough space was allocated).Reciprocally, you implicitly convert the pointer
pp
tovoid *
when passing it tof
, which in turn converts it back tovoid (**)()
. Such a conversion is defined because any object pointer can be safely converted tovoid *
and back to its original type. For completeness, all function pointers can be safely converted from one type to another as long as they are converted to the actual type of the function referenced before calling it.