logoalt Hacker News

amiga386today at 12:05 PM5 repliesview on HN

Can anyone explain why this is undefined behaviour? UBSan calls it "indirect call of a function through a function pointer of the wrong type"

    struct foo {int i;};
    int func(struct foo *x) {return x->i;}
    int main() {
        int (*funcptr)(void*) = (int (*)(void*)) &func;
        struct foo foo = { 42 };
        return funcptr(&foo);
    }
While this is all kosher per the language lawyers:

    struct foo {int i;};
    int func(void *x) {return ((struct foo *)x)->i;}
    int main() {
        int (*funcptr)(void*) = &func;
        struct foo foo = { 42 };
        return funcptr(&foo);
    }

Replies

jcranmertoday at 1:44 PM

C23 §6.5.2.2p7

> If the function is defined with a type that is not compatible with the type (of the expression) pointed to by the expression that denotes the called function, the behavior is undefined.

Compatible types requires integrating texts from several different paragraphs, but the general notion is "identical type, in a frontend sense", not "same ABI." This means that "const void " and "void " are not compatible types, much less "void " and "struct foo ".

wavemodetoday at 1:39 PM

It's undefined behavior due to the "strict aliasing" rule. You're simply not allowed to cast one pointer type to another (ever!) except for the following exceptions:

- casting an object pointer to or from void*

- casting an object pointer to or from char*

You're not doing either of those things. A function pointer is not an object pointer (the standard does not guarantee that the two kinds of pointer even have the same size/representation, and in fact on some esoteric hardware they don't), and even if it were, you aren't casting to or from void* or char*. So it's UB for two separate reasons.

show 1 reply
j16sdiztoday at 12:21 PM

Two function pointer (in practice) compatible or not depends on machine specific calling convention.

I guess enumerating all the possibility is just .. don't look right? make the standard too long and complex?

tomptoday at 12:09 PM

Casting to a pointer of incompatible type is UB. The exception is casting to char*.

show 1 reply
kingforadaytoday at 12:20 PM

[dead]