2

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

2
  • 1
    pp already rewrite by &p. free(pp) is UB. Commented Jun 9, 2015 at 0:37
  • I think you need to read about malloc() and understand deeply what it does and what it is for. Commented Jun 9, 2015 at 0:49

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

4 Comments

Last sentence. OP does that twice: malloc returns a void* pointer which is converted to a function pointer, and passing a function pointer to f().
@2501: no, malloc returns a void* that is converted to a pointer to a function pointer, f is passed a pointer to a function pointer that can be converted to void* and back.
no, malloc returns a void* that is converted to a pointer to a function pointer Contradiction: Your remark on converting void* and function pointers is correct, but you do no such thing in your code. ?????? Converting function pointers to object pointers is undefined in C. Even OP knows that: I know void* and function pointers cannot be safely converted either way.
@2501: The OP knows that, and I acknowledge it. The OP does not convert void* pointers to function pointers, but merely to pointers to function pointers. Type void (**)() is a data pointer. I updated my answer to make this more explicit.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.