]> Savannah Git Hosting - gnulib.git/commitdiff
wmemcmp: Work around ISO C compliance bug on several platforms.
authorBruno Haible <bruno@clisp.org>
Tue, 18 Apr 2023 23:01:56 +0000 (01:01 +0200)
committerBruno Haible <bruno@clisp.org>
Tue, 18 Apr 2023 23:07:24 +0000 (01:07 +0200)
* lib/wchar.in.h (wmemcmp): Consider REPLACE_WMEMCMP.
* lib/wmemcmp-impl.h (wmemcmp): Don't assume that the two wide
characters are in the range 0..INT_MAX.
* m4/wmemcmp.m4 (gl_FUNC_WMEMCMP): Test whether wmemcmp works for all
wide characters. Set REPLACE_WMEMCMP.
* m4/wchar_h.m4 (gl_WCHAR_H_DEFAULTS): Initialize REPLACE_WMEMCMP.
* modules/wchar (Makefile.am): Substitute REPLACE_WMEMCMP.
* modules/wmemcmp (configure.ac): Consider REPLACE_WMEMCMP.
* doc/posix-functions/wmemcmp.texi: Mention the bug.

ChangeLog
doc/posix-functions/wmemcmp.texi
lib/wchar.in.h
lib/wmemcmp-impl.h
m4/wchar_h.m4
m4/wmemcmp.m4
modules/wchar
modules/wmemcmp

index 4b8c72490bb85b96724adfc1d9f8a5eb6d270a1b..6e885d865cf942ff69452e10827a773e2f886551 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2023-04-18  Bruno Haible  <bruno@clisp.org>
+
+       wmemcmp: Work around ISO C compliance bug on several platforms.
+       * lib/wchar.in.h (wmemcmp): Consider REPLACE_WMEMCMP.
+       * lib/wmemcmp-impl.h (wmemcmp): Don't assume that the two wide
+       characters are in the range 0..INT_MAX.
+       * m4/wmemcmp.m4 (gl_FUNC_WMEMCMP): Test whether wmemcmp works for all
+       wide characters. Set REPLACE_WMEMCMP.
+       * m4/wchar_h.m4 (gl_WCHAR_H_DEFAULTS): Initialize REPLACE_WMEMCMP.
+       * modules/wchar (Makefile.am): Substitute REPLACE_WMEMCMP.
+       * modules/wmemcmp (configure.ac): Consider REPLACE_WMEMCMP.
+       * doc/posix-functions/wmemcmp.texi: Mention the bug.
+
 2023-04-18  Bruno Haible  <bruno@clisp.org>
 
        doc: Update platform list for posix_spawnp.
index 8d3262c5cb17dba9567a027e358b6fdc5b867174..cebacfb6641713c2f46e4876ae8265fdc2f80eeb 100644 (file)
@@ -11,6 +11,10 @@ Portability problems fixed by Gnulib:
 @item
 This function is missing on some platforms:
 HP-UX 11.00, IRIX 6.5, MSVC 14.
+@item
+This function compares the wide characters as if they were unsigned, although
+@code{wchar_t} is signed, on some platforms:
+glibc 2.14.1 on x86 or x86_64, musl libc 1.2.3, NetBSD 9.0, OpenBSD 7.2, Solaris 11.4.
 @end itemize
 
 Portability problems not fixed by Gnulib:
index 80b6652e95db3202b352919b61f7116cab24d4db..6a5b18d39d78a57b23496b93f9ac7c11bbe7cec4 100644 (file)
@@ -641,13 +641,25 @@ _GL_WARN_ON_USE (wmemchr, "wmemchr is unportable - "
 
 /* Compare N wide characters of S1 and S2.  */
 #if @GNULIB_WMEMCMP@
-# if !@HAVE_WMEMCMP@
+# if @REPLACE_WMEMCMP@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef wmemcmp
+#   define wmemcmp rpl_wmemcmp
+#  endif
+_GL_FUNCDECL_RPL (wmemcmp, int,
+                  (const wchar_t *s1, const wchar_t *s2, size_t n)
+                  _GL_ATTRIBUTE_PURE);
+_GL_CXXALIAS_RPL (wmemcmp, int,
+                  (const wchar_t *s1, const wchar_t *s2, size_t n));
+# else
+#  if !@HAVE_WMEMCMP@
 _GL_FUNCDECL_SYS (wmemcmp, int,
                   (const wchar_t *s1, const wchar_t *s2, size_t n)
                   _GL_ATTRIBUTE_PURE);
-# endif
+#  endif
 _GL_CXXALIAS_SYS (wmemcmp, int,
                   (const wchar_t *s1, const wchar_t *s2, size_t n));
+# endif
 # if __GLIBC__ >= 2
 _GL_CXXALIASWARN (wmemcmp);
 # endif
index 2b8125fe26d8c831b42cec96fdf1b2b87bacae68..6148220de7ba027161f3b77f40fa60b154eab6ab 100644 (file)
@@ -27,8 +27,9 @@ wmemcmp (const wchar_t *s1, const wchar_t *s2, size_t n)
           n--;
           continue;
         }
-      /* Note that wc1 and wc2 each have at most 31 bits.  */
-      return (int)wc1 - (int)wc2;
+      /* ISO C requires wmemcmp to work with all wchar_t values.
+         We cannot assume that wc1 and wc2 are in the range 0..INT_MAX.  */
+      return _GL_CMP (wc1, wc2);
              /* > 0 if wc1 > wc2, < 0 if wc1 < wc2.  */
     }
   return 0;
