From: Alejandro Colomar <alx@kernel.org>
To: Joseph Myers <josmyers@redhat.com>
Cc: "G. Branden Robinson" <g.branden.robinson@gmail.com>,
linux-man@vger.kernel.org, Keith Bostic <keith@bostic.com>,
Mark Harris <mark.hsj@gmail.com>,
Nevin Liber <nevin@cplusplusguy.com>,
JeanHeyd Meneide <phdofthehouse@gmail.com>,
Christopher Bazley <chris.bazley.wg14@gmail.com>,
"Serge E. Hallyn" <serge@hallyn.com>,
Iker Pedrosa <ipedrosa@redhat.com>,
"Evgeny Grin (Karlson2k)" <k2k@drgrin.dev>,
Kees Cook <keescook@chromium.org>,
bug-gnulib@gnu.org, libc-alpha@sourceware.org,
Martin Sebor <msebor@redhat.com>
Subject: Re: on the irresponsibility of pursuing C language reform (was: [PATCH 1/2] man/man3/{mem,strn}*(): SYNOPSIS, STANDARDS: Document these as provided by <memory.h>)
Date: Sat, 1 Aug 2026 01:45:04 +0200 [thread overview]
Message-ID: <am0vIUDzNzTnXMcI@devuan> (raw)
In-Reply-To: <9223d084-7de4-914f-9b53-8862510542d8@redhat.com>
[-- Attachment #1: Type: text/plain, Size: 7346 bytes --]
Hi Joseph,
> Date: 2026-07-31 23:11:56+0000
> From: Joseph Myers <josmyers@redhat.com>
>
> On Sat, 1 Aug 2026, Alejandro Colomar wrote:
>
> > > In other words, they were in that header for 6 years, and it's been
> > > implicitly obsolescent by virtue of the standard choice for the 37 years
> > > since then.
> >
> > Yes. And I'm trying to revert the implicit obsolescence. Obsolescence
> > isn't a one-way process. Sometimes, evidence shows up, and the obsolete
> > feature must come back for $reasons.
>
> When it's been obsolescent for 37 years, bringing back a header with the
> same name is just going to confuse people with 37 years of past
> information saying it's obsolescent (normally if one source says "use X"
> and another says "X is obsolescent", you can reliably assume that "X is
> obsolescent" is the more recent information, even without 37 years of
> history involved).
This is highly speculative.
If the official documentation says use <memory.h>, use <memory.h>.
Moreover, I've never seen anything saying <memory.h> is obsolescent.
It's been only implicitly obsolescent, and most programmers don't even
know <memory.h> exists at all. FWIW, I've sometimes seen it in the
system headers, and eventually wondered why it was there, but nothing
else. Thus, there's no contradicting information about it.
> Any reasonable change there would involve a new
> header, say <strnpad.h> for strncpy and strncat,
I think that misses that strn*() are still relatively misunderstood.
It's only because they don't write that they aren't as dangerous.
But we would be much better with strprefix/suffix() and other related
functions in <string.h> to even further remove uses of strn*()
functions.
Moving the entirety of strn*() might be less urgent/important than
moving strncpy/cat(), but it'd still be good to move them. They are all
about handling [[gnu::nonstring]]s.
> rather than resurrecting
> a very old one.
I think the very old one is much better, because it can be used by
virtually all programs already, since it already is there in all systems
that matter, and already provides the functions were moving there.
Apart from documentation, there's no real change.
On the other hand, if we were adding a new header, it'd have to be
wrapped in #if __has_include(), and wouldn't be used until 10 years from
now or so.
> > The solution of moving both mem*() and strn*() to <memory.h> and leaving
> > just str*() in <string.h> is a consistent one, because <string.h> then
> > remains strictly for string APIs, and <memory.h> is for the rest of byte
> > handling.
>
> It's inconsistent with how people have understood C ever since it was
> standardized. Changing the header memcpy is in is just as ridiculous at
> this point as the proposal there once was to obsolesce NULL.
I disagree. Obsolescing NULL is a deeply breaking change.
Standardizing an existing header file is just like standardizing an
existing function. Nobody is saying <string.h> won't provide memcpy(3).
My proposal to C2y says that <string.h> includes <memory.h>, so nothing
changes. All of the existing understanding remains valid (although less
preferred).
> > It wouldn't be reasonable to move strn*() to <memory.h>, and then leave
> > mem*() in <string.h>, of course.
> >
> > Similarly, it wouldn't be reasonable to more strncpy/cat() to <memory.h>
> > and leave the rest of strn*() and all of mem*() in <string.h>.
>
> On the contrary, it's only the functions for null-padded fixed-width
> buffers that are niche functions causing confusion, compared to all the
> rest of the functions in <string.h> for which it's a very well-established
> and well-understood location. Some others like memccpy are *obscure*, but
> not confusing in the same way.
Did you read my alx-0096 paper? It shows how n2349 --which introduced
memccpy(3) in C23-- is full of UB in examples introduced as
To avoid the risk of buffer overflow, the appropriate bound
needs to be determined for each call and provided as an
argument.
If memccpy(3) was standardized for reducing buffer overflows (which is
implied, but not very explicitly said in the paper), it's ironic that
the examples of how it's supposed to be used invoke UB. If the author
of the paper can't avoid UB, you can guess it's a bomb as bad as
strncpy(3) once was. And I'm not saying that memccpy(3) is bad, not
that strncpy(3) is bad. I use strncpy(3) and know it's fine, and have
been recently shown that memccpy(3) is actually good for implementing
fgets(3). But it's not a function for copying strings, and n2349 is the
ultimate proof. It is just as bad as strncpy(3) if misused for copying
strings.
I'll paste here part of alx-0096, which clarifies how n2349 invokes UB.
Reading N2349 further, one finds an example of copying with
truncation:
char *p = memccpy (d, s1, '\0', dsize);
dsize -= (p - d - 1);
memccpy (p - 1, s2, '\0', dsize);
This is more prone to bugs than the case above, and more than
strncpy(3). Anyone suggesting to use this to improve safety
compared to strncpy(3), please, please, explain to me how they
think this can be safe in any way.
In fact, the code above is completely bogus, because if the
string is truncated, p will be NULL, and it invokes UB in
line 2. See how it was predictably prone to bugs? :)
At the bottom of the N2349 paper, there's a more correct --and
also more worrying-- example of how memccpy(3) could be used for
copying strings with truncation. This shows how terrible
memccpy(3) is for copying strings:
char *p = memccpy (d, s1, '\0', dsize);
if (p) {
--p;
p = memccpy (p, "/", '\0', dsize - (p - d));
if (p) {
--p;
p = memccpy (p, s2, '\0', dsize - (p - d));
}
}
if (!p)
d[dsize - 1] = '\0';
I think I don't need to explain what can go wrong in such
unreadable, brittle, and complex code.
...
Using a more suitable function --similar to POSIX's stpcpy(3)--,
this could be written much more safely:
char *p = d;
char *e = d + dsize;
p = stpecpy(p, e, s1);
p = stpecpy(p, e, "/");
p = stpecpy(p, e, s2);
if (p == NULL)
goto trunc; // The string was truncated
Here's how stpecpy() can be implemented for this:
char *
stpecpy(char *dst, const char *end, const char *restrict src)
{
ssize_t dlen;
if (dst == NULL)
return NULL;
dlen = strtcpy(dst, src, end - dst);
if (dlen == -1)
return NULL;
return dst + dlen;
}
Cheers,
Alex
--
<https://www.alejandro-colomar.es>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
next prev parent reply other threads:[~2026-07-31 23:45 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-31 21:18 [PATCH 0/2] alx-0097r1 - <memory.h>, the legitimate header for memcpy(3) et al Alejandro Colomar
2026-07-31 21:18 ` [PATCH 1/2] man/man3/{mem,strn}*(): SYNOPSIS, STANDARDS: Document these as provided by <memory.h> Alejandro Colomar
2026-07-31 21:23 ` Joseph Myers
2026-07-31 21:28 ` Alejandro Colomar
2026-07-31 21:54 ` Sam James
2026-07-31 22:18 ` Alejandro Colomar
2026-08-01 0:12 ` Alejandro Colomar
2026-07-31 21:51 ` on the irresponsibility of pursuing C language reform (was: [PATCH 1/2] man/man3/{mem,strn}*(): SYNOPSIS, STANDARDS: Document these as provided by <memory.h>) G. Branden Robinson
2026-07-31 21:59 ` on the irresponsibility of pursuing C language reform Sam James
2026-07-31 22:24 ` G. Branden Robinson
2026-07-31 23:19 ` Alejandro Colomar
2026-07-31 22:10 ` on the irresponsibility of pursuing C language reform (was: [PATCH 1/2] man/man3/{mem,strn}*(): SYNOPSIS, STANDARDS: Document these as provided by <memory.h>) Joseph Myers
2026-07-31 22:21 ` Alejandro Colomar
2026-07-31 22:28 ` [PATCH 1/2] man/man3/{mem,strn}*(): SYNOPSIS, STANDARDS: Document these as provided by <memory.h> G. Branden Robinson
2026-07-31 22:42 ` on the irresponsibility of pursuing C language reform (was: [PATCH 1/2] man/man3/{mem,strn}*(): SYNOPSIS, STANDARDS: Document these as provided by <memory.h>) Joseph Myers
2026-07-31 22:52 ` Alejandro Colomar
2026-07-31 23:11 ` Joseph Myers
2026-07-31 23:32 ` G. Branden Robinson
2026-07-31 23:45 ` Alejandro Colomar [this message]
2026-07-31 23:08 ` [PATCH 1/2] man/man3/{mem,strn}*(): SYNOPSIS, STANDARDS: Document these as provided by <memory.h> G. Branden Robinson
2026-07-31 23:28 ` Joseph Myers
2026-07-31 23:57 ` G. Branden Robinson
2026-08-01 0:06 ` Alejandro Colomar
2026-07-31 22:05 ` Alejandro Colomar
2026-07-31 22:16 ` Joseph Myers
2026-07-31 22:33 ` Alejandro Colomar
2026-07-31 23:48 ` [PATCH 1/2] man/man3/{mem, strn}*(): " Collin Funk
2026-07-31 23:52 ` Alejandro Colomar
2026-08-01 0:01 ` Alejandro Colomar
2026-07-31 21:19 ` [PATCH 2/2] man/man*/{string.3,memory.h.3head}: Move functions to a new page memory.h(3head) Alejandro Colomar
2026-07-31 21:20 ` [PATCH 0/2] alx-0097r1 - <memory.h>, the legitimate header for memcpy(3) et al Alejandro Colomar
2026-08-01 0:25 ` [PATCH v2] man/man3/mem*(): SYNOPSIS: Document non-standard mem*() functions as provided by <memory.h> 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=am0vIUDzNzTnXMcI@devuan \
--to=alx@kernel.org \
--cc=bug-gnulib@gnu.org \
--cc=chris.bazley.wg14@gmail.com \
--cc=g.branden.robinson@gmail.com \
--cc=ipedrosa@redhat.com \
--cc=josmyers@redhat.com \
--cc=k2k@drgrin.dev \
--cc=keescook@chromium.org \
--cc=keith@bostic.com \
--cc=libc-alpha@sourceware.org \
--cc=linux-man@vger.kernel.org \
--cc=mark.hsj@gmail.com \
--cc=msebor@redhat.com \
--cc=nevin@cplusplusguy.com \
--cc=phdofthehouse@gmail.com \
--cc=serge@hallyn.com \
/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.