git: d08296c7ab0d - main - libc: Implement qualifier-preserving standard library functions

Faraz Vahedi <[email protected]>
Newsgroups gmane.os.freebsd.devel.cvs.src
Message-ID <6a7df341.47136.739b699d__43734.974406992$1786639186$gmane$org@gitrepo.freebsd.org>
The branch main has been updated by kfv:

URL: https://cgit.FreeBSD.org/src/commit/?id=d08296c7ab0d7bb259bf7b8cdf9ffb819c1929ab

commit d08296c7ab0d7bb259bf7b8cdf9ffb819c1929ab
Author:     Faraz Vahedi <[email protected]>
AuthorDate: 2026-06-19 21:50:20 +0000
Commit:     Faraz Vahedi <[email protected]>
CommitDate: 2026-08-13 16:38:49 +0000

    libc: Implement qualifier-preserving standard library functions
    
    Several standard library functions are specified to return an unqualified
    pointer while accepting a pointer to a potentially const-qualified object.
    N3020 addresses this behaviour, discarding qualifiers due to incompatible
    pointer types, by introducing qualifier-preserving macros for the affected
    set of standard library functions.
    
    Add `__qualsel()` helper to `<sys/cdefs.h>`, implemented using the generic
    selection, and define qualifier-preserving macros for that set of functions
    in `<string.h>`, `<wchar.h>`, and `<stdlib.h>`.
    
    Macros are gated on `_STDC_VERSION__ >= 202311L && !__cplusplus`, therefore
    there is no behavioural change for earlier C modes or C++ translation units.
    The kernel is likewise unaffected, as it does not include userland headers.
    
    As function-like macros, they are transparent except at a call site where
    the address-of operator is applied, the macro is suppressed via `#undef`,
    or the identifier appears in parenthesised form; all of which cause the
    underlying function designator to be used instead.
    
    Reviewed by:    fuz
    Approved by:    fuz (mentor)
    MFC after:      1 month
    Pull Request:   https://github.com/freebsd/freebsd-src/pull/2288
---
 include/stdlib.h          | 12 ++++++++++
 include/string.h          | 28 ++++++++++++++++++++++++
 include/wchar.h           | 14 ++++++++++++
 lib/libc/stdlib/bsearch.3 |  5 +++--
 lib/libc/string/bstring.3 |  9 ++++++--
 lib/libc/string/memchr.3  | 13 +++++++----
 lib/libc/string/memmem.3  |  5 +++++
 lib/libc/string/strchr.3  | 12 ++++++++--
 lib/libc/string/string.3  | 16 +++++++++-----
 lib/libc/string/strpbrk.3 |  8 +++----
 lib/libc/string/strstr.3  | 21 ++++++++++++++----
 lib/libc/string/wmemchr.3 | 56 ++++++++++++++++++++++++++++++++++++++---------
 sys/sys/cdefs.h           | 21 ++++++++++++++++++
 13 files changed, 187 insertions(+), 33 deletions(-)

diff --git a/include/stdlib.h b/include/stdlib.h
index c1f465e21fd1..d61e2de99693 100644
--- a/include/stdlib.h
+++ b/include/stdlib.h
@@ -418,4 +418,16 @@ errno_t	 qsort_s(void *, rsize_t, rsize_t,
 __END_DECLS
 __NULLABILITY_PRAGMA_POP
 
+#if defined(__qualsel) && !defined(__cplusplus) && \
+    defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
+#define	bsearch(key, base, nmemb, size, compar)		__qualsel((base),    \
+	(const void *)(bsearch)((key), (base), (nmemb), (size), (compar)),   \
+	(bsearch)((key), (base), (nmemb), (size), (compar)))
+#ifdef __BLOCKS__
+#define	bsearch_b(key, base, nmemb, size, compar)	__qualsel((base),    \
+	(const void *)(bsearch_b)((key), (base), (nmemb), (size), (compar)), \
+	(bsearch_b)((key), (base), (nmemb), (size), (compar)))
+#endif
+#endif
+
 #endif /* !_STDLIB_H_ */
diff --git a/include/string.h b/include/string.h
index e9aa1b55281a..98a0a6396848 100644
--- a/include/string.h
+++ b/include/string.h
@@ -205,4 +205,32 @@ errno_t memset_s(void *, rsize_t, int, rsize_t);
 #endif /* __EXT1_VISIBLE */
 __END_DECLS
 