index 8cc38ef8043fb7a6875dea0989da2a8f58ff88a7..dfd154f8e93e75b180e13232ac1462812f1ce508 100644 (file)
@@ -7,7 +7,7 @@ dnl with or without modifications, as long as this notice is preserved.
 
 dnl Written by Eric Blake.
 
-# wchar_h.m4 serial 57
+# wchar_h.m4 serial 58
 
 AC_DEFUN_ONCE([gl_WCHAR_H],
 [
@@ -255,5 +255,6 @@ AC_DEFUN([gl_WCHAR_H_DEFAULTS],
   REPLACE_WCSFTIME=0;   AC_SUBST([REPLACE_WCSFTIME])
   REPLACE_WCSSTR=0;     AC_SUBST([REPLACE_WCSSTR])
   REPLACE_WCSTOK=0;     AC_SUBST([REPLACE_WCSTOK])
+  REPLACE_WMEMCMP=0;    AC_SUBST([REPLACE_WMEMCMP])
   REPLACE_WMEMPCPY=0;   AC_SUBST([REPLACE_WMEMPCPY])
 ])
index 534dde10ccf8ada721214db5e74976e9191cd04d..c804dc8a4a6569a8f1ed55da498d37d6eef6d853 100644 (file)
@@ -1,4 +1,4 @@
-# wmemcmp.m4 serial 5
+# wmemcmp.m4 serial 6
 dnl Copyright (C) 2011-2023 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -7,6 +7,7 @@ dnl with or without modifications, as long as this notice is preserved.
 AC_DEFUN([gl_FUNC_WMEMCMP],
 [
   AC_REQUIRE([gl_WCHAR_H_DEFAULTS])
+  AC_REQUIRE([AC_CANONICAL_HOST])
   dnl We cannot use AC_CHECK_FUNCS here, because the MSVC 9 header files
   dnl provide this function as an inline function definition.
   AC_CACHE_CHECK([for wmemcmp], [gl_cv_func_wmemcmp],
@@ -21,5 +22,51 @@ AC_DEFUN([gl_FUNC_WMEMCMP],
     ])
   if test $gl_cv_func_wmemcmp = no; then
     HAVE_WMEMCMP=0
+  else
+    AC_CACHE_CHECK([whether wmemcmp works for all wide characters],
+      [gl_cv_func_wmemcmp_works],
+      [AC_RUN_IFELSE(
+         [AC_LANG_SOURCE([[
+            #include <wchar.h>
+            int main ()
+            {
+              wchar_t a = (wchar_t) 0x76547654;
+              wchar_t b = (wchar_t) 0x9abc9abc;
+              int cmp = wmemcmp (&a, &b, 1);
+              if ((wchar_t)-1 < 0)
+                return !(cmp > 0);
+              else
+                return !(cmp < 0);
+            }
+            ]])
+         ],
+         [gl_cv_func_wmemcmp_works=yes],
+         [gl_cv_func_wmemcmp_works=no],
+         [case "$host_on" in
+            # Guess no on glibc versions < 2.15.
+            *-gnu* | gnu*)
+              AC_EGREP_CPP([Unlucky],
+                [
+#include <features.h>
+#ifdef __GNU_LIBRARY__
+ #if (__GLIBC__ == 2 && __GLIBC_MINOR__ < 15)
+  Unlucky GNU user
+ #endif
+#endif
+                ],
+                [gl_cv_func_wmemcmp_works="guessing no"],
+                [gl_cv_func_wmemcmp_works="guessing yes"])
+              ;;
+            # Guess no on musl systems.
+            *-musl* | midipix*) gl_cv_func_wmemcmp_works="guessing no" ;;
+            # If we don't know, obey --enable-cross-guesses.
+            *) gl_cv_func_wmemcmp_works="$gl_cross_guess_normal" ;;
+          esac
+         ])
+      ])
+    case "$gl_cv_func_wmemcmp_works" in
+      *yes) ;;
+      *) REPLACE_WMEMCMP=1 ;;
+    esac
   fi
 ])
index feacaffff1ea4898a493f6def9411cc5e824b15d..180c94309c0f3b4c20b42fe222e361cafc2d7a24 100644 (file)
@@ -144,6 +144,7 @@ wchar.h: wchar.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H)
              -e 's|@''REPLACE_WCSFTIME''@|$(REPLACE_WCSFTIME)|g' \
              -e 's|@''REPLACE_WCSSTR''@|$(REPLACE_WCSSTR)|g' \
              -e 's|@''REPLACE_WCSTOK''@|$(REPLACE_WCSTOK)|g' \
+             -e 's|@''REPLACE_WMEMCMP''@|$(REPLACE_WMEMCMP)|g' \
              -e 's|@''REPLACE_WMEMPCPY''@|$(REPLACE_WMEMPCPY)|g' \
              -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \
              -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \
index 219f3c3754bf8b1c87c6621bbd867b8532e4b5f2..c0e19a518493f1ac5d3d3f2fe0847b7a550d2d1e 100644 (file)
@@ -11,7 +11,8 @@ wchar
 
 configure.ac:
 gl_FUNC_WMEMCMP
-gl_CONDITIONAL([GL_COND_OBJ_WMEMCMP], [test $HAVE_WMEMCMP = 0])
+gl_CONDITIONAL([GL_COND_OBJ_WMEMCMP],
+               [test $HAVE_WMEMCMP = 0 || test $REPLACE_WMEMCMP = 1])
 gl_WCHAR_MODULE_INDICATOR([wmemcmp])
 
 Makefile.am: