bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

vasnwprintf: Fix test failures on musl libc


From: Bruno Haible
Subject: vasnwprintf: Fix test failures on musl libc
Date: Mon, 20 Mar 2023 03:32:50 +0100

On musl libc, test-vasnwprintf-posix fails. This is due to two musl libc bugs:
  https://www.openwall.com/lists/musl/2023/03/19/1
  https://www.openwall.com/lists/musl/2023/03/20/1

As a workaround, on this platform, vasnwprintf needs to
  - avoid %n,
  - do the padding itself, instead of leaving it to the swprintf primitive.


2023-03-19  Bruno Haible  <bruno@clisp.org>

        vasnwprintf: Fix test failures on musl libc.
        * m4/vasnprintf.m4 (gl_PREREQ_VASNWPRINTF): Invoke gl_MUSL_LIBC.
        * lib/vasnprintf.c (VASNPRINTF): On musl libc, when WIDE_CHAR_VERSION,
        - force pad_ourselves to be 1,
        - don't use %n.
        Fix zero-padding when the result starts with a prefix "0x" or "0b".
        * modules/vasnwprintf (Files): Add musl.m4.
        * doc/posix-functions/swprintf.texi: Mention two musl libc bugs.

diff --git a/doc/posix-functions/swprintf.texi 
b/doc/posix-functions/swprintf.texi
index 906ee521aa..a87bc06c86 100644
--- a/doc/posix-functions/swprintf.texi
+++ b/doc/posix-functions/swprintf.texi
@@ -26,11 +26,21 @@
 glibc when used with @code{_FORTIFY_SOURCE >= 2} (set by default on Ubuntu),
 macOS 11.1, MSVC 14.
 @item
+This function sometimes returns a wrong value through the @samp{n} directive
+on some platforms:
+@c https://www.openwall.com/lists/musl/2023/03/19/1
+musl libc 1.2.3.
+@item
 On Windows and 32-bit AIX platforms, @code{wchar_t} is a 16-bit type and 
therefore cannot
 accommodate all Unicode characters.
 @item
 On Windows, this function does not take a buffer size as second argument.
 @item
+This function ignores the minimum field width in the @samp{lc} directive
+on some platforms:
+@c https://www.openwall.com/lists/musl/2023/03/20/1
+musl libc 1.2.3.
+@item
 This function does not support the @samp{b} directive, required by ISO C23,
 on some platforms:
 glibc 2.34, musl libc, macOS 12.5, FreeBSD 13.1, NetBSD 9.0, OpenBSD 7.2,
diff --git a/lib/vasnprintf.c b/lib/vasnprintf.c
index c2f10cb0c4..50ff2e64dd 100644
--- a/lib/vasnprintf.c
+++ b/lib/vasnprintf.c
@@ -4932,7 +4932,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
               {
                 arg_type type = a.arg[dp->arg_index].type;
                 int flags = dp->flags;
-#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || 
NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
+#if (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || 
NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || 
NEED_PRINTF_UNBOUNDED_PRECISION
                 int has_width;
 #endif
 #if !USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || 
USE_MSVC__SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || 
NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || 
NEED_PRINTF_UNBOUNDED_PRECISION
@@ -4947,7 +4947,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
 #else
 #               define prec_ourselves 0
 #endif
-#if NEED_PRINTF_FLAG_LEFTADJUST
+#if (WIDE_CHAR_VERSION && MUSL_LIBC) || NEED_PRINTF_FLAG_LEFTADJUST
 #               define pad_ourselves 1
 #elif !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || 
NEED_PRINTF_UNBOUNDED_PRECISION
                 int pad_ourselves;
@@ -4964,7 +4964,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                 TCHAR_T *tmp;
 #endif
 
-#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || 
NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
+#if (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || 
NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || 
NEED_PRINTF_UNBOUNDED_PRECISION
                 has_width = 0;
 #endif
 #if !USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || 
USE_MSVC__SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || 
NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || 
NEED_PRINTF_UNBOUNDED_PRECISION
@@ -4995,7 +4995,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                           width = xsum (xtimes (width, 10), *digitp++ - '0');
                         while (digitp != dp->width_end);
                       }
-#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || 
NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
+#if (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || 
NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || 
NEED_PRINTF_UNBOUNDED_PRECISION
                     has_width = 1;
 #endif
                   }
@@ -5050,7 +5050,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
 #endif
 
                 /* Decide whether to perform the padding ourselves.  */
-#if !NEED_PRINTF_FLAG_LEFTADJUST && (!DCHAR_IS_TCHAR || ENABLE_UNISTDIO || 
NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION)
+#if !((WIDE_CHAR_VERSION && MUSL_LIBC) || NEED_PRINTF_FLAG_LEFTADJUST) && 
(!DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || 
NEED_PRINTF_UNBOUNDED_PRECISION)
                 switch (dp->conversion)
                   {
 # if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO
@@ -5210,7 +5210,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
       || (defined __APPLE__ && defined __MACH__)                            \
       || defined __OpenBSD__                                                \
       || defined __ANDROID__                                                \
-      || (defined _WIN32 && ! defined __CYGWIN__))
+      || (defined _WIN32 && ! defined __CYGWIN__))                          \
+      || (WIDE_CHAR_VERSION && MUSL_LIBC)
                 /* We can avoid passing %n and instead rely on SNPRINTF's
                    return value if
                      - !WIDE_CHAR_VERSION, because if WIDE_CHAR_VERSION,
@@ -5263,6 +5264,9 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                      - Although the gl_SNPRINTF_RETVAL_C99 test fails, snprintf
                        allows us to recognize the case of an insufficient
                        buffer size: it returns -1 in this case.  */
+                /* Additionally, in the WIDE_CHAR_VERSION case, we cannot use 
%n
+                   on musl libc because we would run into an swprintf() bug.
+                   See <https://www.openwall.com/lists/musl/2023/03/19/1>.  */
                 fbp[1] = '\0';
 # else           /* AIX <= 5.1, HP-UX, IRIX, OSF/1, Solaris <= 9, BeOS */
                 fbp[1] = '%';
@@ -5768,7 +5772,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                     /* Here count <= allocated - length.  */
 
                     /* Perform padding.  */
-#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || 
NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
+#if (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || 
NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || 
NEED_PRINTF_UNBOUNDED_PRECISION
                     if (pad_ourselves && has_width)
                       {
                         size_t w;
@@ -5827,6 +5831,22 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                                   if ((*pad_ptr >= 'A' && *pad_ptr <= 'Z')
                                       || (*pad_ptr >= 'a' && *pad_ptr <= 'z'))
                                     pad_ptr = NULL;
+                                  else
+                                    /* Do the zero-padding after the "0x" or
+                                       "0b" prefix, not before.  */
+                                    if (p - rp >= 2
+                                        && *rp == '0'
+                                        && (((dp->conversion == 'a'
+                                              || dp->conversion == 'x')
+                                             && rp[1] == 'x')
+                                            || ((dp->conversion == 'A'
+                                                 || dp->conversion == 'X')
+                                                && rp[1] == 'X')
+                                            || (dp->conversion == 'b'
+                                                && rp[1] == 'b')
+                                            || (dp->conversion == 'B'
+                                                && rp[1] == 'B')))
+                                      pad_ptr += 2;
                                 }
                               /* The generated string now extends from rp to p,
                                  with the zero padding insertion point being at
diff --git a/m4/vasnprintf.m4 b/m4/vasnprintf.m4
index b868aed08b..8e582dd791 100644
--- a/m4/vasnprintf.m4
+++ b/m4/vasnprintf.m4
@@ -1,4 +1,4 @@
-# vasnprintf.m4 serial 41
+# vasnprintf.m4 serial 42
 dnl Copyright (C) 2002-2004, 2006-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,
@@ -96,6 +96,7 @@ AC_DEFUN_ONCE([gl_PREREQ_VASNWPRINTF]
 [
   AC_CHECK_FUNCS([wcsnlen mbrtowc])
   AC_CHECK_DECLS([_snwprintf], , , [[#include <stdio.h>]])
+  gl_MUSL_LIBC
   gl_PREREQ_VASNXPRINTF
 ])
 
diff --git a/modules/vasnwprintf b/modules/vasnwprintf
index 6c7d63a5f6..07a078696c 100644
--- a/modules/vasnwprintf
+++ b/modules/vasnwprintf
@@ -21,6 +21,7 @@ m4/vasnprintf.m4
 m4/printf.m4
 m4/math_h.m4
 m4/exponentd.m4
+m4/musl.m4
 
 Depends-on:
 stdio






reply via email to

[Prev in Thread] Current Thread [Next in Thread]