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
This commit is contained in:
Faraz Vahedi committed 2026-08-13 20:08:49 +03:30
1 parent 4a8bf4de7b
commit d08296c7ab
13 files changed
+187 -33

No files matched your search

+12
View File
@@ -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_ */
+28
View File
@@ -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_ */
+14
View File
@@ -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_ */