From: Alejandro Colomar <alx.manpages@gmail.com>
To: Xi Ruoyao <xry111@xry111.site>,
linux-man@vger.kernel.org, Rich Felker <dalias@libc.org>
Cc: "Alejandro Colomar" <alx@kernel.org>, GCC <gcc@gcc.gnu.org>,
glibc <libc-alpha@sourceware.org>,
"Bastien Roucariès" <rouca@debian.org>,
"Stefan Puiu" <stefan.puiu@gmail.com>,
"Igor Sysoev" <igor@sysoev.ru>,
"Andrew Clayton" <a.clayton@nginx.com>,
"Richard Biener" <richard.guenther@gmail.com>,
"Zack Weinberg" <zack@owlfolio.org>,
"Florian Weimer" <fweimer@redhat.com>,
"Joseph Myers" <joseph@codesourcery.com>,
"Jakub Jelinek" <jakub@redhat.com>,
"Eric Blake" <eblake@redhat.com>
Subject: Re: [PATCH] sockaddr.3type: BUGS: Document that libc should be fixed using a union
Date: Mon, 6 Feb 2023 12:55:12 +0100 [thread overview]
Message-ID: <ae73337b-7b37-9c94-e5e0-d6ebbf2c7ffb@gmail.com> (raw)
In-Reply-To: <0a9306fa37edeb4a989b2929de67fee8606a3d8a.camel@xry111.site>
[-- Attachment #1.1: Type: text/plain, Size: 3028 bytes --]
Hi Xi,
On 2/6/23 07:02, 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).
True; I hadn't thought of memcpy()ing the first member of the struct. That's
valid; overcomplicated but valid.
>
> 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]]).
But as you say, it still leaves us with a question. What should one declare for
passing to the standard APIs? It can only be a union. So we can either tell
users to each create their own union, or we can make sockaddr_storage be a
union. The latter slightly violates POSIX due to namespaces as Rich noted, but
that's a minor violation, and POSIX can be changed to accomodate for that.
If we change sockaddr_storage to be a union, we have two benefits:
- Old code which uses sockaddr_storage is made conforming (non-UB) without
modifying the source.
- Users can inspect the structures.
If we don't, and deprecate sockaddr_storage, we should tell users to declare
their own unions _and_ treat all these structures as black boxes which can only
be read by memcpy()ing their contents.
Which of the two do we want? I think fixing sockaddr_storage is simpler, and
allows existing practice of reading these structures. The other one just makes
(or rather acknowledges, since it has always been like that) a lot of existing
code invoke UB, and acknowledges that you can't safely use these structures
without a lot of workarounding.
Cheers,
Alex
--
<http://www.alejandro-colomar.es/>
GPG key fingerprint: A9348594CE31283A826FBDD8D57633D441E25BB5
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
next prev parent reply other threads:[~2023-02-06 11:55 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-02-05 15:28 [PATCH] sockaddr.3type: BUGS: Document that libc should be fixed using a union Alejandro Colomar
2023-02-05 15:31 ` Alejandro Colomar
2023-02-06 6:02 ` Xi Ruoyao
2023-02-06 11:20 ` Rich Felker
2023-02-06 11:55 ` Alejandro Colomar [this message]
2023-02-06 13:38 ` Rich Felker
2023-02-06 14:11 ` Alejandro Colomar
2023-02-06 17:48 ` Rich Felker
2023-02-05 23:43 ` Rich Felker
2023-02-05 23:59 ` Alejandro Colomar
2023-02-06 0:15 ` Rich Felker
2023-02-06 18:45 ` Eric Blake
2023-02-07 1:21 ` Alejandro Colomar
2023-03-18 7:54 ` roucaries bastien
2023-03-20 10:49 ` Alejandro Colomar
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ae73337b-7b37-9c94-e5e0-d6ebbf2c7ffb@gmail.com \
--to=alx.manpages@gmail.com \
--cc=a.clayton@nginx.com \
--cc=alx@kernel.org \
--cc=dalias@libc.org \
--cc=eblake@redhat.com \
--cc=fweimer@redhat.com \
--cc=gcc@gcc.gnu.org \
--cc=igor@sysoev.ru \
--cc=jakub@redhat.com \
--cc=joseph@codesourcery.com \
--cc=libc-alpha@sourceware.org \
--cc=linux-man@vger.kernel.org \
--cc=richard.guenther@gmail.com \
--cc=rouca@debian.org \
--cc=stefan.puiu@gmail.com \
--cc=xry111@xry111.site \
--cc=zack@owlfolio.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.