On 2026-08-17 Bruno Haible wrote:
> Since I now have a clang 22 + UBSAN + ASAN pass in my CI, there is
> need to silence these failures. Previously I had used gnulib-tool
> options --avoid=memchr-tests --avoid=memcmp-tests ...
> but this is no longer practical.

Sorry, I should have placed the #ifs like that since the beginning.

I attached patches. The first one the removes the now-redundant #ifs and
moves the comments to the main function. The second patch updates the
mingw-w64 workaround in test-wmemcpy.c and test-wmemmove.c to avoid
undefined behavior completely.

-- 
Lasse Collin
From 3bb855134d23a6950ac543c2dbe7fd774665d31a Mon Sep 17 00:00:00 2001
From: Lasse Collin <[email protected]>
Date: Tue, 18 Aug 2026 18:10:25 +0300
Subject: [PATCH 1/2] tests: Remove redundant #ifs from N3322 tests

* tests/test-bsearch.c (null_bsearch, main): Remove the #if from
null_bsearch because having the same condition in main is enough.
Move the comment explaining the #if from null_bsearch to main.
* tests/test-memccpy.c (null_memccpy, main): Likewise.
* tests/test-memchr.c (null_memchr, main): Likewise.
* tests/test-memcmp.c (null_memcmp, main): Likewise.
* tests/test-memcpy.c (null_memcpy, main): Likewise.
* tests/test-memmove.c (null_memmove, main): Likewise.
* tests/test-memset.c (null_memset, main): Likewise.
* tests/test-memset_explicit.c (null_memset_explicit, main): Likewise.
* tests/test-qsort.c (null_qsort, main): Likewise.
* tests/test-strncat.c (null_strncat, main): Likewise.
* tests/test-strncmp.c (null_strncmp, main): Likewise.
* tests/test-strncpy.c (null_strncpy, main): Likewise.
* tests/test-strndup.c (null_strndup, main): Likewise.
* tests/test-wcsncat.c (null_wcsncat, main): Likewise.
* tests/test-wcsncmp.c (null_wcsncmp, main): Likewise.
* tests/test-wcsncpy.c (null_wcsncpy, main): Likewise.
---
 ChangeLog                    | 22 ++++++++++++++++++++++
 tests/test-bsearch.c         | 10 ++++------
 tests/test-memccpy.c         |  8 +++-----
 tests/test-memchr.c          | 11 ++++-------
 tests/test-memcmp.c          | 11 ++++-------
 tests/test-memcpy.c          | 11 ++++-------
 tests/test-memmove.c         | 11 ++++-------
 tests/test-memset.c          | 11 ++++-------
 tests/test-memset_explicit.c |  8 +++-----
 tests/test-qsort.c           |  8 +++-----
 tests/test-strncat.c         | 11 ++++-------
 tests/test-strncmp.c         | 11 ++++-------
 tests/test-strncpy.c         | 11 ++++-------
 tests/test-strndup.c         | 11 ++++-------
 tests/test-wcsncat.c         |  8 +++-----
 tests/test-wcsncmp.c         |  8 +++-----
 tests/test-wcsncpy.c         |  8 +++-----
 17 files changed, 80 insertions(+), 99 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 30ad4d78e8..83e0fedaa4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+2026-08-18  Lasse Collin  <[email protected]>
