* vasnwprintf: Fix test failures on musl libc
@ 2023-03-20 2:32 Bruno Haible
0 siblings, 0 replies; only message in thread
From: Bruno Haible @ 2023-03-20 2:32 UTC (permalink / raw)
To: bug-gnulib
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
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2023-03-20 2:33 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-03-20 2:32 vasnwprintf: Fix test failures on musl libc Bruno Haible
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).