Dmitry Bogatov wrote:
> > Example code:
> >
> > #include <string.h>
> > #include <stdio.h>
> >
> > int main()
> > {
> >     int value = strverscmp("UNKNOWN", "2.2.0");
> >     printf("%d\n", value);
> >     return 0;
> > }
> >
> > Under glibc value "35" is printed (positive), under musl value "-1" is
> > printed (negative).

Indeed, I can reproduce this with
  - musl libc 1.2.3 and older (Alpine Linux 3.17 and older),
  - Cygwin 2.9.0.

> > Not sure what is the correct solution for the
> > issue, so I cross-post into two lists.

Since the issue has meanwhile been fixed in musl libc 1.2.4
https://git.musl-libc.org/cgit/musl/commit/src/string/strverscmp.c?id=b50eb8c36c20f967bd0ed70c0b0db38a450886ba
the glibc behaviour is the correct one.

I'm applying the patch below.

> > While trying to building gsasl statically with musl library as part of
> > Nixpkgs distribution

Nixpkg must be using an old musl libc, then. The newest one is 1.2.4.

Simon Josefsson wrote:
> https://cygwin.com/cgit/newlib-cygwin/tree/newlib/libc/string/strverscmp.c

So, I've forwarded the report to the Cygwin people:
https://sourceware.org/pipermail/cygwin/2024-January/255085.html

> Cygwin (via MSYS2)

Errr. Cygwin does not use MSYS2. MSYS2 cannibalizes the Cygwin sources, not
the other way around.


2024-01-02  Bruno Haible  <br...@clisp.org>

        strverscmp: Work around bug in musl libc 1.2.3 and in Cygwin.
        Reported by Dmitry Bogatov <kact...@gnu.org> via Simon Josefsson in
        <https://lists.gnu.org/archive/html/bug-gnulib/2024-01/msg00002.html>.
        * m4/string_h.m4 (gl_STRING_H_DEFAULTS): Initialize REPLACE_STRVERSCMP.
        * m4/strverscmp.m4 (gl_FUNC_STRVERSCMP): Test whether strverscmp works
        and set REPLACE_STRVERSCMP if not.
        * lib/string.in.h (strverscmp): Consider REPLACE_STRVERSCMP.
        * modules/strverscmp (Depends-on, configure.ac): Likewise.
        * modules/string (Makefile.am): Substitute REPLACE_STRVERSCMP.
        * tests/test-strverscmp.c (main): Add test cases suggested by Dmitry
        Bogatov and by Simon Josefsson.
        * doc/glibc-functions/strverscmp.texi: Mention the musl and Cygwin bug.
        Update version info regarding FreeBSD.

diff --git a/doc/glibc-functions/strverscmp.texi 
b/doc/glibc-functions/strverscmp.texi
index 5882d223e1..9e37143fa4 100644
--- a/doc/glibc-functions/strverscmp.texi
+++ b/doc/glibc-functions/strverscmp.texi
@@ -20,8 +20,13 @@
 Portability problems fixed by Gnulib:
 @itemize
 @item
-This function is missing on all non-glibc platforms:
-macOS 11.1, FreeBSD 13.0, NetBSD 9.0, OpenBSD 6.7, Minix 3.1.8, AIX 5.1, HP-UX 
11, IRIX 6.5, Solaris 11.4, Cygwin 1.7.x, mingw, MSVC 14, Android 9.0.
+This function is missing on many platforms:
+macOS 11.1, FreeBSD 13.1, NetBSD 9.0, OpenBSD 6.7, Minix 3.1.8, AIX 5.1, HP-UX 
11, IRIX 6.5, Solaris 11.4, Cygwin 1.7.x, mingw, MSVC 14, Android 9.0.
+@item
+This function treats ASCII letters as smaller than a digit sequence
+on some platforms:
+@c 
https://git.musl-libc.org/cgit/musl/commit/src/string/strverscmp.c?id=b50eb8c36c20f967bd0ed70c0b0db38a450886ba
+musl libc 1.2.3, Cygwin 3.4.6.
 @end itemize
 
 Portability problems not fixed by Gnulib:
diff --git a/lib/string.in.h b/lib/string.in.h
index 66be871a57..01ea3e3913 100644
--- a/lib/string.in.h
+++ b/lib/string.in.h
@@ -1419,12 +1419,22 @@ _GL_WARN_ON_USE (strsignal, "strsignal is unportable - "
 #endif
 
 #if @GNULIB_STRVERSCMP@
-# if !@HAVE_STRVERSCMP@
+# if @REPLACE_STRVERSCMP@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   define strverscmp rpl_strverscmp
+#  endif
+_GL_FUNCDECL_RPL (strverscmp, int, (const char *, const char *)
+                                   _GL_ATTRIBUTE_PURE
+                                   _GL_ARG_NONNULL ((1, 2)));
+_GL_CXXALIAS_RPL (strverscmp, int, (const char *, const char *));
+# else
+#  if !@HAVE_STRVERSCMP@
 _GL_FUNCDECL_SYS (strverscmp, int, (const char *, const char *)
                                    _GL_ATTRIBUTE_PURE
                                    _GL_ARG_NONNULL ((1, 2)));
-# endif
+#  endif
 _GL_CXXALIAS_SYS (strverscmp, int, (const char *, const char *));
+# endif
 _GL_CXXALIASWARN (strverscmp);
 #elif defined GNULIB_POSIXCHECK
 # undef strverscmp
diff --git a/m4/string_h.m4 b/m4/string_h.m4
index 3cbcbc7487..8b12101447 100644
--- a/m4/string_h.m4
+++ b/m4/string_h.m4
@@ -5,7 +5,7 @@
 # gives unlimited permission to copy and/or distribute it,
 # with or without modifications, as long as this notice is preserved.
 
-# serial 37
+# serial 38
 
 # Written by Paul Eggert.
 
@@ -146,5 +146,6 @@ AC_DEFUN([gl_STRING_H_DEFAULTS]
   REPLACE_STRERROR_R=0;         AC_SUBST([REPLACE_STRERROR_R])
   REPLACE_STRERRORNAME_NP=0;    AC_SUBST([REPLACE_STRERRORNAME_NP])
   REPLACE_STRSIGNAL=0;          AC_SUBST([REPLACE_STRSIGNAL])
+  REPLACE_STRVERSCMP=0;         AC_SUBST([REPLACE_STRVERSCMP])
   UNDEFINE_STRTOK_R=0;          AC_SUBST([UNDEFINE_STRTOK_R])
 ])
diff --git a/m4/strverscmp.m4 b/m4/strverscmp.m4
index a0eef7bd92..748272abec 100644
--- a/m4/strverscmp.m4
+++ b/m4/strverscmp.m4
@@ -1,4 +1,4 @@
-# strverscmp.m4 serial 9
+# strverscmp.m4 serial 10
 dnl Copyright (C) 2002, 2005-2024 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -13,6 +13,37 @@ AC_DEFUN([gl_FUNC_STRVERSCMP]
   AC_CHECK_FUNCS([strverscmp])
   if test $ac_cv_func_strverscmp = no; then
     HAVE_STRVERSCMP=0
+  else
+    AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
+    AC_CACHE_CHECK([whether strverscmp works],
+      [gl_cv_func_strverscmp_works],
+      [dnl Detect musl-1.2.3 and Cygwin 3.4.6 bug.
+       AC_RUN_IFELSE(
+         [AC_LANG_SOURCE([[
+#include <string.h>
+int main ()
+{
+  return strverscmp ("UNKNOWN", "2.2.0") <= 0;
+}
+         ]])],
+         [gl_cv_func_strverscmp_works=yes],
+         [gl_cv_func_strverscmp_works=no],
+         [case "$host_os" in
+                                # Guess yes on glibc systems.
+            *-gnu* | gnu*)      gl_cv_func_strverscmp_works="guessing yes" ;;
+                                # Guess no on musl systems.
+            *-musl* | midipix*) gl_cv_func_strverscmp_works="guessing no" ;;
+                                # Guess no on Cygwin.
+            cygwin*)            gl_cv_func_strverscmp_works="guessing no" ;;
+                                # If we don't know, obey 
--enable-cross-guesses.
+            *)                  
gl_cv_func_strverscmp_works="$gl_cross_guess_normal" ;;
+          esac
+         ])
+      ])
+    case "$gl_cv_func_strverscmp_works" in
+      *yes) ;;
+      *) REPLACE_STRVERSCMP=1 ;;
+    esac
   fi
 ])
 
diff --git a/modules/string b/modules/string
index 8fbcc542c5..acbd614dcd 100644
--- a/modules/string
+++ b/modules/string
@@ -125,6 +125,7 @@ string.h: string.in.h $(top_builddir)/config.status 
$(CXXDEFS_H) $(ARG_NONNULL_H
              -e 's|@''REPLACE_STRERROR_R''@|$(REPLACE_STRERROR_R)|g' \
              -e 's|@''REPLACE_STRERRORNAME_NP''@|$(REPLACE_STRERRORNAME_NP)|g' 
\
              -e 's|@''REPLACE_STRSIGNAL''@|$(REPLACE_STRSIGNAL)|g' \
+             -e 's|@''REPLACE_STRVERSCMP''@|$(REPLACE_STRVERSCMP)|g' \
              -e 's|@''UNDEFINE_STRTOK_R''@|$(UNDEFINE_STRTOK_R)|g' \
              -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \
              -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \
diff --git a/modules/strverscmp b/modules/strverscmp
index a80d1dd1d7..f4f76c7d0c 100644
--- a/modules/strverscmp
+++ b/modules/strverscmp
@@ -7,13 +7,14 @@ m4/strverscmp.m4
 
 Depends-on:
 extensions
-libc-config  [test $HAVE_STRVERSCMP = 0]
-stdint       [test $HAVE_STRVERSCMP = 0]
+libc-config  [test $HAVE_STRVERSCMP = 0 || test $REPLACE_STRVERSCMP = 1]
+stdint       [test $HAVE_STRVERSCMP = 0 || test $REPLACE_STRVERSCMP = 1]
 string
 
 configure.ac:
 gl_FUNC_STRVERSCMP
-gl_CONDITIONAL([GL_COND_OBJ_STRVERSCMP], [test $HAVE_STRVERSCMP = 0])
+gl_CONDITIONAL([GL_COND_OBJ_STRVERSCMP],
+               [test $HAVE_STRVERSCMP = 0 || test $REPLACE_STRVERSCMP = 1])
 AM_COND_IF([GL_COND_OBJ_STRVERSCMP], [
   gl_PREREQ_STRVERSCMP
 ])
diff --git a/tests/test-strverscmp.c b/tests/test-strverscmp.c
index a7fbcdb993..2706572bc6 100644
--- a/tests/test-strverscmp.c
+++ b/tests/test-strverscmp.c
@@ -30,6 +30,7 @@ main (void)
 {
   ASSERT (strverscmp ("", "") == 0);
   ASSERT (strverscmp ("a", "a") == 0);
+  ASSERT (strverscmp ("1.7", "1.7") == 0);
   ASSERT (strverscmp ("a", "b") < 0);
   ASSERT (strverscmp ("b", "a") > 0);
   ASSERT (strverscmp ("000", "00") < 0);
@@ -55,5 +56,13 @@ main (void)
     ASSERT (strverscmp (c, a) > 0);
   }
 
+  /* From Dmitry Bogatov.  */
+  {
+    static char const a[] = "UNKNOWN";
+    static char const b[] = "2.2.0";
+    ASSERT (strverscmp (a, b) > 0);
+    ASSERT (strverscmp (b, a) < 0);
+  }
+
   return 0;
 }




Reply via email to