+#if defined(__qualsel) && !defined(__cplusplus) && \
+    defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
+#define	memchr(b, c, n)		__qualsel((b),				\
+	(const void *)(memchr)((b), (c), (n)), (memchr)((b), (c), (n)))
+#define	strchr(s, c)		__qualsel((s),				\
+	(const char *)(strchr)((s), (c)), (strchr)((s), (c)))
+#define	strpbrk(s, charset)	__qualsel((s),				\
+	(const char *)(strpbrk)((s), (charset)), (strpbrk)((s), (charset)))
+#define	strrchr(s, c)		__qualsel((s),				\
+	(const char *)(strrchr)((s), (c)), (strrchr)((s), (c)))
+#define	strstr(s, find)		__qualsel((s),				\
+	(const char *)(strstr)((s), (find)), (strstr)((s), (find)))
+#if __BSD_VISIBLE
+#define	memmem(b, blen, pat, plen)	__qualsel((b),			\
+	(const void *)(memmem)((b), (blen), (pat), (plen)),		\
+	(memmem)((b), (blen), (pat), (plen)))
+#define	memrchr(b, c, n)	__qualsel((b),				\
+	(const void *)(memrchr)((b), (c), (n)), (memrchr)((b), (c), (n)))
+#define	strcasestr(s, find)	__qualsel((s),				\
+	(const char *)(strcasestr)((s), (find)), (strcasestr)((s), (find)))
+#define	strchrnul(s, c)		__qualsel((s),				\
+	(const char *)(strchrnul)((s), (c)), (strchrnul)((s), (c)))
+#define	strnstr(s, find, slen)	__qualsel((s),				\
+	(const char *)(strnstr)((s), (find), (slen)),			\
+	(strnstr)((s), (find), (slen)))
+#endif /* __BSD_VISIBLE */
+#endif
+
 #endif /* _STRING_H_ */
diff --git a/include/wchar.h b/include/wchar.h
index bf07062935d5..1447d083a889 100644
--- a/include/wchar.h
+++ b/include/wchar.h
@@ -246,4 +246,18 @@ size_t	wcslcpy(wchar_t *, const wchar_t *, size_t);
 #endif
 __END_DECLS
 
+#if defined(__qualsel) && !defined(__cplusplus) && \
+    defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
+#define	wcschr(s, c)		__qualsel((s),				\
+	(const wchar_t *)(wcschr)((s), (c)), (wcschr)((s), (c)))
+#define	wcspbrk(s, set)		__qualsel((s),				\
+	(const wchar_t *)(wcspbrk)((s), (set)), (wcspbrk)((s), (set)))
+#define	wcsrchr(s, c)		__qualsel((s),				\
+	(const wchar_t *)(wcsrchr)((s), (c)), (wcsrchr)((s), (c)))
+#define	wcsstr(s, find)		__qualsel((s),				\
+	(const wchar_t *)(wcsstr)((s), (find)), (wcsstr)((s), (find)))
+#define	wmemchr(s, c, n)	__qualsel((s),				\
+	(const wchar_t *)(wmemchr)((s), (c), (n)), (wmemchr)((s), (c), (n)))
+#endif
+
 #endif /* !_WCHAR_H_ */
diff --git a/lib/libc/stdlib/bsearch.3 b/lib/libc/stdlib/bsearch.3
index 712be0f98381..68c0cae5154a 100644
--- a/lib/libc/stdlib/bsearch.3
+++ b/lib/libc/stdlib/bsearch.3
@@ -29,7 +29,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd July 17, 2019
+.Dd June 21, 2026
 .Dt BSEARCH 3
 .Os
 .Sh NAME
@@ -153,4 +153,5 @@ main(void)
 The
 .Fn bsearch
 function conforms to
-.St -isoC .
+.St -isoC-2023 ,
+where it is specified as a qualifier-preserving function.
diff --git a/lib/libc/string/bstring.3 b/lib/libc/string/bstring.3
index dd89af44fc4a..25168404029b 100644
--- a/lib/libc/string/bstring.3
+++ b/lib/libc/string/bstring.3
@@ -27,7 +27,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd December 5, 2023
+.Dd June 21, 2026
 .Dt BSTRING 3
 .Os
 .Sh NAME
@@ -88,7 +88,6 @@ See the specific manual pages for more information.
 .Xr memset 3
 .Sh STANDARDS
 The functions
-.Fn memchr ,
 .Fn memcmp ,
 .Fn memcpy ,
 .Fn memmove ,
@@ -96,6 +95,12 @@ and
 .Fn memset
 conform to
 .St -isoC .
+.Pp
+The
+.Fn memchr
+function conforms to
+.St -isoC-2023 ,
+where it is specified as a qualifier-preserving function.
 .Sh HISTORY
 The functions
 .Fn bzero
diff --git a/lib/libc/string/memchr.3 b/lib/libc/string/memchr.3
index c50e932d3382..da96256e976d 100644
--- a/lib/libc/string/memchr.3
+++ b/lib/libc/string/memchr.3
@@ -29,7 +29,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd April 9, 2008
+.Dd June 21, 2026
 .Dt MEMCHR 3
 .Os
 .Sh NAME
@@ -92,13 +92,18 @@ bytes.
 .Sh STANDARDS
 The
 .Fn memchr
-function
-conforms to
-.St -isoC .
+function conforms to
+.St -isoC-2023 ,
+where it is specified as a qualifier-preserving function.
 .Pp
 The
 .Fn memrchr
 function is a GNU extension and conforms to no standard.
+Like the qualifier-preserving functions in
+.St -isoC-2023 ,
+.Fx implements
+.Fn memrchr
+as qualifier-preserving as well.
 .Sh HISTORY
 The
 .Fn memrchr
diff --git a/lib/libc/string/memmem.3 b/lib/libc/string/memmem.3
index 8e8aa6dafa99..ca236839e755 100644
--- a/lib/libc/string/memmem.3
+++ b/lib/libc/string/memmem.3
@@ -71,6 +71,11 @@ is returned.
 .Fn memmem
 conforms to
 .St -p1003.1-2024 .
+Like the qualifier-preserving functions in
+.St -isoC-2023 ,
+.Fx implements
+.Fn memmem
+as qualifier-preserving as well.
 .Sh HISTORY
 The
 .Fn memmem
diff --git a/lib/libc/string/strchr.3 b/lib/libc/string/strchr.3
index 45179a0001fc..a2f5b32c32c9 100644
--- a/lib/libc/string/strchr.3
+++ b/lib/libc/string/strchr.3
@@ -29,7 +29,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd February 13, 2013
+.Dd June 21, 2026
 .Dt STRCHR 3
 .Os
 .Sh NAME
@@ -109,12 +109,20 @@ The functions
 and
 .Fn strrchr
 conform to
-.St -isoC .
+.St -isoC-2023 ,
+where they are specified as qualifier-preserving functions.
+.Pp
 The function
 .Fn strchrnul
 is a
 .Tn GNU
 extension.
+Like the qualifier-preserving functions in
+.St -isoC-2023 ,
+.Fx
+implements
+.Fn strchrnul
+as qualifier-preserving as well.
 .Sh HISTORY
 The
 .Fn strchrnul
diff --git a/lib/libc/string/string.3 b/lib/libc/string/string.3
index 3ffea6ce0369..c91f6317b5db 100644
--- a/lib/libc/string/string.3
+++ b/lib/libc/string/string.3
@@ -27,7 +27,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd September 2, 2023
+.Dd June 21, 2026
 .Dt STRING 3
 .Os
 .Sh NAME
@@ -136,20 +136,26 @@ for size limitations.
 The
 .Fn strcat ,
 .Fn strncat ,
-.Fn strchr ,
-.Fn strrchr ,
 .Fn strcmp ,
 .Fn strncmp ,
 .Fn strcpy ,
 .Fn strncpy ,
 .Fn strerror ,
 .Fn strlen ,
-.Fn strpbrk ,
 .Fn strspn ,
 .Fn strcspn ,
-.Fn strstr ,
 and
 .Fn strtok
 functions
 conform to
 .St -isoC .
+.Pp
+The
+.Fn strchr ,
+.Fn strrchr ,
+.Fn strpbrk ,
+and
+.Fn strstr
+functions conform to
+.St -isoC-2023 ,
+where they are specified as qualifier-preserving functions.
diff --git a/lib/libc/string/strpbrk.3 b/lib/libc/string/strpbrk.3
index cdccf0da957f..fd63aacfa965 100644
--- a/lib/libc/string/strpbrk.3
+++ b/lib/libc/string/strpbrk.3
@@ -29,7 +29,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd June 4, 1993
+.Dd June 21, 2026
 .Dt STRPBRK 3
 .Os
 .Sh NAME
@@ -69,6 +69,6 @@ returns NULL.
 .Sh STANDARDS
 The
 .Fn strpbrk
