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

Rich Felker dalias@libc.org
Mon Feb 6 11:20:20 GMT 2023


On Mon, Feb 06, 2023 at 02:02:23PM +0800, Xi Ruoyao wrote:
> 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]]).

If you wanted to make this work, you can just memcpy sockaddr_storage
to a local object of the right declared type to access it. But this is
only relevant for a userspace implementation of bind() rather than one
that just marshalls it across some syscall boundary to a kernel.

Rich


More information about the Gcc mailing list