[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 Libc-alpha
mailing list