+
+	tests: Remove redundant #ifs from N3322 tests.
+	* tests/test-bsearch.c (null_bsearch, main): Remove the #if from
+	null_bsearch because having the same condition in main is enough.
+	Move the comment explaining the #if from null_bsearch to main.
+	* tests/test-memccpy.c (null_memccpy, main): Likewise.
+	* tests/test-memchr.c (null_memchr, main): Likewise.
+	* tests/test-memcmp.c (null_memcmp, main): Likewise.
+	* tests/test-memcpy.c (null_memcpy, main): Likewise.
+	* tests/test-memmove.c (null_memmove, main): Likewise.
+	* tests/test-memset.c (null_memset, main): Likewise.
+	* tests/test-memset_explicit.c (null_memset_explicit, main): Likewise.
+	* tests/test-qsort.c (null_qsort, main): Likewise.
+	* tests/test-strncat.c (null_strncat, main): Likewise.
+	* tests/test-strncmp.c (null_strncmp, main): Likewise.
+	* tests/test-strncpy.c (null_strncpy, main): Likewise.
+	* tests/test-strndup.c (null_strndup, main): Likewise.
+	* tests/test-wcsncat.c (null_wcsncat, main): Likewise.
+	* tests/test-wcsncmp.c (null_wcsncmp, main): Likewise.
+	* tests/test-wcsncpy.c (null_wcsncpy, main): Likewise.
+
 2026-08-18  Paul Eggert  <[email protected]>
 
 	exclude: new function excluded_file_name_status
diff --git a/tests/test-bsearch.c b/tests/test-bsearch.c
index 60cd0ff08c..3aeee9a558 100644
--- a/tests/test-bsearch.c
+++ b/tests/test-bsearch.c
@@ -21,17 +21,13 @@
 
 #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.  */
+/* Test the prototype in <stdlib.h> + compiler.  */
 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__ + (99 <= __GLIBC_MINOR__)
   ASSERT (base == NULL);
-#endif
   return (void *) p;
 }
 static void *(*volatile volatile_null_bsearch) (void const *, void const *,
@@ -63,7 +59,9 @@ int
 main (void)
 {
   /* Test zero-length operations on NULL pointers, allowed by
-     <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.  */
+     <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.
+     In glibc >= 2.18, <bits/stdlib-bsearch.h> has an inline version.
+     Some glibc versions use the nonnull attribute, which breaks this test.  */
 #if ! defined __GLIBC__ || 2 < __GLIBC__ + (99 <= __GLIBC_MINOR__)
   ASSERT (bsearch ("x", NULL, 0, 1, cmp) == NULL);
 
diff --git a/tests/test-memccpy.c b/tests/test-memccpy.c
index c942e18675..35a7c0488d 100644
--- a/tests/test-memccpy.c
+++ b/tests/test-memccpy.c
@@ -23,15 +23,12 @@
 
 #include "macros.h"
 
-/* Test the prototype in <string.h> + compiler.
-   Some glibc versions use the nonnull attribute, which breaks this test.  */
+/* Test the prototype in <string.h> + compiler.  */
 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__ + (99 <= __GLIBC_MINOR__)
   ASSERT (dest == NULL);
-#endif
   return p;
 }
 static void *(*volatile volatile_null_memccpy) (void *, void const *, int,
@@ -54,7 +51,8 @@ int
 main (void)
 {
   /* Test zero-length operations on NULL pointers, allowed by
-     <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.  */
+     <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.
+     Some glibc versions use the nonnull attribute, which breaks this test.  */
 
 #if ! defined __GLIBC__ || 2 < __GLIBC__ + (99 <= __GLIBC_MINOR__)
   ASSERT (memccpy (NULL, "x", '?', 0) == NULL);
diff --git a/tests/test-memchr.c b/tests/test-memchr.c
index ea662ca2f2..4ed0e10383 100644
--- a/tests/test-memchr.c
+++ b/tests/test-memchr.c
@@ -27,17 +27,12 @@ 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.  */
+/* Test the prototype in <string.h> + compiler.  */
 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__ + (99 <= __GLIBC_MINOR__))
   ASSERT (s == NULL);
-#endif
   return (void *) p;
 }
 static void *(*volatile volatile_null_memchr) (void const *, int, size_t)
@@ -151,7 +146,9 @@ main (void)
   }
 
   /* Test zero-length operations on NULL pointers, allowed by
-     <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.  */
+     <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.
+     In GCC < 15 this is a builtin that has the nonnull attribute.
+     Some glibc versions use the nonnull attribute, which breaks this test.  */
 #if (! defined __GNUC__ || __GNUC__ >= 15 || defined __clang__) \
     && (! defined __GLIBC__ || 2 < __GLIBC__ + (99 <= __GLIBC_MINOR__))
   ASSERT (memchr (NULL, '?', 0) == NULL);
