Hi,

After reading more about transparent_unit, here's my idea of a fix for the API. old_api() is an example for the libc functions that accept a `struct sockaddr *`, and user_code() is an example for user code functions that handle sockaddr structures. The interface would be the same as it is currently, but the implementation inside libc would change to use a union. In user code, uses of sockaddr_storage would be made safe with these changes, I believe, and new code would be simpler, since it wouldn't need casts.



void old_api(union my_sockaddr_ptr *sa);


struct sockaddr_storage {
        union {
                struct {
                        sa_family_t  ss_family;
                };
                struct sockaddr_in   sin;
                struct sockaddr_in6  sin6;
                struct sockaddr_un   sun;
                // ...
        };
};


union [[gnu::transparent_union]] sockaddr_ptr {
        struct sockaddr_storage  *ss;
        struct sockaddr          *sa;
};


void old_api(struct sockaddr_storage *ss)
{
        // Here libc uses the union, so it doesn't invoke UB.
        ss->sun.sa_family = AF_UNIX;
        //...
}


void user_code(void)
{
        struct my_sockaddr_storage  ss;  // object definition

        // ...

        old_api(&ss);  // The transparent_union allows no casts.

        switch (ss.ss_family) {
                // This is safe too.
                // thanks to common initial sequence within a union.
        }
}


This would in fact deprecate plain `struct sockaddr`, as Bastien suggested.


Cheers,

Alex


--
<http://www.alejandro-colomar.es/>

Attachment: OpenPGP_signature
Description: OpenPGP digital signature

Reply via email to