On 2026-07-29 Bruno Haible wrote: > Lasse Collin wrote: > > The tests should pass once C2y is finished and supported by > > toolchains, but I suppose it's not useful to add them behind "#if > > 0" now. > > Yes. *Now* is too early. In 10-15 years maybe (because we need to > consider also the toolchains of then "old" platforms).
I have a hunch that only GCC < 15 and glibc's headers are problematic, so excluding those might keep "make check" happy everywhere. If it doesn't, then it reveals what other platforms have problems with N3322. I attached a draft patch to demonstrate the idea. It is optimistic and assumes that glibc 2.45 will have updated headers. The tests pass on GNU/Linux (glibc 2.24, 2.41, and 2.43, and musl 1.2.6; a few GCC versions from 4.9 to 16.1, and Clang 22) and on FreeBSD (Clang), OpenBSD (Clang), NetBSD (Clang, GCC), AIX (ibm-clang, GCC), and Solaris (Developer Studio). If this isn't a good idea, then let's go with the shorter patch from the earlier email. > > For some reason glibc's <wchar.h> doesn't have the nonnull > > attribute in the prototypes of these functions. Anyway, I attached > > an updated patch in case it is useful (feel free to edit etc.). > > Thanks! This patch could go in. [...] > So, we can apply this (good) patch only once the paperwork with the > FSF is complete. OK. The instruction say "print, sign, and then email (or fax) a scanned copy", which sounds easy enough. I assume I should use doc/Copyright/request-assign.future. Let's continue this off-list. -- Lasse Collin
>From 4adf8040229a55c54e29de2d5e7350776a039738 Mon Sep 17 00:00:00 2001 From: Lasse Collin <[email protected]> Date: Thu, 30 Jul 2026 21:01:52 +0300 Subject: [PATCH] tests: Verify N3322 compatibility of the function prototypes Test that the compiler doesn't optimize a NULL check away when it sees the prototypes in the headers <string.h>, <wchar.h>, and <stdlib.h>. Exclude GCC and glibc versions that are known to be problematic. (The existing tests explicitly avoided the effects of the attributes in the function prototypes.) * tests/test-bsearch.c: Add the test null_bsearch. * tests/test-memccpy.c: Add the test null_memccpy. * tests/test-memchr.c: Add the test null_memchr. * tests/test-memcmp.c: Add the test null_memcmp. * tests/test-memcpy.c: Add the test null_memcpy. * tests/test-memmove.c: Add the test null_memmove. * tests/test-memset.c: Add the test null_memset. * tests/test-memset_explicit.c: Add the test null_memset_explicit. * tests/test-qsort.c: Add the test null_qsort. * tests/test-strncat.c: Add the test null_strncat. * tests/test-strncmp.c: Add the test null_strncmp. * tests/test-strncpy.c: Add the test null_strncpy. * tests/test-strndup.c: Add the test null_strndup. * tests/test-wcsncat.c: Add the test null_wcsncat. * tests/test-wcsncmp.c: Add the test null_wcsncmp. * tests/test-wcsncpy.c: Add the test null_wcsncpy. * tests/test-wmemchr.c: Add the test null_wmemchr. * tests/test-wmemcmp.c: Add the test null_wmemcmp. * tests/test-wmemcpy.c: Add the test null_wmemcpy. * tests/test-wmemmove.c: Add the test null_wmemmove. * tests/test-wmemset.c: Add the test null_wmemset. --- tests/test-bsearch.c | 17 +++++++++++++++++ tests/test-memccpy.c | 15 +++++++++++++++ tests/test-memchr.c | 17 +++++++++++++++++ tests/test-memcmp.c | 17 +++++++++++++++++ tests/test-memcpy.c | 19 +++++++++++++++++++ tests/test-memmove.c | 17 +++++++++++++++++ tests/test-memset.c | 17 +++++++++++++++++ tests/test-memset_explicit.c | 15 +++++++++++++++ tests/test-qsort.c | 17 +++++++++++++++++ tests/test-strncat.c | 17 +++++++++++++++++ tests/test-strncmp.c | 17 +++++++++++++++++ tests/test-strncpy.c | 17 +++++++++++++++++ tests/test-strndup.c | 17 +++++++++++++++++ tests/test-wcsncat.c | 15 +++++++++++++++ tests/test-wcsncmp.c | 15 +++++++++++++++ tests/test-wcsncpy.c | 15 +++++++++++++++ tests/test-wmemchr.c | 12 ++++++++++++ tests/test-wmemcmp.c | 12 ++++++++++++ tests/test-wmemcpy.c | 12 ++++++++++++ tests/test-wmemmove.c | 12 ++++++++++++ tests/test-wmemset.c | 12 ++++++++++++ 21 files changed, 324 insertions(+) diff --git a/tests/test-bsearch.c b/tests/test-bsearch.c index 6f318256cb..5c773d1410 100644 --- a/tests/test-bsearch.c +++ b/tests/test-bsearch.c @@ -21,6 +21,20 @@ #include "macros.h" +/* Test the prototype in <stdlib.h> + compiler. + In glibc >= 2.18, <bits/stdlib-bsearch.h> has an inline version. + Some glibc versions use the nonnull attribute, which breaks this test. */ +static void * +null_bsearch (void const *key, void const *base, size_t nel, size_t width, + int (*compar) (void const *, void const *)) +{ + void const *p = bsearch (key, base, nel, width, compar); +#if ! defined __GLIBC__ || 2 < __GLIBC__ + (45 <= __GLIBC_MINOR__) + ASSERT (base == NULL); +#endif + return (void *) p; +} + /* Test the library, not the compiler+library. */ static void * lib_bsearch (void const *key, void const *base, size_t nel, size_t width, @@ -48,5 +62,8 @@ main (void) <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>. */ ASSERT (bsearch ("x", NULL, 0, 1, cmp) == NULL); + volatile_bsearch = null_bsearch; + ASSERT (bsearch ("x", NULL, 0, 1, cmp) == NULL); + return test_exit_status; } diff --git a/tests/test-memccpy.c b/tests/test-memccpy.c index 4232e36fb1..966d224708 100644 --- a/tests/test-memccpy.c +++ b/tests/test-memccpy.c @@ -23,6 +23,18 @@ #include "macros.h" +/* Test the prototype in <string.h> + compiler. + Some glibc versions use the nonnull attribute, which breaks this test. */ +static void * +null_memccpy (void *dest, const void *src, int c, size_t n) +{ + void *p = memccpy (dest, src, c, n); +#if ! defined __GLIBC__ || 2 < __GLIBC__ + (45 <= __GLIBC_MINOR__) + ASSERT (dest == NULL); +#endif + return p; +} + /* Test the library, not the compiler+library. */ static void * lib_memccpy (void *dest, void const *src, int c, size_t n) @@ -47,5 +59,8 @@ main (void) ASSERT (memccpy (y, NULL, '?', 0) == NULL); } + volatile_memccpy = null_memccpy; + ASSERT (memccpy (NULL, "x", '?', 0) == NULL); + return test_exit_status; } diff --git a/tests/test-memchr.c b/tests/test-memchr.c index 7d72dbac5b..cd79f67d56 100644 --- a/tests/test-memchr.c +++ b/tests/test-memchr.c @@ -27,6 +27,20 @@ SIGNATURE_CHECK (memchr, void *, (void const *, int, size_t)); #include "zerosize-ptr.h" #include "macros.h" +/* Test the prototype in <string.h> + compiler. + In GCC < 15 this is a builtin that has the nonnull attribute. + Some glibc versions use the nonnull attribute, which breaks this test. */ +static void * +null_memchr (void const *s, int c, size_t n) +{ + const void *p = memchr (s, c, n); +#if (! defined __GNUC__ || __GNUC__ >= 15 || defined __clang__) \ + && (! defined __GLIBC__ || 2 < __GLIBC__ + (45 <= __GLIBC_MINOR__)) + ASSERT (s == NULL); +#endif + return (void *) p; +} + /* Test the library, not the compiler+library. */ static void * lib_memchr (void const *s, int c, size_t n) @@ -138,5 +152,8 @@ main (void) <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>. */ ASSERT (memchr (NULL, '?', 0) == NULL); + volatile_memchr = null_memchr; + ASSERT (memchr (NULL, '?', 0) == NULL); + return test_exit_status; } diff --git a/tests/test-memcmp.c b/tests/test-memcmp.c index d773652214..8f6fc927af 100644 --- a/tests/test-memcmp.c +++ b/tests/test-memcmp.c @@ -25,6 +25,20 @@ SIGNATURE_CHECK (memcmp, int, (void const *, void const *, size_t)); #include "zerosize-ptr.h" #include "macros.h" +/* Test the prototype in <string.h> + compiler. + In GCC < 15 this is a builtin that has the nonnull attribute. + Some glibc versions use the nonnull attribute, which breaks this test. */ +static int +null_memcmp (void const *s1, void const *s2, size_t n) +{ + int r = memcmp (s1, s2, n); +#if (! defined __GNUC__ || __GNUC__ >= 15 || defined __clang__) \ + && (! defined __GLIBC__ || 2 < __GLIBC__ + (45 <= __GLIBC_MINOR__)) + ASSERT (s1 == NULL); +#endif + return r; +} + /* Test the library, not the compiler+library. */ static int lib_memcmp (void const *s1, void const *s2, size_t n) @@ -86,5 +100,8 @@ main (void) ASSERT (memcmp ("x", NULL, 0) == 0); ASSERT (memcmp (NULL, NULL, 0) == 0); + volatile_memcmp = null_memcmp; + ASSERT (memcmp (NULL, "x", 0) == 0); + return test_exit_status; } diff --git a/tests/test-memcpy.c b/tests/test-memcpy.c index 180525fca6..28165a7042 100644 --- a/tests/test-memcpy.c +++ b/tests/test-memcpy.c @@ -23,6 +23,20 @@ #include "macros.h" +/* Test the prototype in <string.h> + compiler. + In GCC < 15 this is a builtin that has the nonnull attribute. + Some glibc versions use the nonnull attribute, which breaks this test. */ +static void * +null_memcpy (void *dest, const void *src, size_t n) +{ + void *p = memcpy (dest, src, n); +#if (! defined __GNUC__ || __GNUC__ >= 15 || defined __clang__) \ + && (! defined __GLIBC__ || 2 < __GLIBC__ + (45 <= __GLIBC_MINOR__)) + ASSERT (dest == NULL); +#endif + return p; +} + /* Test the library, not the compiler+library. */ static void * lib_memcpy (void *s1, void const *s2, size_t n) @@ -47,5 +61,10 @@ main (void) ASSERT (memcpy (y, NULL, 0) == y); } + /* Redirect via the volatile function pointer to ensure that that the ASSERT + in null_memcpy won't be optimized away by GCC 6.3.0. */ + volatile_memcpy = null_memcpy; + ASSERT (memcpy (NULL, "x", 0) == NULL); + return test_exit_status; } diff --git a/tests/test-memmove.c b/tests/test-memmove.c index 438d5aaa83..71c428805e 100644 --- a/tests/test-memmove.c +++ b/tests/test-memmove.c @@ -23,6 +23,20 @@ #include "macros.h" +/* Test the prototype in <string.h> + compiler. + In GCC < 15 this is a builtin that has the nonnull attribute. + Some glibc versions use the nonnull attribute, which breaks this test. */ +static void * +null_memmove (void *dest, const void *src, size_t n) +{ + void * p = memmove (dest, src, n); +#if (! defined __GNUC__ || __GNUC__ >= 15 || defined __clang__) \ + && (! defined __GLIBC__ || 2 < __GLIBC__ + (45 <= __GLIBC_MINOR__)) + ASSERT (dest == NULL); +#endif + return p; +} + /* Test the library, not the compiler+library. */ static void * lib_memmove (void *s1, void const *s2, size_t n) @@ -47,5 +61,8 @@ main (void) ASSERT (memmove (y, NULL, 0) == y); } + volatile_memmove = null_memmove; + ASSERT (memmove (NULL, "x", 0) == NULL); + return test_exit_status; } diff --git a/tests/test-memset.c b/tests/test-memset.c index be744d0dfd..4781aed459 100644 --- a/tests/test-memset.c +++ b/tests/test-memset.c @@ -23,6 +23,20 @@ #include "macros.h" +/* Test the prototype in <string.h> + compiler. + In GCC < 15 this is a builtin that has the nonnull attribute. + Some glibc versions use the nonnull attribute, which breaks this test. */ +static void * +null_memset (void *s, int c, size_t n) +{ + void *p = memset (s, c, n); +#if (! defined __GNUC__ || __GNUC__ >= 15 || defined __clang__) \ + && (! defined __GLIBC__ || 2 < __GLIBC__ + (45 <= __GLIBC_MINOR__)) + ASSERT (s == NULL); +#endif + return p; +} + /* Test the library, not the compiler+library. */ static void * lib_memset (void *s, int c, size_t n) @@ -41,5 +55,8 @@ main (void) <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>. */ ASSERT (memset (NULL, '?', 0) == NULL); + volatile_memset = null_memset; + ASSERT (memset (NULL, '?', 0) == NULL); + return test_exit_status; } diff --git a/tests/test-memset_explicit.c b/tests/test-memset_explicit.c index d02431b4bb..0ecf2a5b3e 100644 --- a/tests/test-memset_explicit.c +++ b/tests/test-memset_explicit.c @@ -48,6 +48,18 @@ static char zero[SECRET_SIZE] = { 0 }; # define memset_explicit memset #endif +/* Test the prototype in <string.h> + compiler. + Some glibc versions use the nonnull attribute, which breaks this test. */ +static void * +null_memset_explicit (void *s, int c, size_t n) +{ + void *p = memset_explicit (s, c, n); +#if ! defined __GLIBC__ || 2 < __GLIBC__ + (45 <= __GLIBC_MINOR__) + ASSERT (s == NULL); +#endif + return p; +} + /* Test the library, not the compiler+library. */ static void * lib_memset_explicit (void *s, int c, size_t n) @@ -268,5 +280,8 @@ main () <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>. */ ASSERT (memset_explicit (NULL, '?', 0) == NULL); + volatile_memset_explicit = null_memset_explicit; + ASSERT (memset_explicit (NULL, '?', 0) == NULL); + return test_exit_status; } diff --git a/tests/test-qsort.c b/tests/test-qsort.c index 43c4909f03..055911552f 100644 --- a/tests/test-qsort.c +++ b/tests/test-qsort.c @@ -19,6 +19,20 @@ /* Specification. */ #include <stdlib.h> +#include "macros.h" + +/* Test the prototype in <stdlib.h> + compiler. + Some glibc versions use the nonnull attribute, which breaks this test. */ +static void +null_qsort (void *base, size_t nel, size_t width, + int (*compar) (void const *, void const *)) +{ + qsort (base, nel, width, compar); +#if ! defined __GLIBC__ || 2 < __GLIBC__ + (45 <= __GLIBC_MINOR__) + ASSERT (base == NULL); +#endif +} + /* Test the library, not the compiler+library. */ static void lib_qsort (void *base, size_t nel, size_t width, @@ -46,5 +60,8 @@ main (void) qsort (NULL, 0, 1, cmp); + volatile_qsort = null_qsort; + qsort (NULL, 0, 1, cmp); + return 0; } diff --git a/tests/test-strncat.c b/tests/test-strncat.c index 1817bb9d10..70567edeec 100644 --- a/tests/test-strncat.c +++ b/tests/test-strncat.c @@ -29,6 +29,20 @@ SIGNATURE_CHECK (strncat, char *, (char *, const char *, size_t)); #include "zerosize-ptr.h" #include "macros.h" +/* Test the prototype in <string.h> + compiler. + In GCC < 15 this is a builtin that has the nonnull attribute. + Some glibc versions use the nonnull attribute, which breaks this test. */ +static char * +null_strncat (char *s1, char const *s2, size_t n) +{ + char *p = strncat (s1, s2, n); +#if (! defined __GNUC__ || __GNUC__ >= 15 || defined __clang__) \ + && (! defined __GLIBC__ || 2 < __GLIBC__ + (45 <= __GLIBC_MINOR__)) + ASSERT (s2 == NULL); +#endif + return p; +} + /* Test the library, not the compiler+library. */ static char * lib_strncat (char *s1, char const *s2, size_t n) @@ -80,6 +94,9 @@ main () { char y[2] = { 'x', '\0' }; ASSERT (strncat (y, NULL, 0) == y); + + volatile_strncat = null_strncat; + ASSERT (strncat (y, NULL, 0) == y); } return test_exit_status; diff --git a/tests/test-strncmp.c b/tests/test-strncmp.c index 6d49af9056..0623a346d8 100644 --- a/tests/test-strncmp.c +++ b/tests/test-strncmp.c @@ -23,6 +23,20 @@ #include "macros.h" +/* Test the prototype in <string.h> + compiler. + In GCC < 15 this is a builtin that has the nonnull attribute. + Some glibc versions use the nonnull attribute, which breaks this test. */ +static int +null_strncmp (char const *s1, char const *s2, size_t n) +{ + int r = strncmp (s1, s2, n); +#if (! defined __GNUC__ || __GNUC__ >= 15 || defined __clang__) \ + && (! defined __GLIBC__ || 2 < __GLIBC__ + (45 <= __GLIBC_MINOR__)) + ASSERT (s1 == NULL); +#endif + return r; +} + /* Test the library, not the compiler+library. */ static int lib_strncmp (char const *s1, char const *s2, size_t n) @@ -43,5 +57,8 @@ main (void) ASSERT (strncmp ("x", NULL, 0) == 0); ASSERT (strncmp (NULL, NULL, 0) == 0); + volatile_strncmp = null_strncmp; + ASSERT (strncmp (NULL, "x", 0) == 0); + return test_exit_status; } diff --git a/tests/test-strncpy.c b/tests/test-strncpy.c index 83535a4bee..1d896f6561 100644 --- a/tests/test-strncpy.c +++ b/tests/test-strncpy.c @@ -25,6 +25,20 @@ #include "zerosize-ptr.h" #include "macros.h" +/* Test the prototype in <string.h> + compiler. + In GCC < 15 this is a builtin that has the nonnull attribute. + Some glibc versions use the nonnull attribute, which breaks this test. */ +static char * +null_strncpy (char *s1, char const *s2, size_t n) +{ + char *p = strncpy (s1, s2, n); +#if (! defined __GNUC__ || __GNUC__ >= 15 || defined __clang__) \ + && (! defined __GLIBC__ || 2 < __GLIBC__ + (45 <= __GLIBC_MINOR__)) + ASSERT (s2 == NULL); +#endif + return p; +} + /* Test the library, not the compiler+library. */ static char * lib_strncpy (char *s1, char const *s2, size_t n) @@ -116,6 +130,9 @@ main (void) { char y[1]; ASSERT (strncpy (y, NULL, 0) == y); + + volatile_strncpy = null_strncpy; + ASSERT (strncpy (y, NULL, 0) == y); } return test_exit_status; diff --git a/tests/test-strndup.c b/tests/test-strndup.c index 10ad604f24..6e0002c690 100644 --- a/tests/test-strndup.c +++ b/tests/test-strndup.c @@ -23,6 +23,20 @@ #include "macros.h" +/* Test the prototype in <string.h> + compiler. + In GCC < 15 this is a builtin that has the nonnull attribute. + Some glibc versions use the nonnull attribute, which breaks this test. */ +static char * +null_strndup (char const *s, size_t size) +{ + char *p = strndup (s, size); +#if (! defined __GNUC__ || __GNUC__ >= 15 || defined __clang__) \ + && (! defined __GLIBC__ || 2 < __GLIBC__ + (45 <= __GLIBC_MINOR__)) + ASSERT (s == NULL); +#endif + return p; +} + /* Test the library, not the compiler+library. */ static char * lib_strndup (char const *s, size_t size) @@ -41,5 +55,8 @@ main (void) <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>. */ ASSERT (strndup (NULL, 0) != NULL); + volatile_strndup = null_strndup; + ASSERT (strndup (NULL, 0) != NULL); + return test_exit_status; } diff --git a/tests/test-wcsncat.c b/tests/test-wcsncat.c index 3aaa68a24f..ec34c17e88 100644 --- a/tests/test-wcsncat.c +++ b/tests/test-wcsncat.c @@ -25,6 +25,18 @@ #include "macros.h" +/* Test the prototype in <wchar.h> + compiler. + Some glibc versions use the nonnull attribute, which breaks this test. */ +static wchar_t * +null_wcsncat (wchar_t *ws1, wchar_t const *ws2, size_t n) +{ + wchar_t *p = wcsncat (ws1, ws2, n); +#if ! defined __GLIBC__ || 2 < __GLIBC__ + (45 <= __GLIBC_MINOR__) + ASSERT (ws2 == NULL); +#endif + return p; +} + /* Test the library, not the compiler+library. */ static wchar_t * lib_wcsncat (wchar_t *ws1, wchar_t const *ws2, size_t n) @@ -50,6 +62,9 @@ main () { wchar_t y[2] = { L'x', 0 }; ASSERT (wcsncat (y, NULL, 0) == y); + + volatile_wcsncat = null_wcsncat; + ASSERT (wcsncat (y, NULL, 0) == y); } return test_exit_status; diff --git a/tests/test-wcsncmp.c b/tests/test-wcsncmp.c index c43ce8273c..a5a099f9bc 100644 --- a/tests/test-wcsncmp.c +++ b/tests/test-wcsncmp.c @@ -25,6 +25,18 @@ SIGNATURE_CHECK (wcsncmp, int, (const wchar_t *, const wchar_t *, size_t)); #include "macros.h" +/* Test the prototype in <wchar.h> + compiler. + Some glibc versions use the nonnull attribute, which breaks this test. */ +static int +null_wcsncmp (wchar_t const *ws1, wchar_t const *ws2, size_t n) +{ + int r = wcsncmp (ws1, ws2, n); +#if ! defined __GLIBC__ || 2 < __GLIBC__ + (45 <= __GLIBC_MINOR__) + ASSERT (ws1 == NULL); +#endif + return r; +} + /* Test the library, not the compiler+library. */ static int lib_wcsncmp (wchar_t const *ws1, wchar_t const *ws2, size_t n) @@ -196,5 +208,8 @@ main (int argc, char *argv[]) ASSERT (wcsncmp (L"x", NULL, 0) == 0); ASSERT (wcsncmp (NULL, NULL, 0) == 0); + volatile_wcsncmp = null_wcsncmp; + ASSERT (wcsncmp (NULL, L"x", 0) == 0); + return test_exit_status; } diff --git a/tests/test-wcsncpy.c b/tests/test-wcsncpy.c index 321fabd6ef..02bb08b2da 100644 --- a/tests/test-wcsncpy.c +++ b/tests/test-wcsncpy.c @@ -23,6 +23,18 @@ #include "macros.h" +/* Test the prototype in <wchar.h> + compiler. + Some glibc versions use the nonnull attribute, which breaks this test. */ +static wchar_t * +null_wcsncpy (wchar_t *ws1, wchar_t const *ws2, size_t n) +{ + wchar_t *p = wcsncpy (ws1, ws2, n); +#if ! defined __GLIBC__ || 2 < __GLIBC__ + (45 <= __GLIBC_MINOR__) + ASSERT (ws2 == NULL); +#endif + return p; +} + /* Test the library, not the compiler+library. */ static wchar_t * lib_wcsncpy (wchar_t *ws1, wchar_t const *ws2, size_t n) @@ -46,6 +58,9 @@ main (void) { wchar_t y[1]; ASSERT (wcsncpy (y, NULL, 0) == y); + + volatile_wcsncpy = null_wcsncpy; + ASSERT (wcsncpy (y, NULL, 0) == y); } return test_exit_status; diff --git a/tests/test-wmemchr.c b/tests/test-wmemchr.c index 877f519aa8..04858ba93e 100644 --- a/tests/test-wmemchr.c +++ b/tests/test-wmemchr.c @@ -23,6 +23,15 @@ #include "macros.h" +/* Test the prototype in <wchar.h> + compiler. */ +static wchar_t * +null_wmemchr (wchar_t const *s, wchar_t wc, size_t n) +{ + wchar_t const *p = wmemchr (s, wc, n); + ASSERT (s == NULL); + return (wchar_t *) p; +} + /* Test the library, not the compiler+library. */ static wchar_t * lib_wmemchr (wchar_t const *s, wchar_t wc, size_t n) @@ -41,5 +50,8 @@ main (void) <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>. */ ASSERT (wmemchr (NULL, L'?', 0) == NULL); + volatile_wmemchr = null_wmemchr; + ASSERT (wmemchr (NULL, L'?', 0) == NULL); + return test_exit_status; } diff --git a/tests/test-wmemcmp.c b/tests/test-wmemcmp.c index 6b7564659d..8d68196074 100644 --- a/tests/test-wmemcmp.c +++ b/tests/test-wmemcmp.c @@ -25,6 +25,15 @@ SIGNATURE_CHECK (wmemcmp, int, (const wchar_t *, const wchar_t *, size_t)); #include "macros.h" +/* Test the prototype in <wchar.h> + compiler. */ +static int +null_wmemcmp (wchar_t const *ws1, wchar_t const *ws2, size_t n) +{ + int r = wmemcmp (ws1, ws2, n); + ASSERT (ws1 == NULL); + return r; +} + /* Test the library, not the compiler+library. */ static int lib_wmemcmp (wchar_t const *ws1, wchar_t const *ws2, size_t n) @@ -108,5 +117,8 @@ main (int argc, char *argv[]) ASSERT (wmemcmp (L"x", NULL, 0) == 0); ASSERT (wmemcmp (NULL, NULL, 0) == 0); + volatile_wmemcmp = null_wmemcmp; + ASSERT (wmemcmp (NULL, L"x", 0) == 0); + return test_exit_status; } diff --git a/tests/test-wmemcpy.c b/tests/test-wmemcpy.c index f5bb779ce8..296a0cae1e 100644 --- a/tests/test-wmemcpy.c +++ b/tests/test-wmemcpy.c @@ -23,6 +23,15 @@ #include "macros.h" +/* Test the prototype in <wchar.h> + compiler. */ +static wchar_t * +null_wmemcpy (wchar_t *s1, wchar_t const *s2, size_t n) +{ + wchar_t *p = wmemcpy (s1, s2, n); + ASSERT (s1 == NULL); + return p; +} + /* Test the library, not the compiler+library. */ static wchar_t * lib_wmemcpy (wchar_t *s1, wchar_t const *s2, size_t n) @@ -48,5 +57,8 @@ main (void) ASSERT (wmemcpy (y, NULL, 0) == y); } + volatile_wmemcpy = null_wmemcpy; + ASSERT (wmemcpy (NULL, L"x", 0) == NULL); + return test_exit_status; } diff --git a/tests/test-wmemmove.c b/tests/test-wmemmove.c index 4e0401c37f..3737d62d98 100644 --- a/tests/test-wmemmove.c +++ b/tests/test-wmemmove.c @@ -23,6 +23,15 @@ #include "macros.h" +/* Test the prototype in <wchar.h> + compiler. */ +static wchar_t * +null_wmemmove (wchar_t *s1, wchar_t const *s2, size_t n) +{ + wchar_t *p = wmemmove (s1, s2, n); + ASSERT (s1 == NULL); + return p; +} + /* Test the library, not the compiler+library. */ static wchar_t * lib_wmemmove (wchar_t *s1, wchar_t const *s2, size_t n) @@ -48,5 +57,8 @@ main (void) ASSERT (wmemmove (y, NULL, 0) == y); } + volatile_wmemmove = null_wmemmove; + ASSERT (wmemmove (NULL, L"x", 0) == NULL); + return test_exit_status; } diff --git a/tests/test-wmemset.c b/tests/test-wmemset.c index a7fb360932..9d45f4c5a6 100644 --- a/tests/test-wmemset.c +++ b/tests/test-wmemset.c @@ -23,6 +23,15 @@ #include "macros.h" +/* Test the prototype in <wchar.h> + compiler. */ +static wchar_t * +null_wmemset (wchar_t *ws, wchar_t wc, size_t n) +{ + wchar_t *p = wmemset (ws, wc, n); + ASSERT (ws == NULL); + return p; +} + /* Test the library, not the compiler+library. */ static wchar_t * lib_wmemset (wchar_t *ws, wchar_t wc, size_t n) @@ -41,5 +50,8 @@ main (void) <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>. */ ASSERT (wmemset (NULL, L'?', 0) == NULL); + volatile_wmemset = null_wmemset; + ASSERT (wmemset (NULL, L'?', 0) == NULL); + return test_exit_status; } -- 2.55.0
