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]);