diff --git a/tests/test-memcmp.c b/tests/test-memcmp.c
index 601f46859f..30822b8e62 100644
--- a/tests/test-memcmp.c
+++ b/tests/test-memcmp.c
@@ -25,17 +25,12 @@ 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.  */
+/* Test the prototype in <string.h> + compiler.  */
 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__ + (99 <= __GLIBC_MINOR__))
   ASSERT (s1 == NULL);
-#endif
   return r;
 }
 int (*volatile volatile_null_memcmp) (void const *, void const *, size_t)
@@ -97,7 +92,9 @@ main (void)
   }
 
   /* Test zero-length operations on NULL pointers, allowed by
-     <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.  */
+     <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.
+     In GCC < 15 this is a builtin that has the nonnull attribute.
+     Some glibc versions use the nonnull attribute, which breaks this test.  */
 #if (! defined __GNUC__ || __GNUC__ >= 15 || defined __clang__) \
     && (! defined __GLIBC__ || 2 < __GLIBC__ + (99 <= __GLIBC_MINOR__))
   ASSERT (memcmp (NULL, "x", 0) == 0);
diff --git a/tests/test-memcpy.c b/tests/test-memcpy.c
index 8836e9680a..b6bd045625 100644
--- a/tests/test-memcpy.c
+++ b/tests/test-memcpy.c
@@ -23,17 +23,12 @@
 
 #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.  */
+/* Test the prototype in <string.h> + compiler.  */
 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__ + (99 <= __GLIBC_MINOR__))
   ASSERT (dest == NULL);
-#endif
   return p;
 }
 void *(*volatile volatile_null_memcpy) (void *, void const *, size_t)
@@ -54,7 +49,9 @@ int
 main (void)
 {
   /* Test zero-length operations on NULL pointers, allowed by
-     <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.  */
+     <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.
+     In GCC < 15 this is a builtin that has the nonnull attribute.
+     Some glibc versions use the nonnull attribute, which breaks this test.  */
 
 #if (! defined __GNUC__ || __GNUC__ >= 15 || defined __clang__) \
     && (! defined __GLIBC__ || 2 < __GLIBC__ + (99 <= __GLIBC_MINOR__))
diff --git a/tests/test-memmove.c b/tests/test-memmove.c
index 6b433ce7f0..6282d73158 100644
--- a/tests/test-memmove.c
+++ b/tests/test-memmove.c
@@ -23,17 +23,12 @@
 
 #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.  */
+/* Test the prototype in <string.h> + compiler.  */
 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__ + (99 <= __GLIBC_MINOR__))
   ASSERT (dest == NULL);
-#endif
   return p;
 }
 static void *(*volatile volatile_null_memmove) (void *, void const *, size_t)
@@ -54,7 +49,9 @@ int
 main (void)
 {
   /* Test zero-length operations on NULL pointers, allowed by
-     <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.  */
+     <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.
+     In GCC < 15 this is a builtin that has the nonnull attribute.
+     Some glibc versions use the nonnull attribute, which breaks this test.  */
 
 #if (! defined __GNUC__ || __GNUC__ >= 15 || defined __clang__) \
     && (! defined __GLIBC__ || 2 < __GLIBC__ + (99 <= __GLIBC_MINOR__))
diff --git a/tests/test-memset.c b/tests/test-memset.c
index 39dd047b65..cb35c3a1fd 100644
--- a/tests/test-memset.c
+++ b/tests/test-memset.c
@@ -23,17 +23,12 @@
 
 #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.  */
+/* Test the prototype in <string.h> + compiler.  */
 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__ + (99 <= __GLIBC_MINOR__))
   ASSERT (s == NULL);
