Re: N3322 functionality tests

Bruno Haible via Gnulib discussion list <[email protected]>
Newsgroups gmane.comp.lib.gnulib.bugs
Message-ID <8094324.6MygDL6H9D@cagnes>
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.
0001-tests-Avoid-some-test-failures-with-the-clang-UBSAN.patch (text/x-patch, 12.5 KB)
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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.