-function
-conforms to
-.St -isoC .
+function conforms to
+.St -isoC-2023 ,
+where it is specified as a qualifier-preserving function.
diff --git a/lib/libc/string/strstr.3 b/lib/libc/string/strstr.3
index 8957388db535..e04e882eec6a 100644
--- a/lib/libc/string/strstr.3
+++ b/lib/libc/string/strstr.3
@@ -30,7 +30,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd October 11, 2001
+.Dd June 21, 2026
 .Dt STRSTR 3
 .Os
 .Sh NAME
@@ -147,9 +147,22 @@ ptr = strnstr(largestring, smallstring, 4);
 .Sh STANDARDS
 The
 .Fn strstr
-function
-conforms to
-.St -isoC .
+function conforms to
+.St -isoC-2023 ,
+where it is specified as a qualifier-preserving function.
+.Pp
+The
+.Fn strcasestr
+function is a
+.Tn GNU
+extension, and the
+.Fn strnstr
+function is a
+.Bx
+extension.
+Like the qualifier-preserving functions in
+.St -isoC-2023 ,
+.Fx implements them as qualifier-preserving as well.
 .Sh HISTORY
 The
 .Fn strnstr
diff --git a/lib/libc/string/wmemchr.3 b/lib/libc/string/wmemchr.3
index c1701facb7d5..fddb59a1f49f 100644
--- a/lib/libc/string/wmemchr.3
+++ b/lib/libc/string/wmemchr.3
@@ -154,21 +154,57 @@ counterpart, such as
 .Xr strspn 3 ,
 .Xr strstr 3
 .Sh STANDARDS
-These functions conform to
-.St -isoC-99 ,
-with the exception of
+Functions
+.Fn wmemcmp ,
+.Fn wmemcpy ,
+.Fn wmemmove ,
+.Fn wmemset ,
+.Fn wcscat ,
+.Fn wcscmp ,
+.Fn wcscpy ,
+.Fn wcscspn ,
+.Fn wcslen ,
+.Fn wcsncat ,
+.Fn wcsncmp ,
+.Fn wcsncpy ,
+and
+.Fn wcsspn
+conform to
+.St -isoC-99 .
+.Pp
+Functions
+.Fn wmemchr ,
+.Fn wcschr ,
+.Fn wcspbrk ,
+.Fn wcsrchr ,
+and
+.Fn wcsstr
+conform to
+.St -isoC-2023 ,
+where they are specified as qualifier-preserving functions.
+.Pp
+Functions
 .Fn wcpcpy ,
 .Fn wcpncpy ,
 .Fn wcscasecmp ,
 .Fn wcsdup ,
 .Fn wcsncasecmp ,
 and
-.Fn wcsnlen ,
-which conform to
-.St -p1003.1-2008 ;
+.Fn wcsnlen
+conform to
+.St -p1003.1-2008 ,
+and functions
+.Fn wcslcat
 and
-.Fn wcslcat ,
 .Fn wcslcpy ,
-and
-.Fn wmempcpy ,
-which are extensions.
+first introduced by
+.Ox ,
+conform to
+.St -p1003.1-2024 .
+.Pp
+Function
+.Fn wmempcpy
+is a
+.Tn GNU
+extensions.
+
diff --git a/sys/sys/cdefs.h b/sys/sys/cdefs.h
index d0a34f1bdfc0..22e2888d80af 100644
--- a/sys/sys/cdefs.h
+++ b/sys/sys/cdefs.h
@@ -227,6 +227,27 @@
 	    __typeof(((void)0, (expr))), t), yes, no)
 #endif
 
+/*
+ * __qualsel() is the building block for C23 qualifier-preserving macros
+ * as proposed in N3020: it selects cexpr when the pointer expression p
+ * references a const-qualified object, and expr otherwise.
+ *
+ * The conditional operator's composite-type rule collapses every
+ * pointer-to-const-object type onto the single "const void *"" association,
+ * so callers passing any such pointer are matched even though _Generic()
+ * otherwise compares types exactly.
+ *
+ * The (__uintptr_t) round-trip only suppresses -Wcast-qual on the throwaway
+ * second operand.
+ */
+#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) || \
+    __has_extension(c_generic_selections)
+#define	__qualsel(p, cexpr, expr)					\
+	_Generic(1 ? (p) : (void *)(__uintptr_t)(p),			\
+	    const void *: (cexpr),					\
+	    default: (expr))
+#endif
+
 /*
  * C99 Static array indices in function parameter declarations.  Syntax such as:
  * void bar(int myArray[static 10]);
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.