-#endif
   return p;
 }
 static void *(*volatile volatile_null_memset) (void *, int, size_t)
@@ -54,7 +49,9 @@ int
 main (void)
 {
   /* Test zero-length operations on NULL pointers, allowed by
-     <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.  */
+     <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.
+     In GCC < 15 this is a builtin that has the nonnull attribute.
+     Some glibc versions use the nonnull attribute, which breaks this test.  */
 #if (! defined __GNUC__ || __GNUC__ >= 15 || defined __clang__) \
     && (! defined __GLIBC__ || 2 < __GLIBC__ + (99 <= __GLIBC_MINOR__))
   ASSERT (memset (NULL, '?', 0) == NULL);
diff --git a/tests/test-memset_explicit.c b/tests/test-memset_explicit.c
index e2ab32097f..488f07beea 100644
--- a/tests/test-memset_explicit.c
+++ b/tests/test-memset_explicit.c
@@ -48,15 +48,12 @@ 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.  */
+/* Test the prototype in <string.h> + compiler.  */
 static void *
 null_memset_explicit (void *s, int c, size_t n)
 {
   void *p = memset_explicit (s, c, n);
-#if ! defined __GLIBC__ || 2 < __GLIBC__ + (99 <= __GLIBC_MINOR__)
   ASSERT (s == NULL);
-#endif
   return p;
 }
 static void *(*volatile volatile_null_memset_explicit) (void *, int, size_t)
@@ -279,7 +276,8 @@ main ()
   test_stack ();
 
   /* Test zero-length operations on NULL pointers, allowed by
-     <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.  */
+     <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.
+     Some glibc versions use the nonnull attribute, which breaks this test.  */
 #if ! defined __GLIBC__ || 2 < __GLIBC__ + (99 <= __GLIBC_MINOR__)
   ASSERT (memset_explicit (NULL, '?', 0) == NULL);
 
diff --git a/tests/test-qsort.c b/tests/test-qsort.c
index 8904882ac1..382dfe99f7 100644
--- a/tests/test-qsort.c
+++ b/tests/test-qsort.c
@@ -21,16 +21,13 @@
 
 #include "macros.h"
 
-/* Test the prototype in <stdlib.h> + compiler.
-   Some glibc versions use the nonnull attribute, which breaks this test.  */
+/* Test the prototype in <stdlib.h> + compiler.  */
 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__ + (99 <= __GLIBC_MINOR__)
   ASSERT (base == NULL);
-#endif
 }
 static void (*volatile volatile_null_qsort) (void *, size_t, size_t,
                                              int (*) (void const *, void const *))
@@ -59,7 +56,8 @@ int
 main (void)
 {
   /* Test zero-length operations on NULL pointers, allowed by
-     <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.  */
+     <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.
+     Some glibc versions use the nonnull attribute, which breaks this test.  */
 
 #if ! defined __GLIBC__ || 2 < __GLIBC__ + (99 <= __GLIBC_MINOR__)
   qsort (NULL, 0, 1, cmp);
diff --git a/tests/test-strncat.c b/tests/test-strncat.c
index 162b3d4e42..a74e882a4e 100644
--- a/tests/test-strncat.c
+++ b/tests/test-strncat.c
@@ -29,17 +29,12 @@ 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.  */
+/* Test the prototype in <string.h> + compiler.  */
 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__ + (99 <= __GLIBC_MINOR__))
   ASSERT (s2 == NULL);
-#endif
   return p;
 }
 static char *(*volatile volatile_null_strncat) (char *, char const *, size_t)
@@ -87,7 +82,9 @@ main ()
   }
 
   /* Test zero-length operations on NULL pointers, allowed by
-     <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.  */
+     <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.
+     In GCC < 15 this is a builtin that has the nonnull attribute.
+     Some glibc versions use the nonnull attribute, which breaks this test.  */
 
 #if (! defined __GNUC__ || __GNUC__ >= 15 || defined __clang__) \
     && (! defined __GLIBC__ || 2 < __GLIBC__ + (99 <= __GLIBC_MINOR__))
diff --git a/tests/test-strncmp.c b/tests/test-strncmp.c
index cbc2327861..83526a4a3a 100644
--- a/tests/test-strncmp.c
+++ b/tests/test-strncmp.c
@@ -23,17 +23,12 @@
 
 #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.  */
+/* Test the prototype in <string.h> + compiler.  */
 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__ + (99 <= __GLIBC_MINOR__))
   ASSERT (s1 == NULL);
-#endif
   return r;
 }
 static int (*volatile volatile_null_strncmp) (char const *, char const *,
@@ -56,7 +51,9 @@ int
 main (void)
 {
   /* Test zero-length operations on NULL pointers, allowed by
-     <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.  */
+     <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.
+     In GCC < 15 this is a builtin that has the nonnull attribute.
+     Some glibc versions use the nonnull attribute, which breaks this test.  */
 #if (! defined __GNUC__ || __GNUC__ >= 15 || defined __clang__) \
     && (! defined __GLIBC__ || 2 < __GLIBC__ + (99 <= __GLIBC_MINOR__))
   ASSERT (strncmp (NULL, "x", 0) == 0);
diff --git a/tests/test-strncpy.c b/tests/test-strncpy.c
index 2bbbecd991..03f5e245ab 100644
--- a/tests/test-strncpy.c
+++ b/tests/test-strncpy.c
@@ -25,17 +25,12 @@
 #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.  */
+/* Test the prototype in <string.h> + compiler.  */
 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__ + (99 <= __GLIBC_MINOR__))
   ASSERT (s2 == NULL);
-#endif
   return p;
 }
 static char *(*volatile volatile_null_strncpy) (char *, char const *, size_t)
@@ -125,7 +120,9 @@ main (void)
   }
 
   /* Test zero-length operations on NULL pointers, allowed by
-     <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.  */
+     <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.
+     In GCC < 15 this is a builtin that has the nonnull attribute.
+     Some glibc versions use the nonnull attribute, which breaks this test.  */
 
 #if (! defined __GNUC__ || __GNUC__ >= 15 || defined __clang__) \
     && (! defined __GLIBC__ || 2 < __GLIBC__ + (99 <= __GLIBC_MINOR__))
diff --git a/tests/test-strndup.c b/tests/test-strndup.c
index b7f9db05c5..36f93e85e8 100644
--- a/tests/test-strndup.c
+++ b/tests/test-strndup.c
@@ -23,17 +23,12 @@
 
 #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.  */
+/* Test the prototype in <string.h> + compiler.  */
 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__ + (99 <= __GLIBC_MINOR__))
   ASSERT (s == NULL);
-#endif
   return p;
 }
 static char *(*volatile volatile_null_strndup) (char const *, size_t)
@@ -54,7 +49,9 @@ int
 main (void)
 {
   /* Test zero-length operations on NULL pointers, allowed by
-     <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.  */
+     <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.
+     In GCC < 15 this is a builtin that has the nonnull attribute.
+     Some glibc versions use the nonnull attribute, which breaks this test.  */
 #if (! defined __GNUC__ || __GNUC__ >= 15 || defined __clang__) \
     && (! defined __GLIBC__ || 2 < __GLIBC__ + (99 <= __GLIBC_MINOR__))
   ASSERT (strndup (NULL, 0) != NULL);
diff --git a/tests/test-wcsncat.c b/tests/test-wcsncat.c
index bf5cc48ae8..40a502d347 100644
--- a/tests/test-wcsncat.c
+++ b/tests/test-wcsncat.c
@@ -25,15 +25,12 @@
 
 #include "macros.h"
 
-/* Test the prototype in <wchar.h> + compiler.
-   Some glibc versions use the nonnull attribute, which breaks this test.  */
+/* Test the prototype in <wchar.h> + compiler.  */
 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__ + (99 <= __GLIBC_MINOR__)
   ASSERT (ws2 == NULL);
-#endif
   return p;
 }
 static wchar_t *(*volatile volatile_null_wcsncat) (wchar_t *, wchar_t const *,
@@ -56,7 +53,8 @@ int
 main ()
 {
   /* Test zero-length operations on NULL pointers, allowed by
-     <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.  */
+     <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.
+     Some glibc versions use the nonnull attribute, which breaks this test.  */
 
 #if ! defined __GLIBC__ || 2 < __GLIBC__ + (99 <= __GLIBC_MINOR__)
 # if 0 /* I think this is invalid, per ISO C 23 § 7.31.4.3.2.  */
diff --git a/tests/test-wcsncmp.c b/tests/test-wcsncmp.c
index 16990772ad..bb9dcd1a99 100644
--- a/tests/test-wcsncmp.c
+++ b/tests/test-wcsncmp.c
@@ -25,15 +25,12 @@ 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.  */
+/* Test the prototype in <wchar.h> + compiler.  */
 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__ + (99 <= __GLIBC_MINOR__)
   ASSERT (ws1 == NULL);
-#endif
   return r;
 }
 static int (*volatile volatile_null_wcsncmp) (wchar_t const *,
@@ -206,7 +203,8 @@ main (int argc, char *argv[])
   }
 
   /* Test zero-length operations on NULL pointers, allowed by
-     <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.  */
+     <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.
+     Some glibc versions use the nonnull attribute, which breaks this test.  */
 #if ! defined __GLIBC__ || 2 < __GLIBC__ + (99 <= __GLIBC_MINOR__)
   ASSERT (wcsncmp (NULL, L"x", 0) == 0);
   ASSERT (wcsncmp (L"x", NULL, 0) == 0);
diff --git a/tests/test-wcsncpy.c b/tests/test-wcsncpy.c
index a2e8622ca8..169ce787cf 100644
--- a/tests/test-wcsncpy.c
+++ b/tests/test-wcsncpy.c
@@ -23,15 +23,12 @@
 
 #include "macros.h"
 
-/* Test the prototype in <wchar.h> + compiler.
-   Some glibc versions use the nonnull attribute, which breaks this test.  */
+/* Test the prototype in <wchar.h> + compiler.  */
 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__ + (99 <= __GLIBC_MINOR__)
   ASSERT (ws2 == NULL);
-#endif
   return p;
 }
 static wchar_t *(*volatile volatile_null_wcsncpy) (wchar_t *, wchar_t const *,
@@ -54,7 +51,8 @@ int
 main (void)
 {
   /* Test zero-length operations on NULL pointers, allowed by
-     <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.  */
+     <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.
+     Some glibc versions use the nonnull attribute, which breaks this test.  */
 
 #if ! defined __GLIBC__ || 2 < __GLIBC__ + (99 <= __GLIBC_MINOR__)
   ASSERT (wcsncpy (NULL, L"x", 0) == NULL);
-- 
2.55.0

>From 3d955c41ef0a0787a77ee0eb2ae83845c5f4d322 Mon Sep 17 00:00:00 2001
From: Lasse Collin <[email protected]>
Date: Tue, 18 Aug 2026 18:10:25 +0300
Subject: [PATCH 2/2] tests: Avoid undefined behavior on mingw-w64

* tests/test-wmemcpy.c (null_wmemcpy, main): Move the #if and comment
from null_wmemcpy to main to avoid invoking undefined behavior.
* tests/test-wmemmove.c (null_wmemmove, main): Likewise.
---
 ChangeLog             |  7 +++++++
 tests/test-wmemcpy.c  | 14 +++++++-------
 tests/test-wmemmove.c | 14 +++++++-------
 3 files changed, 21 insertions(+), 14 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 83e0fedaa4..920834ca9b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2026-08-18  Lasse Collin  <[email protected]>
+
+	tests: Avoid undefined behavior on mingw-w64.
+	* tests/test-wmemcpy.c (null_wmemcpy, main): Move the #if and comment
+	from null_wmemcpy to main to avoid invoking undefined behavior.
+	* tests/test-wmemmove.c (null_wmemmove, main): Likewise.
+
 2026-08-18  Lasse Collin  <[email protected]>
 
 	tests: Remove redundant #ifs from N3322 tests.
diff --git a/tests/test-wmemcpy.c b/tests/test-wmemcpy.c
index 8a0b31db68..e1a8a751d8 100644
--- a/tests/test-wmemcpy.c
+++ b/tests/test-wmemcpy.c
@@ -23,17 +23,12 @@
 
 #include "macros.h"
 
-/* Test the prototype in <wchar.h> + compiler.
-   In mingw-w64 14.0.0, wmemcpy is an inline function that calls memcpy.
-   In GCC < 15, memcpy is a builtin that has the nonnull attribute.  */
+/* 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);
-#if ! (defined __MINGW32__ \
-       && defined __GNUC__ && !defined __clang__ && __GNUC__ < 15)
   ASSERT (s1 == NULL);
-#endif
   return p;
 }
 static wchar_t *(*volatile volatile_null_wmemcpy) (wchar_t *, wchar_t const *,
@@ -56,8 +51,12 @@ int
 main (void)
 {
   /* Test zero-length operations on NULL pointers, allowed by
-     <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.  */
+     <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.
+     In mingw-w64 14.0.0, wmemcpy is an inline function that calls memcpy.
+     In GCC < 15, memcpy is a builtin that has the nonnull attribute.  */
 
+#if ! (defined __MINGW32__ \
+       && defined __GNUC__ && !defined __clang__ && __GNUC__ < 15)
   ASSERT (wmemcpy (NULL, L"x", 0) == NULL);
 
   {
@@ -66,6 +65,7 @@ main (void)
   }
 
   ASSERT (volatile_null_wmemcpy (NULL, L"x", 0) == NULL);
+#endif
 
   return test_exit_status;
 }
diff --git a/tests/test-wmemmove.c b/tests/test-wmemmove.c
index ed924e1a68..82315281ab 100644
--- a/tests/test-wmemmove.c
+++ b/tests/test-wmemmove.c
@@ -23,17 +23,12 @@
 
 #include "macros.h"
 
-/* Test the prototype in <wchar.h> + compiler.
-   In mingw-w64 14.0.0, wmemmove is an inline function that calls memmove.
-   In GCC < 15, memmove is a builtin that has the nonnull attribute.  */
+/* 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);
-#if ! (defined __MINGW32__ \
-       && defined __GNUC__ && !defined __clang__ && __GNUC__ < 15)
   ASSERT (s1 == NULL);
-#endif
   return p;
 }
 static wchar_t *(*volatile volatile_null_wmemmove) (wchar_t *, wchar_t const *,
@@ -56,8 +51,12 @@ int
 main (void)
 {
   /* Test zero-length operations on NULL pointers, allowed by
-     <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.  */
+     <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.
+     In mingw-w64 14.0.0, wmemmove is an inline function that calls memmove.
+     In GCC < 15, memmove is a builtin that has the nonnull attribute.  */
 
+#if ! (defined __MINGW32__ \
+       && defined __GNUC__ && !defined __clang__ && __GNUC__ < 15)
   ASSERT (wmemmove (NULL, L"x", 0) == NULL);
 
   {
@@ -66,6 +65,7 @@ main (void)
   }
 
   ASSERT (volatile_null_wmemmove (NULL, L"x", 0) == NULL);
+#endif
 
   return test_exit_status;
 }
-- 
2.55.0

Reply via email to