Conversion between a void pointer and a pointer to function pointer

1.1k views Asked by At

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 :/

1

There are 1 answers

4
chqrlie On BEST ANSWER

There is a bug in your code:

You first allocate space for a function pointer and store the address in pp.

void (**pp)(void) = malloc(sizeof(void (*)(void)));

Then you immediately overwrite that with the address of a local function function p:

pp = &p;

You call f(), which in turn calls the function pointer at the address passed.

f(pp);

Finally you attempt to free the address of the local variable, this is undefined behaviour, a crash on your environment.

free(pp); //segfault

Instead of pp = &p;, you probably meant to store the value of p in the allocated object:

*pp = p;

Your remark on converting void * and function pointers is correct: void * pointers cannot be safely converted to void(*)() nor vice versa. Object pointers and function pointers may have different incompatible representations.

In your case, you implicitly convert the void * return value from malloc() to a pointer to a function pointer void (**)(). This conversion is correct since malloc is defined as returning a pointer suitable for storing any object type (provided enough space was allocated).

Reciprocally, you implicitly convert the pointer pp to void * when passing it to f, which in turn converts it back to void (**)(). Such a conversion is defined because any object pointer can be safely converted to void * 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.