From: Alejandro Colomar <alx@kernel.org>
To: linux-man@vger.kernel.org
Cc: Keith Bostic <keith@bostic.com>,
Joseph Myers <josmyers@redhat.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,
Alejandro Colomar <alx@kernel.org>
Subject: [PATCH 1/2] man/man3/{mem,strn}*(): SYNOPSIS, STANDARDS: Document these as provided by <memory.h>
Date: Fri, 31 Jul 2026 23:18:59 +0200 [thread overview]
Message-ID: <784288e704183a4297aeaa3d13af8edab18bc1ea.1785532392.git.alx@kernel.org> (raw)
In-Reply-To: <cover.1785532392.git.alx@kernel.org>
[-- Attachment #1: Type: text/plain, Size: 13166 bytes --]
The standard mixes functions for handling strings, functions for
handling bytes, and other hybrids, all in a single header file:
<string.h>.
This has historically caused confusion, for example leading to believe
that strncpy(3) is appropriate to handle strings.
It turns out that mem*() functions haven't been always in <string.h>.
These functions were first introduced in 1983 in System V, and were
added in a separate <memory.h> file. Very soon, they were added to
4.3BSD in 1986 for compatibility to System V, also in <memory.h>.
Most modern-day POSIX-compatible libc implementations still provide this
header file for backwards compatibility reasons:
$ find ~/src/bsd/freebsd/main/ | grep /include/memory.h
/home/alx/src/bsd/freebsd/main/include/memory.h
$ find ~/src/bsd/netbsd/trunk/ | grep /include/memory.h
/home/alx/src/bsd/netbsd/trunk/include/memory.h
$ find ~/src/bsd/openbsd/master/ | grep /include/memory.h
/home/alx/src/bsd/openbsd/master/include/memory.h
$ find ~/src/gnu/glibc/master/ | grep /include/memory.h
/home/alx/src/gnu/glibc/master/include/memory.h
$ find ~/src/musl/libc/master/ | grep /include/memory.h
/home/alx/src/musl/libc/master/include/memory.h
It seems that it was C89 that moved the mem*() functions to <string.h>,
even though the Rationale document for C89 doesn't mention it at all.
This was a huge mistake --we can see the consequences in the many
misuses of these functions, and programmers that believe they are
appropriate for uses for which they are unappropriate-- that we can undo
now.
Let's document these as provided by <memory.h>, which is still true;
all POSIX-ish libc implementations I've consulted provide the <memory.h>
header with mem*() functions, except two: Illumos gate, and gnulib.
Let's ignore them, or rather, hope they will follow suit eventually.
This will signal to programmers that this is the header file they should
be using. The C Committee is discussing the possibility of
standardizing the good old <memory.h> header file, so let's give it a
little bump.
Let's also move the strn*() functions there, since modern libc
implementations also provide them there. And they certainly don't
belong in <string.h>, so <memory.h> is more adequate.
After this change, <string.h> contains only functions that exclusively
handle (and require) strings.
Cc: Keith Bostic <keith@bostic.com>
Cc: Joseph Myers <josmyers@redhat.com>
Cc: Mark Harris <mark.hsj@gmail.com>
Cc: Nevin Liber <nevin@cplusplusguy.com>
Cc: JeanHeyd Meneide <phdofthehouse@gmail.com>
Cc: Christopher Bazley <chris.bazley.wg14@gmail.com>
Cc: "Serge E. Hallyn" <serge@hallyn.com>
Cc: Iker Pedrosa <ipedrosa@redhat.com>
Cc: "Evgeny Grin (Karlson2k)" <k2k@drgrin.dev>
Cc: Kees Cook <keescook@chromium.org>
Cc: bug-gnulib@gnu.org
Cc: libc-alpha@sourceware.org
Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
man/man3/memccpy.3 | 5 ++++-
man/man3/memchr.3 | 5 ++++-
man/man3/memcmp.3 | 5 ++++-
man/man3/memcpy.3 | 5 ++++-
man/man3/memfrob.3 | 2 +-
man/man3/memmem.3 | 2 +-
man/man3/memmove.3 | 5 ++++-
man/man3/mempcpy.3 | 2 +-
man/man3/memrchr.3 | 2 +-
man/man3/memset.3 | 5 ++++-
man/man3/stpncpy.3 | 8 +++++++-
man/man3/strcasecmp.3 | 6 ++++++
man/man3/strcmp.3 | 6 ++++++
man/man3/strdup.3 | 5 +++++
man/man3/strdupa.3 | 4 ++++
man/man3/strncat.3 | 5 ++++-
man/man3/strnlen.3 | 5 ++++-
17 files changed, 64 insertions(+), 13 deletions(-)
diff --git a/man/man3/memccpy.3 b/man/man3/memccpy.3
index 706f8152f58c..a6bc4e8a3e0b 100644
--- a/man/man3/memccpy.3
+++ b/man/man3/memccpy.3
@@ -12,7 +12,7 @@ .SH LIBRARY
.RI ( libc ,\~ \-lc )
.SH SYNOPSIS
.nf
-.B #include <string.h>
+.BR #include\~<memory.h> " // See STANDARDS"
.P
.BR "void *memccpy(" "size_t n;"
.BI " void " dest "[restrict " n "], const void " src "[restrict " n ],
@@ -67,6 +67,9 @@ .SH ATTRIBUTES
.TE
.SH STANDARDS
POSIX.1-2008.
+.P
+ISO C and POSIX declare this function in
+.IR <string.h> .
.SH HISTORY
POSIX.1-2001, SVr4, 4.3BSD.
.SH SEE ALSO
diff --git a/man/man3/memchr.3 b/man/man3/memchr.3
index 0a493ff4029d..f3ee95c00406 100644
--- a/man/man3/memchr.3
+++ b/man/man3/memchr.3
@@ -12,7 +12,7 @@ .SH LIBRARY
.RI ( libc ,\~ \-lc )
.SH SYNOPSIS
.nf
-.B #include <string.h>
+.BR #include\~<memory.h> " // See STANDARDS"
.P
.BR "void *memchr(" "size_t n;"
.BI " const void " s [ n "], int " c ", size_t " n );
@@ -53,6 +53,9 @@ .SH ATTRIBUTES
.TE
.SH STANDARDS
C11, POSIX.1-2008.
+.P
+ISO C and POSIX declare this function in
+.IR <string.h> .
.SH HISTORY
POSIX.1-2001, C89, SVr4, 4.3BSD.
.SH SEE ALSO
diff --git a/man/man3/memcmp.3 b/man/man3/memcmp.3
index 9cecb282ba4f..467f24cb39a7 100644
--- a/man/man3/memcmp.3
+++ b/man/man3/memcmp.3
@@ -12,7 +12,7 @@ .SH LIBRARY
.RI ( libc ,\~ \-lc )
.SH SYNOPSIS
.nf
-.B #include <string.h>
+.BR #include\~<memory.h> " // See STANDARDS"
.P
.BR "int memcmp(" "size_t n;"
.BI " const void " s1 [ n "], const void " s2 [ n "], size_t " n );
@@ -70,6 +70,9 @@ .SH ATTRIBUTES
.TE
.SH STANDARDS
C11, POSIX.1-2008.
+.P
+ISO C and POSIX declare this function in
+.IR <string.h> .
.SH HISTORY
POSIX.1-2001, C89, SVr4, 4.3BSD.
.SH CAVEATS
diff --git a/man/man3/memcpy.3 b/man/man3/memcpy.3
index f8f049bf5c4c..7083dc3f7577 100644
--- a/man/man3/memcpy.3
+++ b/man/man3/memcpy.3
@@ -13,7 +13,7 @@ .SH LIBRARY
.RI ( libc ,\~ \-lc )
.SH SYNOPSIS
.nf
-.B #include <string.h>
+.BR #include\~<memory.h> " // See STANDARDS"
.P
.BR "void *memcpy(" "size_t n;"
.BI " void " dest "[restrict " n "], const void " src "[restrict " n ],
@@ -53,6 +53,9 @@ .SH ATTRIBUTES
.TE
.SH STANDARDS
C11, POSIX.1-2008.
+.P
+ISO C and POSIX declare this function in
+.IR <string.h> .
.SH HISTORY
POSIX.1-2001, C89, SVr4, 4.3BSD.
.SH CAVEATS
diff --git a/man/man3/memfrob.3 b/man/man3/memfrob.3
index ee41da0ced7b..ad736949002c 100644
--- a/man/man3/memfrob.3
+++ b/man/man3/memfrob.3
@@ -13,7 +13,7 @@ .SH LIBRARY
.SH SYNOPSIS
.nf
.BR "#define _GNU_SOURCE" " /* See feature_test_macros(7) */"
-.B #include <string.h>
+.B #include <memory.h>
.P
.BR "void *memfrob(" "size_t n;"
.BI " void " s [ n "], size_t " n );
diff --git a/man/man3/memmem.3 b/man/man3/memmem.3
index 13fd8b7cea7b..d0f99e6d577d 100644
--- a/man/man3/memmem.3
+++ b/man/man3/memmem.3
@@ -13,7 +13,7 @@ .SH LIBRARY
.SH SYNOPSIS
.nf
.BR "#define _GNU_SOURCE" " /* See feature_test_macros(7) */"
-.B #include <string.h>
+.B #include <memory.h>
.P
.BR "void *memmem(" "size_t hsize, size_t nsize;"
.BI " const void " haystack [ hsize "], size_t " hsize ,
diff --git a/man/man3/memmove.3 b/man/man3/memmove.3
index 99f152412142..65f6a67b9b35 100644
--- a/man/man3/memmove.3
+++ b/man/man3/memmove.3
@@ -12,7 +12,7 @@ .SH LIBRARY
.RI ( libc ,\~ \-lc )
.SH SYNOPSIS
.nf
-.B #include <string.h>
+.BR #include\~<memory.h> " // See STANDARDS"
.P
.BR "void *memmove(" "size_t n;"
.BI " void " dest [ n "], const void " src [ n "], size_t " n );
@@ -56,6 +56,9 @@ .SH ATTRIBUTES
.TE
.SH STANDARDS
C11, POSIX.1-2008.
+.P
+ISO C and POSIX declare this function in
+.IR <string.h> .
.SH HISTORY
POSIX.1-2001, C89, SVr4, 4.3BSD.
.SH SEE ALSO
diff --git a/man/man3/mempcpy.3 b/man/man3/mempcpy.3
index 012e6326dd00..4598be5d7bc2 100644
--- a/man/man3/mempcpy.3
+++ b/man/man3/mempcpy.3
@@ -14,7 +14,7 @@ .SH LIBRARY
.SH SYNOPSIS
.nf
.BR "#define _GNU_SOURCE" " /* See feature_test_macros(7) */"
-.B #include <string.h>
+.B #include <memory.h>
.P
.BR "void *mempcpy(" "size_t n;"
.BI " void " dest "[restrict " n "], const void " src "[restrict " n ],
diff --git a/man/man3/memrchr.3 b/man/man3/memrchr.3
index 6e49defc5e4a..fe2841147f05 100644
--- a/man/man3/memrchr.3
+++ b/man/man3/memrchr.3
@@ -13,7 +13,7 @@ .SH LIBRARY
.SH SYNOPSIS
.nf
.BR #define\~_GNU_SOURCE " // See feature_test_macros(7)"
-.B #include <string.h>
+.B #include <memory.h>
.P
.BR void\~*memrchr( size_t\~n;
.BI " const void " s [ n "], int " c ", size_t " n );
diff --git a/man/man3/memset.3 b/man/man3/memset.3
index 91b3b476abf9..b69398a7762a 100644
--- a/man/man3/memset.3
+++ b/man/man3/memset.3
@@ -12,7 +12,7 @@ .SH LIBRARY
.RI ( libc ,\~ \-lc )
.SH SYNOPSIS
.nf
-.B #include <string.h>
+.BR #include\~<memory.h> " // See STANDARDS"
.P
.BR "void *memset(" "size_t n;"
.BI " void " s [ n "], int " c ", size_t " n );
@@ -48,6 +48,9 @@ .SH ATTRIBUTES
.TE
.SH STANDARDS
C11, POSIX.1-2008.
+.P
+ISO C and POSIX declare this function in
+.IR <string.h> .
.SH HISTORY
POSIX.1-2001, C89, SVr4, 4.3BSD.
.SH SEE ALSO
diff --git a/man/man3/stpncpy.3 b/man/man3/stpncpy.3
index 5b1ec5595169..4d959fde9f83 100644
--- a/man/man3/stpncpy.3
+++ b/man/man3/stpncpy.3
@@ -14,7 +14,7 @@ .SH LIBRARY
.RI ( libc ,\~ \-lc )
.SH SYNOPSIS
.nf
-.B #include <string.h>
+.BR #include\~<memory.h> " // See STANDARDS"
.P
.BR "char *strncpy(" "size_t dsize;"
.BI " char " dst "[restrict " dsize "], const char *restrict " src ,
@@ -97,9 +97,15 @@ .SH STANDARDS
.TP
.BR strncpy ()
C11, POSIX.1-2008.
+.IP
+ISO C and POSIX declare this function in
+.IR <string.h> .
.TP
.BR stpncpy ()
POSIX.1-2008.
+.IP
+POSIX declares this function in
+.IR <string.h> .
.SH HISTORY
.TP
.BR strncpy ()
diff --git a/man/man3/strcasecmp.3 b/man/man3/strcasecmp.3
index 65941ddf6524..a4100a0d0f02 100644
--- a/man/man3/strcasecmp.3
+++ b/man/man3/strcasecmp.3
@@ -15,6 +15,9 @@ .SH SYNOPSIS
.B #include <strings.h>
.P
.BI "int strcasecmp(const char *" s1 ", const char *" s2 );
+.P
+.BR #include\~<memory.h> " // See STANDARDS"
+.P
.BI "int strncasecmp(const char " s1 "[], const char " s2 "[], size_t " n );
.fi
.SH DESCRIPTION
@@ -70,6 +73,9 @@ .SH ATTRIBUTES
.TE
.SH STANDARDS
POSIX.1-2008.
+.P
+POSIX declares both functions in
+.IR <string.h> .
.SH HISTORY
4.4BSD, POSIX.1-2001.
.P
diff --git a/man/man3/strcmp.3 b/man/man3/strcmp.3
index 0a573e52d936..2909a0b7ea64 100644
--- a/man/man3/strcmp.3
+++ b/man/man3/strcmp.3
@@ -16,6 +16,9 @@ .SH SYNOPSIS
.B #include <string.h>
.P
.BI "int strcmp(const char *" s1 ", const char *" s2 );
+.P
+.BR #include\~<memory.h> " // See STANDARDS"
+.P
.BR "int strncmp(const char " s1 "[], const char " s2 "[], size_t " n );
.fi
.SH DESCRIPTION
@@ -107,6 +110,9 @@ .SH VERSIONS
(If the two characters are equal, this difference is 0.)
.SH STANDARDS
C11, POSIX.1-2008.
+.P
+ISO C and POSIX declare both functions in
+.IR <string.h> .
.SH HISTORY
POSIX.1-2001, C89, SVr4, 4.3BSD.
.SH EXAMPLES
diff --git a/man/man3/strdup.3 b/man/man3/strdup.3
index f3ab0611a323..c12cd3071dd9 100644
--- a/man/man3/strdup.3
+++ b/man/man3/strdup.3
@@ -16,6 +16,8 @@ .SH SYNOPSIS
.P
.BI "char *strdup(const char *" s );
.P
+.BR #include\~<memory.h> " // See STANDARDS"
+.P
.BR "char *strndup(" "size_t n;"
.BI " const char " s [ n "], size_t " n );
.fi
@@ -93,6 +95,9 @@ .SH ATTRIBUTES
.TE
.SH STANDARDS
POSIX.1-2008.
+.P
+POSIX declares both functions in
+.IR <string.h> .
.SH HISTORY
.TP
.BR strdup ()
diff --git a/man/man3/strdupa.3 b/man/man3/strdupa.3
index 63b12c83e9ec..412eec9f3491 100644
--- a/man/man3/strdupa.3
+++ b/man/man3/strdupa.3
@@ -16,6 +16,10 @@ .SH SYNOPSIS
.B #include <string.h>
.P
.BI "char *strdupa(const char *" s );
+.P
+.BR "#define _GNU_SOURCE" " /* See feature_test_macros(7) */"
+.B #include <memory.h>
+.P
.BR "char *strndupa(" "size_t n;"
.BI " const char " s [ n "], size_t " n );
.fi
diff --git a/man/man3/strncat.3 b/man/man3/strncat.3
index dd39d54939d9..dc74e0fefbc3 100644
--- a/man/man3/strncat.3
+++ b/man/man3/strncat.3
@@ -11,7 +11,7 @@ .SH LIBRARY
.RI ( libc ,\~ \-lc )
.SH SYNOPSIS
.nf
-.B #include <string.h>
+.BR #include\~<memory.h> " // See STANDARDS"
.P
.BR "char *strncat(" "size_t ssize;"
.BI " char *restrict " dst ", const char " src "[restrict " ssize ],
@@ -57,6 +57,9 @@ .SH ATTRIBUTES
.TE
.SH STANDARDS
C11, POSIX.1-2008.
+.P
+ISO C and POSIX declare this function in
+.IR <string.h> .
.SH HISTORY
POSIX.1-2001, C89, SVr4, 4.3BSD.
.SH CAVEATS
diff --git a/man/man3/strnlen.3 b/man/man3/strnlen.3
index 553a39a9ec7a..657fc8c7ae9c 100644
--- a/man/man3/strnlen.3
+++ b/man/man3/strnlen.3
@@ -12,7 +12,7 @@ .SH LIBRARY
.RI ( libc ,\~ \-lc )
.SH SYNOPSIS
.nf
-.B #include <string.h>
+.BR #include\~<memory.h> " // See STANDARDS"
.P
.BR "size_t strnlen(const char " s "[], size_t " maxlen );
.fi
@@ -83,6 +83,9 @@ .SH ATTRIBUTES
.TE
.SH STANDARDS
POSIX.1-2008.
+.P
+ISO C and POSIX declare this function in
+.IR <string.h> .
.SH HISTORY
POSIX.1-2008.
.SH SEE ALSO
--
2.53.0
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
next prev parent reply other threads:[~2026-07-31 21:19 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 ` Alejandro Colomar [this message]
2026-07-31 21:23 ` [PATCH 1/2] man/man3/{mem,strn}*(): SYNOPSIS, STANDARDS: Document these as provided by <memory.h> 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 ` on the irresponsibility of pursuing C language reform (was: " Alejandro Colomar
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=784288e704183a4297aeaa3d13af8edab18bc1ea.1785532392.git.alx@kernel.org \
--to=alx@kernel.org \
--cc=bug-gnulib@gnu.org \
--cc=chris.bazley.wg14@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=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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox