Lasse Collin wrote:
> As mentioned earlier, Clang doesn't optimize if it sees the nonnull
> attribute only in a function declaration. A discussion from 2017[1]
> gives an impression that glibc's headers might have been a reason for
> this.
> 
> [1] 
> https://discourse.llvm.org/t/rfc-do-not-optimize-on-basis-of-attribute-nonnull-in-glibc-headers/43547

Well, now it does. With clang 22 + UBSAN I see these test failures:


FAIL: test-memchr
=================

test-memchr.c:50:19: runtime error: null pointer passed as argument 1, which is 
declared to never be null
/usr/include/string.h:119:34: note: nonnull attribute specified here
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior test-memchr.c:50:19 
FAIL test-memchr (exit status: 1)

FAIL: test-memcmp
=================

test-memcmp.c:48:18: runtime error: null pointer passed as argument 1, which is 
declared to never be null
/usr/include/string.h:76:33: note: nonnull attribute specified here
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior test-memcmp.c:48:18 
FAIL test-memcmp (exit status: 1)

and so on.


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.


2026-08-16  Bruno Haible  <[email protected]>

        tests: Avoid some test failures with the clang UBSAN.
        * tests/test-bsearch.c (main): Disable the N3322 test on glibc systems.
        * tests/test-memccpy.c (main): Likewise.
        * tests/test-memchr.c (main): Likewise.
        * tests/test-memcmp.c (main): Likewise.
        * tests/test-memcpy.c (main): Likewise.
        * tests/test-memmove.c (main): Likewise.
        * tests/test-memset.c (main): Likewise.
        * tests/test-memset_explicit.c (main): Likewise.
        * tests/test-qsort.c (main): Likewise.
        * tests/test-strncat.c (main): Likewise.
        * tests/test-strncmp.c (main): Likewise.
        * tests/test-strncpy.c (main): Likewise.
        * tests/test-strndup.c (main): Likewise.
        * tests/test-wcsncat.c (main): Likewise.
        * tests/test-wcsncmp.c (main): Likewise.
        * tests/test-wcsncpy.c (main): Likewise.

From dbdd898e9e63524df43421b95c1cb3cc548db40d Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Mon, 17 Aug 2026 00:27:42 +0200
Subject: [PATCH] tests: Avoid some test failures with the clang UBSAN.

* tests/test-bsearch.c (main): Disable the N3322 test on glibc systems.
* tests/test-memccpy.c (main): Likewise.
* tests/test-memchr.c (main): Likewise.
* tests/test-memcmp.c (main): Likewise.
* tests/test-memcpy.c (main): Likewise.
* tests/test-memmove.c (main): Likewise.
* tests/test-memset.c (main): Likewise.
* tests/test-memset_explicit.c (main): Likewise.
* tests/test-qsort.c (main): Likewise.
* tests/test-strncat.c (main): Likewise.
* tests/test-strncmp.c (main): Likewise.
* tests/test-strncpy.c (main): Likewise.
* tests/test-strndup.c (main): Likewise.
* tests/test-wcsncat.c (main): Likewise.
* tests/test-wcsncmp.c (main): Likewise.
* tests/test-wcsncpy.c (main): Likewise.
---
 ChangeLog                    | 20 ++++++++++++++++++++
 tests/test-bsearch.c         |  2 ++
 tests/test-memccpy.c         |  2 ++
 tests/test-memchr.c          |  3 +++
 tests/test-memcmp.c          |  3 +++
 tests/test-memcpy.c          |  3 +++
 tests/test-memmove.c         |  3 +++
 tests/test-memset.c          |  3 +++
 tests/test-memset_explicit.c |  2 ++
 tests/test-qsort.c           |  2 ++
 tests/test-strncat.c         |  7 +++++--
 tests/test-strncmp.c         |  3 +++
 tests/test-strncpy.c         |  3 +++
 tests/test-strndup.c         |  3 +++
 tests/test-wcsncat.c         |  6 ++++--
 tests/test-wcsncmp.c         |  2 ++
 tests/test-wcsncpy.c         |  2 ++
 17 files changed, 65 insertions(+), 4 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 32a9a08db7..0342ca9cac 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,23 @@
+2026-08-16  Bruno Haible  <[email protected]>
+
+	tests: Avoid some test failures with the clang UBSAN.
+	* tests/test-bsearch.c (main): Disable the N3322 test on glibc systems.
+	* tests/test-memccpy.c (main): Likewise.
+	* tests/test-memchr.c (main): Likewise.
+	* tests/test-memcmp.c (main): Likewise.
+	* tests/test-memcpy.c (main): Likewise.
+	* tests/test-memmove.c (main): Likewise.
+	* tests/test-memset.c (main): Likewise.
+	* tests/test-memset_explicit.c (main): Likewise.
+	* tests/test-qsort.c (main): Likewise.
+	* tests/test-strncat.c (main): Likewise.
+	* tests/test-strncmp.c (main): Likewise.
+	* tests/test-strncpy.c (main): Likewise.
+	* tests/test-strndup.c (main): Likewise.
+	* tests/test-wcsncat.c (main): Likewise.
+	* tests/test-wcsncmp.c (main): Likewise.
+	* tests/test-wcsncpy.c (main): Likewise.
+
 2026-08-16  Bruno Haible  <[email protected]>
 
 	doc: Mention a wcsncat bug.
diff --git a/tests/test-bsearch.c b/tests/test-bsearch.c
index 9cfdcfe3cb..60cd0ff08c 100644
--- a/tests/test-bsearch.c
+++ b/tests/test-bsearch.c
@@ -64,9 +64,11 @@ main (void)
 {
   /* Test zero-length operations on NULL pointers, allowed by
      <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.  */
+#if ! defined __GLIBC__ || 2 < __GLIBC__ + (99 <= __GLIBC_MINOR__)
   ASSERT (bsearch ("x", NULL, 0, 1, cmp) == NULL);
 
   ASSERT (volatile_null_bsearch ("x", NULL, 0, 1, cmp) == NULL);
+#endif
 
   return test_exit_status;
 }
diff --git a/tests/test-memccpy.c b/tests/test-memccpy.c
index 6f9e6d9c34..c942e18675 100644
--- a/tests/test-memccpy.c
+++ b/tests/test-memccpy.c
@@ -56,6 +56,7 @@ main (void)
   /* Test zero-length operations on NULL pointers, allowed by
      <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.  */
 
+#if ! defined __GLIBC__ || 2 < __GLIBC__ + (99 <= __GLIBC_MINOR__)
   ASSERT (memccpy (NULL, "x", '?', 0) == NULL);
 
   {
@@ -64,6 +65,7 @@ main (void)
   }
 
   ASSERT (volatile_null_memccpy (NULL, "x", '?', 0) == NULL);
+#endif
 
   return test_exit_status;
 }
diff --git a/tests/test-memchr.c b/tests/test-memchr.c
index c125244a99..ea662ca2f2 100644
--- a/tests/test-memchr.c
+++ b/tests/test-memchr.c
@@ -152,9 +152,12 @@ main (void)
 
   /* Test zero-length operations on NULL pointers, allowed by
      <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.  */
+#if (! defined __GNUC__ || __GNUC__ >= 15 || defined __clang__) \
+    && (! defined __GLIBC__ || 2 < __GLIBC__ + (99 <= __GLIBC_MINOR__))
   ASSERT (memchr (NULL, '?', 0) == NULL);
 
   ASSERT (volatile_null_memchr (NULL, '?', 0) == NULL);
+#endif
 
   return test_exit_status;
 }
diff --git a/tests/test-memcmp.c b/tests/test-memcmp.c
index be68403159..601f46859f 100644
--- a/tests/test-memcmp.c
+++ b/tests/test-memcmp.c
@@ -98,11 +98,14 @@ main (void)
 
   /* Test zero-length operations on NULL pointers, allowed by
      <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.  */
+#if (! defined __GNUC__ || __GNUC__ >= 15 || defined __clang__) \
+    && (! defined __GLIBC__ || 2 < __GLIBC__ + (99 <= __GLIBC_MINOR__))
   ASSERT (memcmp (NULL, "x", 0) == 0);
   ASSERT (memcmp ("x", NULL, 0) == 0);
   ASSERT (memcmp (NULL, NULL, 0) == 0);
 
   ASSERT (volatile_null_memcmp (NULL, "x", 0) == 0);
+#endif
 
   return test_exit_status;
 }
diff --git a/tests/test-memcpy.c b/tests/test-memcpy.c
index 8d0fdfb88d..8836e9680a 100644
--- a/tests/test-memcpy.c
+++ b/tests/test-memcpy.c
@@ -56,6 +56,8 @@ main (void)
   /* Test zero-length operations on NULL pointers, allowed by
      <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.  */
 
+#if (! defined __GNUC__ || __GNUC__ >= 15 || defined __clang__) \
+    && (! defined __GLIBC__ || 2 < __GLIBC__ + (99 <= __GLIBC_MINOR__))
   ASSERT (memcpy (NULL, "x", 0) == NULL);
 
   {
@@ -66,6 +68,7 @@ main (void)
   /* 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.  */
   ASSERT (volatile_null_memcpy (NULL, "x", 0) == NULL);
+#endif
 
   return test_exit_status;
 }
diff --git a/tests/test-memmove.c b/tests/test-memmove.c
index 8709e9082f..6b433ce7f0 100644
--- a/tests/test-memmove.c
+++ b/tests/test-memmove.c
@@ -56,6 +56,8 @@ main (void)
   /* Test zero-length operations on NULL pointers, allowed by
      <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.  */
 
+#if (! defined __GNUC__ || __GNUC__ >= 15 || defined __clang__) \
+    && (! defined __GLIBC__ || 2 < __GLIBC__ + (99 <= __GLIBC_MINOR__))
   ASSERT (memmove (NULL, "x", 0) == NULL);
 
   {
@@ -64,6 +66,7 @@ main (void)
   }
 
   ASSERT (volatile_null_memmove (NULL, "x", 0) == NULL);
+#endif
 
   return test_exit_status;
 }
diff --git a/tests/test-memset.c b/tests/test-memset.c
index 258d62754c..39dd047b65 100644
--- a/tests/test-memset.c
+++ b/tests/test-memset.c
@@ -55,9 +55,12 @@ main (void)
 {
   /* Test zero-length operations on NULL pointers, allowed by
      <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.  */
+#if (! defined __GNUC__ || __GNUC__ >= 15 || defined __clang__) \
+    && (! defined __GLIBC__ || 2 < __GLIBC__ + (99 <= __GLIBC_MINOR__))
   ASSERT (memset (NULL, '?', 0) == NULL);
 
   ASSERT (volatile_null_memset (NULL, '?', 0) == NULL);
+#endif
 
   return test_exit_status;
 }
diff --git a/tests/test-memset_explicit.c b/tests/test-memset_explicit.c
index 79f42a38c8..e2ab32097f 100644
--- a/tests/test-memset_explicit.c
+++ b/tests/test-memset_explicit.c
@@ -280,9 +280,11 @@ main ()
 
   /* Test zero-length operations on NULL pointers, allowed by
      <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.  */
+#if ! defined __GLIBC__ || 2 < __GLIBC__ + (99 <= __GLIBC_MINOR__)
   ASSERT (memset_explicit (NULL, '?', 0) == NULL);
 
   ASSERT (volatile_null_memset_explicit (NULL, '?', 0) == NULL);
+#endif
 
   return test_exit_status;
 }
diff --git a/tests/test-qsort.c b/tests/test-qsort.c
index 9efbe53397..8904882ac1 100644
--- a/tests/test-qsort.c
+++ b/tests/test-qsort.c
@@ -61,9 +61,11 @@ main (void)
   /* Test zero-length operations on NULL pointers, allowed by
      <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.  */
 
+#if ! defined __GLIBC__ || 2 < __GLIBC__ + (99 <= __GLIBC_MINOR__)
   qsort (NULL, 0, 1, cmp);
 
   volatile_null_qsort (NULL, 0, 1, cmp);
+#endif
 
   return 0;
 }
diff --git a/tests/test-strncat.c b/tests/test-strncat.c
index 2eeb46d77c..162b3d4e42 100644
--- a/tests/test-strncat.c
+++ b/tests/test-strncat.c
@@ -89,9 +89,11 @@ main ()
   /* Test zero-length operations on NULL pointers, allowed by
      <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.  */
 
-#if 0 /* I think this is invalid, per ISO C 23 § 7.26.3.2.  */
+#if (! defined __GNUC__ || __GNUC__ >= 15 || defined __clang__) \
+    && (! defined __GLIBC__ || 2 < __GLIBC__ + (99 <= __GLIBC_MINOR__))
+# if 0 /* I think this is invalid, per ISO C 23 § 7.26.3.2.  */
   ASSERT (strncat (NULL, "x", 0) == NULL);
-#endif
+# endif
 
   {
     char y[2] = { 'x', '\0' };
@@ -99,6 +101,7 @@ main ()
 
     ASSERT (volatile_null_strncat (y, NULL, 0) == y);
   }
+#endif
 
   return test_exit_status;
 }
diff --git a/tests/test-strncmp.c b/tests/test-strncmp.c
index 95ff26085a..cbc2327861 100644
--- a/tests/test-strncmp.c
+++ b/tests/test-strncmp.c
@@ -57,11 +57,14 @@ main (void)
 {
   /* Test zero-length operations on NULL pointers, allowed by
      <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.  */
+#if (! defined __GNUC__ || __GNUC__ >= 15 || defined __clang__) \
+    && (! defined __GLIBC__ || 2 < __GLIBC__ + (99 <= __GLIBC_MINOR__))
   ASSERT (strncmp (NULL, "x", 0) == 0);
   ASSERT (strncmp ("x", NULL, 0) == 0);
   ASSERT (strncmp (NULL, NULL, 0) == 0);
 
   ASSERT (volatile_null_strncmp (NULL, "x", 0) == 0);
+#endif
 
   return test_exit_status;
 }
diff --git a/tests/test-strncpy.c b/tests/test-strncpy.c
index 80b79f4e0c..2bbbecd991 100644
--- a/tests/test-strncpy.c
+++ b/tests/test-strncpy.c
@@ -127,6 +127,8 @@ main (void)
   /* Test zero-length operations on NULL pointers, allowed by
      <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.  */
 
+#if (! defined __GNUC__ || __GNUC__ >= 15 || defined __clang__) \
+    && (! defined __GLIBC__ || 2 < __GLIBC__ + (99 <= __GLIBC_MINOR__))
   ASSERT (strncpy (NULL, "x", 0) == NULL);
 
   {
@@ -135,6 +137,7 @@ main (void)
 
     ASSERT (volatile_null_strncpy (y, NULL, 0) == y);
   }
+#endif
 
   return test_exit_status;
 }
diff --git a/tests/test-strndup.c b/tests/test-strndup.c
index 84c94184b6..b7f9db05c5 100644
--- a/tests/test-strndup.c
+++ b/tests/test-strndup.c
@@ -55,9 +55,12 @@ main (void)
 {
   /* Test zero-length operations on NULL pointers, allowed by
      <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.  */
+#if (! defined __GNUC__ || __GNUC__ >= 15 || defined __clang__) \
+    && (! defined __GLIBC__ || 2 < __GLIBC__ + (99 <= __GLIBC_MINOR__))
   ASSERT (strndup (NULL, 0) != NULL);
 
   ASSERT (volatile_null_strndup (NULL, 0) != NULL);
+#endif
 
   return test_exit_status;
 }
diff --git a/tests/test-wcsncat.c b/tests/test-wcsncat.c
index f18f77a300..bf5cc48ae8 100644
--- a/tests/test-wcsncat.c
+++ b/tests/test-wcsncat.c
@@ -58,9 +58,10 @@ main ()
   /* Test zero-length operations on NULL pointers, allowed by
      <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.  */
 
-#if 0 /* I think this is invalid, per ISO C 23 § 7.31.4.3.2.  */
+#if ! defined __GLIBC__ || 2 < __GLIBC__ + (99 <= __GLIBC_MINOR__)
+# if 0 /* I think this is invalid, per ISO C 23 § 7.31.4.3.2.  */
   ASSERT (wcsncat (NULL, L"x", 0) == NULL);
-#endif
+# endif
 
   {
     wchar_t y[2] = { L'x', 0 };
@@ -68,6 +69,7 @@ main ()
 
     ASSERT (volatile_null_wcsncat (y, NULL, 0) == y);
   }
+#endif
 
   return test_exit_status;
 }
diff --git a/tests/test-wcsncmp.c b/tests/test-wcsncmp.c
index 0772925bbc..16990772ad 100644
--- a/tests/test-wcsncmp.c
+++ b/tests/test-wcsncmp.c
@@ -207,11 +207,13 @@ 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>.  */
+#if ! defined __GLIBC__ || 2 < __GLIBC__ + (99 <= __GLIBC_MINOR__)
   ASSERT (wcsncmp (NULL, L"x", 0) == 0);
   ASSERT (wcsncmp (L"x", NULL, 0) == 0);
   ASSERT (wcsncmp (NULL, NULL, 0) == 0);
 
   ASSERT (volatile_null_wcsncmp (NULL, L"x", 0) == 0);
+#endif
 
   return test_exit_status;
 }
diff --git a/tests/test-wcsncpy.c b/tests/test-wcsncpy.c
index 25bc00c7d9..a2e8622ca8 100644
--- a/tests/test-wcsncpy.c
+++ b/tests/test-wcsncpy.c
@@ -56,6 +56,7 @@ main (void)
   /* Test zero-length operations on NULL pointers, allowed by
      <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3322.pdf>.  */
 
+#if ! defined __GLIBC__ || 2 < __GLIBC__ + (99 <= __GLIBC_MINOR__)
   ASSERT (wcsncpy (NULL, L"x", 0) == NULL);
 
   {
@@ -64,6 +65,7 @@ main (void)
 
     ASSERT (volatile_null_wcsncpy (y, NULL, 0) == y);
   }
+#endif
 
   return test_exit_status;
 }
-- 
2.53.0

Reply via email to