Re: [PATCH] sockaddr.3type: BUGS: Document that libc should be fixed using a union

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sun, 2023-02-05 at 16:31 +0100, Alejandro Colomar via Libc-alpha wrote:

> The only correct way to use  different  types  in  an  API  is
> through  a  union.

I don't think this statement is true (in general).  Technically we can
write something like this:

struct sockaddr { ... };
struct sockaddr_in { ... };
struct sockaddr_in6 { ... };

int bind(int fd, const struct sockaddr *addr, socklen_t addrlen)
{
    if (addrlen < sizeof(struct sockaddr) {
        errno = EINVAL;
        return -1;
    }

    /* cannot use "addr->sa_family" directly: it will be an UB */
    sa_family_t sa_family;
    memcpy(&sa_family, addr, sizeof(sa_family));

    switch (sa_family) {
        case AF_INET:
            return _do_bind_in(fd, (struct sockaddr_in *)addr, addrlen);
        case AF_INET6:
            return _do_bind_in6(fd, (struct sockaddr_in6 *)addr, addrlen);
        /* more cases follow here */
        default:
            errno = EINVAL;
            return -1;
        }
    }
}

In this way we can use sockaddr_{in,in6,...} for bind() safely, as long
as we can distinguish the "real" type of addr using the leading byte
sequence (and the caller uses it carefully).

But obviously sockaddr_storage can't be distinguished here, so casting a
struct sockaddr_stroage * to struct sockaddr * and passing it to bind()
will still be wrong (unless we make sockaddr_storage an union or add
[[gnu::may_alias]]).

-- 
Xi Ruoyao <xry111@xxxxxxxxxxx>
School of Aerospace Science and Technology, Xidian University




[Index of Archives]     [Kernel Documentation]     [Netdev]     [Linux Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux