+2023-11-14 Bruno Haible <bruno@clisp.org>
+
+ *printf-posix: Revert expectations of %lc of 0.
+ * m4/printf.m4 (gl_PRINTF_DIRECTIVE_LC): Expect a NUL byte in the
+ output.
+ * lib/vasnprintf.c (VASNPRINTF): In the %lc implementation, don't
+ special-case the NUL wide character.
+ * tests/test-vasnprintf-posix.c (test_function): Change expected result
+ for %lc of L'\0'.
+ * tests/test-vasprintf-posix.c (test_function): Likewise.
+ * tests/test-snprintf-posix.h (test_function): Likewise.
+ * tests/test-sprintf-posix.h (test_function): Likewise.
+ * doc/posix-functions/dprintf.texi: Update platform list regarding %lc
+ of 0 bug.
+ * doc/posix-functions/fprintf.texi: Likewise.
+ * doc/posix-functions/printf.texi: Likewise.
+ * doc/posix-functions/snprintf.texi: Likewise.
+ * doc/posix-functions/sprintf.texi: Likewise.
+ * doc/posix-functions/vdprintf.texi: Likewise.
+ * doc/posix-functions/vfprintf.texi: Likewise.
+ * doc/posix-functions/vprintf.texi: Likewise.
+ * doc/posix-functions/vsnprintf.texi: Likewise.
+ * doc/posix-functions/vsprintf.texi: Likewise.
+ * doc/glibc-functions/asprintf.texi: Likewise.
+ * doc/glibc-functions/vasprintf.texi: Likewise.
+ * doc/glibc-functions/obstack_printf.texi: Likewise.
+ * doc/glibc-functions/obstack_vprintf.texi: Likewise.
+
2023-11-13 Bruno Haible <bruno@clisp.org>
doc: Add a note.
@item
This function produces wrong output for the @samp{lc} directive with a NUL
wide character argument on some platforms:
-glibc 2.35, FreeBSD 13.1, NetBSD 9.0, OpenBSD 7.2, macOS 12.5, AIX 7.2, Solaris 11.4, and others.
+musl libc 1.2.4.
@item
This function can crash in out-of-memory conditions on some platforms:
FreeBSD 13.0, NetBSD 5.0.
@item
This function produces wrong output for the @samp{lc} directive with a NUL
wide character argument on some platforms:
-glibc 2.35, FreeBSD 13.1, NetBSD 9.0, OpenBSD 7.2, macOS 12.5, AIX 7.2, Solaris 11.4, and others.
+musl libc 1.2.4.
@item
This function can crash in out-of-memory conditions on some platforms:
FreeBSD 13.0, NetBSD 5.0.
@item
This function produces wrong output for the @samp{lc} directive with a NUL
wide character argument on some platforms:
-glibc 2.35, FreeBSD 13.1, NetBSD 9.0, OpenBSD 7.2, macOS 12.5, AIX 7.2, Solaris 11.4, and others.
+musl libc 1.2.4.
@item
This function can crash in out-of-memory conditions on some platforms:
FreeBSD 13.0, NetBSD 5.0.
@item
This function produces wrong output for the @samp{lc} directive with a NUL
wide character argument on some platforms:
-glibc 2.35, FreeBSD 13.1, NetBSD 9.0, OpenBSD 7.2, macOS 12.5, AIX 7.2, Solaris 11.4, and others.
+musl libc 1.2.4.
@item
This function can crash in out-of-memory conditions on some platforms:
FreeBSD 13.0, NetBSD 5.0.
@item
This function produces wrong output for the @samp{lc} directive with a NUL
wide character argument on some platforms:
-glibc 2.35, FreeBSD 13.1, NetBSD 9.0, OpenBSD 7.2, macOS 12.5, AIX 7.2, Solaris 11.4, and others.
+musl libc 1.2.4.
@end itemize
Portability problems fixed by Gnulib module @code{dprintf-gnu}:
@item
This function produces wrong output for the @samp{lc} directive with a NUL
wide character argument on some platforms:
-glibc 2.35, FreeBSD 13.1, NetBSD 9.0, OpenBSD 7.2, macOS 12.5, AIX 7.2, Solaris 11.4, and others.
+musl libc 1.2.4.
@item
This function can crash in out-of-memory conditions on some platforms:
FreeBSD 13.0, NetBSD 5.0.
@item
This function produces wrong output for the @samp{lc} directive with a NUL
wide character argument on some platforms:
-glibc 2.35, FreeBSD 13.1, NetBSD 9.0, OpenBSD 7.2, macOS 12.5, AIX 7.2, Solaris 11.4, and others.
+musl libc 1.2.4.
@item
This function can crash in out-of-memory conditions on some platforms:
FreeBSD 13.0, NetBSD 5.0.
@item
This function produces wrong output for the @samp{lc} directive with a NUL
wide character argument on some platforms:
-glibc 2.35, FreeBSD 13.1, NetBSD 9.0, OpenBSD 7.2, macOS 12.5, AIX 7.2, Solaris 11.4, and others.
+musl libc 1.2.4.
@item
This function can crash in out-of-memory conditions on some platforms:
FreeBSD 13.0, NetBSD 5.0.
@item
This function produces wrong output for the @samp{lc} directive with a NUL
wide character argument on some platforms:
-glibc 2.35, FreeBSD 13.1, NetBSD 9.0, OpenBSD 7.2, macOS 12.5, AIX 7.2, Solaris 11.4, and others.
+musl libc 1.2.4.
@item
This function can crash in out-of-memory conditions on some platforms:
FreeBSD 13.0, NetBSD 5.0.
@item
This function produces wrong output for the @samp{lc} directive with a NUL
wide character argument on some platforms:
-glibc 2.35, FreeBSD 13.1, NetBSD 9.0, OpenBSD 7.2, macOS 12.5, AIX 7.2, Solaris 11.4, and others.
+musl libc 1.2.4.
@end itemize
Portability problems fixed by Gnulib module @code{vdprintf-gnu}:
@item
This function produces wrong output for the @samp{lc} directive with a NUL
wide character argument on some platforms:
-glibc 2.35, FreeBSD 13.1, NetBSD 9.0, OpenBSD 7.2, macOS 12.5, AIX 7.2, Solaris 11.4, and others.
+musl libc 1.2.4.
@item
This function can crash in out-of-memory conditions on some platforms:
FreeBSD 13.0, NetBSD 5.0.
@item
This function produces wrong output for the @samp{lc} directive with a NUL
wide character argument on some platforms:
-glibc 2.35, FreeBSD 13.1, NetBSD 9.0, OpenBSD 7.2, macOS 12.5, AIX 7.2, Solaris 11.4, and others.
+musl libc 1.2.4.
@item
This function can crash in out-of-memory conditions on some platforms:
FreeBSD 13.0, NetBSD 5.0.
@item
This function produces wrong output for the @samp{lc} directive with a NUL
wide character argument on some platforms:
-glibc 2.35, FreeBSD 13.1, NetBSD 9.0, OpenBSD 7.2, macOS 12.5, AIX 7.2, Solaris 11.4, and others.
+musl libc 1.2.4.
@item
This function can crash in out-of-memory conditions on some platforms:
FreeBSD 13.0, NetBSD 5.0.
@item
This function produces wrong output for the @samp{lc} directive with a NUL
wide character argument on some platforms:
-glibc 2.35, FreeBSD 13.1, NetBSD 9.0, OpenBSD 7.2, macOS 12.5, AIX 7.2, Solaris 11.4, and others.
+musl libc 1.2.4.
@item
This function can crash in out-of-memory conditions on some platforms:
FreeBSD 13.0, NetBSD 5.0.
{
/* Count the number of bytes. */
characters = 0;
- if (arg != 0)
- {
- char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
- int count;
+ char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
+ int count;
# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
- mbstate_t state;
- mbszero (&state);
+ mbstate_t state;
+ mbszero (&state);
# endif
- count = local_wcrtomb (cbuf, arg, &state);
- if (count < 0)
- /* Cannot convert. */
- goto fail_with_EILSEQ;
- characters = count;
- }
+ count = local_wcrtomb (cbuf, arg, &state);
+ if (count < 0)
+ /* Cannot convert. */
+ goto fail_with_EILSEQ;
+ characters = count;
}
# if DCHAR_IS_TCHAR
else
# if !DCHAR_IS_TCHAR
/* Convert the string into a piece of temporary memory. */
- if (characters > 0) /* implies arg != 0 */
+ if (characters > 0)
{
char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
int count;
{
/* We know the number of bytes in advance. */
ENSURE_ALLOCATION (xsum (length, characters));
- if (characters > 0) /* implies arg != 0 */
+ if (characters > 0)
{
int count;
# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
}
else
{
- if (arg != 0)
- {
- char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
- int count;
+ char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
+ int count;
# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
- mbstate_t state;
- mbszero (&state);
+ mbstate_t state;
+ mbszero (&state);
# endif
- count = local_wcrtomb (cbuf, arg, &state);
- if (count < 0)
- /* Cannot convert. */
- goto fail_with_EILSEQ;
- ENSURE_ALLOCATION (xsum (length, count));
- memcpy (result + length, cbuf, count);
- length += count;
- }
+ count = local_wcrtomb (cbuf, arg, &state);
+ if (count < 0)
+ /* Cannot convert. */
+ goto fail_with_EILSEQ;
+ ENSURE_ALLOCATION (xsum (length, count));
+ memcpy (result + length, cbuf, count);
+ length += count;
}
# else
ENSURE_ALLOCATION_ELSE (xsum (length, tmpdst_len),
-# printf.m4 serial 87
+# printf.m4 serial 88
dnl Copyright (C) 2003, 2007-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,
dnl Test whether the *printf family of functions supports the %lc format
dnl directive and in particular, when the argument is a null wide character,
-dnl whether the functions don't produce a NUL byte.
+dnl whether the functions produce a NUL byte, as specified in ISO C 23
+dnl after the issue GB-141 was fixed.
dnl Result is gl_cv_func_printf_directive_lc.
AC_DEFUN([gl_PRINTF_DIRECTIVE_LC],
{
int result = 0;
char buf[100];
- /* This test fails on glibc 2.35, FreeBSD 13.1, NetBSD 9.0, OpenBSD 7.2,
- macOS 12.5, AIX 7.2, Solaris 11.4.
- glibc 2.35 bug: <https://sourceware.org/bugzilla/show_bug.cgi?id=30257> */
+ /* This test fails on musl libc 1.2.4. */
{
buf[0] = '\0';
if (sprintf (buf, "%lc%lc%lc", (wint_t) 'a', (wint_t) 0, (wint_t) 'z') < 0
- || strcmp (buf, "az") != 0)
+ || memcmp (buf, "a\0z", 4) != 0)
result |= 1;
}
return result;
[
changequote(,)dnl
case "$host_os" in
- # Guess yes on musl libc.
- *-musl* | midipix*) gl_cv_func_printf_directive_lc="guessing yes";;
- # Guess no otherwise.
- *) gl_cv_func_printf_directive_lc="guessing no";;
+ # Guess no on musl libc.
+ *-musl* | midipix*) gl_cv_func_printf_directive_lc="guessing no";;
+ # Guess yes otherwise.
+ *) gl_cv_func_printf_directive_lc="guessing yes";;
esac
changequote([,])dnl
])
dnl . = yes, # = no.
dnl
dnl 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
-dnl musl libc 1.2.3 . # . . . . # # . . . . . . . . ? . . . . . . . . # . #
-dnl glibc 2.35 . # . . . . . . . . . # . . . . . . . . . . . . . . . .
-dnl glibc 2.5 . # . . . . # # . . . # . . . . . . . . . . . . . . # .
-dnl glibc 2.3.6 . # . . . # # # . . . # . . . . . . . . . . . . . . # .
-dnl FreeBSD 13.0 . # . . . # # # . . . # . . . . . . # . . . . . . # . #
-dnl FreeBSD 5.4, 6.1 . # . . . # # # . . . # . . . # ? . # . . . . . . # ? ?
-dnl Mac OS X 10.13.5 . # . . # # # # . # . # . . . . . . . . . . # . . # ? ?
-dnl Mac OS X 10.5.8 . # . . # # # # . . . # . . . # # . . . . . . . . # ? ?
-dnl Mac OS X 10.3.9 . # . . . # # # . . . # . . . # # . # . . . . . . # ? ?
-dnl OpenBSD 6.0, 6.7 . # . . . # # # . . . # . . . . . . # . . . . . . # . #
-dnl OpenBSD 3.9, 4.0 . # . # # # # # # . # # . # . # ? . # . . . . . . # ? ?
+dnl musl libc 1.2.3 . # . . . . # # . . . # . . . . ? . . . . . . . . # . #
+dnl glibc 2.35 . # . . . . . . . . . . . . . . . . . . . . . . . . . .
+dnl glibc 2.5 . # . . . . # # . . . . . . . . . . . . . . . . . . # .
+dnl glibc 2.3.6 . # . . . # # # . . . . . . . . . . . . . . . . . . # .
+dnl FreeBSD 13.0 . # . . . # # # . . . . . . . . . . # . . . . . . # . #
+dnl FreeBSD 5.4, 6.1 . # . . . # # # . . . . . . . # ? . # . . . . . . # ? ?
+dnl Mac OS X 10.13.5 . # . . # # # # . # . . . . . . . . . . . . # . . # ? ?
+dnl Mac OS X 10.5.8 . # . . # # # # . . . . . . . # # . . . . . . . . # ? ?
+dnl Mac OS X 10.3.9 . # . . . # # # . . . . . . . # # . # . . . . . . # ? ?
+dnl OpenBSD 6.0, 6.7 . # . . . # # # . . . . . . . . . . # . . . . . . # . #
+dnl OpenBSD 3.9, 4.0 . # . # # # # # # . # . . # . # ? . # . . . . . . # ? ?
dnl Cygwin 1.7.0 (2009) . # . . # . # # . . ? ? . . . . ? . ? . . . . . . ? ? ?
dnl Cygwin 1.5.25 (2008) . # . . # # # # . . # ? . . . . ? . # . . . . . . ? ? ?
dnl Cygwin 1.5.19 (2006) # # . . # # # # # . # ? . # . # ? # # . . . . . . ? ? ?
-dnl Solaris 11.4 . # . # # # # # . . # # . . . # . . . . . . . . . . # .
-dnl Solaris 11.3 . # . . . # # # . . # # . . . . . . . . . . . . . . # .
-dnl Solaris 11.0 . # . # # # # # . . # # . . . # . . . . . . . . . ? ? ?
-dnl Solaris 10 . # . # # # # # . . # # . . . # . # . . . . . . . . # .
-dnl Solaris 2.6 ... 9 # # . # # # # # # . # # . . . # ? # . . . # . . . ? ? ?
-dnl Solaris 2.5.1 # # . # # # # # # . # # . . . # ? . . # # # # # # ? ? ?
-dnl AIX 7.1 . # . # # # # # . . . # . . . # . # . . . . . . . # . .
-dnl AIX 5.2 . # . # # # # # . . . # . . . # ? . . . . . . . . # ? ?
-dnl AIX 4.3.2, 5.1 # # . # # # # # # . . # . . . # ? . . . . # . . . # ? ?
+dnl Solaris 11.4 . # . # # # # # . . # . . . . # . . . . . . . . . . # .
+dnl Solaris 11.3 . # . . . # # # . . # . . . . . . . . . . . . . . . # .
+dnl Solaris 11.0 . # . # # # # # . . # . . . . # . . . . . . . . . ? ? ?
+dnl Solaris 10 . # . # # # # # . . # . . . . # . # . . . . . . . . # .
+dnl Solaris 2.6 ... 9 # # . # # # # # # . # . . . . # ? # . . . # . . . ? ? ?
+dnl Solaris 2.5.1 # # . # # # # # # . # . . . . # ? . . # # # # # # ? ? ?
+dnl AIX 7.1 . # . # # # # # . . . . . . . # . # . . . . . . . # . .
+dnl AIX 5.2 . # . # # # # # . . . . . . . # ? . . . . . . . . # ? ?
+dnl AIX 4.3.2, 5.1 # # . # # # # # # . . . . . . # ? . . . . # . . . # ? ?
dnl HP-UX 11.31 . # . . . # # # . . . ? . . . # ? . . . . # # . . ? ? ?
dnl HP-UX 11.{00,11,23} # # . . . # # # # . . ? . . . # ? . . . . # # . # ? ? ?
dnl HP-UX 10.20 # # . # . # # # # . ? ? . . # # ? . . . . # # ? # ? ? ?
-dnl IRIX 6.5 # # . # # # # # # . # # . . . # ? . . . . # . . . # ? ?
+dnl IRIX 6.5 # # . # # # # # # . # . . . . # ? . . . . # . . . # ? ?
dnl OSF/1 5.1 # # . # # # # # # . . ? . . . # ? . . . . # . . # ? ? ?
dnl OSF/1 4.0d # # . # # # # # # . . ? . . . # ? . . # # # # # # ? ? ?
-dnl NetBSD 9.0 . # . . . # # # . . . # . . . . . . . . . . . . . # . #
-dnl NetBSD 5.0 . # . . # # # # . . . # . . . # ? . # . . . . . . # ? ?
-dnl NetBSD 4.0 . # ? ? ? ? # # ? . ? # . ? ? ? ? ? ? . . . ? ? ? # ? ?
-dnl NetBSD 3.0 . # . . . # # # # . ? # # # ? # ? . # . . . . . . # ? ?
+dnl NetBSD 9.0 . # . . . # # # . . . . . . . . . . . . . . . . . # . #
+dnl NetBSD 5.0 . # . . # # # # . . . . . . . # ? . # . . . . . . # ? ?
+dnl NetBSD 4.0 . # ? ? ? ? # # ? . ? . . ? ? ? ? ? ? . . . ? ? ? # ? ?
+dnl NetBSD 3.0 . # . . . # # # # . ? . # # ? # ? . # . . . . . . # ? ?
dnl Haiku . # . . # # # # # . # ? . . . . ? . ? . . ? . . . . # .
dnl BeOS # # # . # # # # # . ? ? # . ? . ? # ? . . ? . . . ? ? ?
dnl Android 4.3 . # . # # # # # # # # ? . # . # ? . # . . . # . . ? ? ?
int retval =
my_snprintf (result, sizeof (result),
"a%lcz %d", (wint_t) L'\0', 33, 44, 55);
- /* No NUL byte between 'a' and 'z'. This is surprising, but is a
- consequence of how POSIX:2018 and ISO C 23 specify the handling
- of %lc. */
- ASSERT (memcmp (result, "az 33\0", 5 + 1) == 0);
- ASSERT (retval == 5);
+ /* ISO C had this wrong for decades. ISO C 23 now corrects it, through
+ this wording:
+ "If an l length modifier is present, the wint_t argument is converted
+ as if by a call to the wcrtomb function with a pointer to storage of
+ at least MB_CUR_MAX bytes, the wint_t argument converted to wchar_t,
+ and an initial shift state." */
+ ASSERT (memcmp (result, "a\0z 33\0", 6 + 1) == 0);
+ ASSERT (retval == 6);
}
static wint_t L_invalid = (wchar_t) 0x76543210;
{ /* NUL character. */
int retval =
my_sprintf (result, "a%lcz %d", (wint_t) L'\0', 33, 44, 55);
- /* No NUL byte between 'a' and 'z'. This is surprising, but is a
- consequence of how POSIX:2018 and ISO C 23 specify the handling
- of %lc. */
- ASSERT (memcmp (result, "az 33\0", 5 + 1) == 0);
- ASSERT (retval == 5);
+ /* ISO C had this wrong for decades. ISO C 23 now corrects it, through
+ this wording:
+ "If an l length modifier is present, the wint_t argument is converted
+ as if by a call to the wcrtomb function with a pointer to storage of
+ at least MB_CUR_MAX bytes, the wint_t argument converted to wchar_t,
+ and an initial shift state." */
+ ASSERT (memcmp (result, "a\0z 33\0", 6 + 1) == 0);
+ ASSERT (retval == 6);
}
static wint_t L_invalid = (wchar_t) 0x76543210;
size_t length;
char *result =
my_asnprintf (NULL, &length, "a%lcz %d", (wint_t) L'\0', 33, 44, 55);
- /* No NUL byte between 'a' and 'z'. This is surprising, but is a
- consequence of how POSIX:2018 and ISO C 23 specify the handling
- of %lc. */
- ASSERT (memcmp (result, "az 33\0", 5 + 1) == 0);
- ASSERT (length == 5);
+ /* ISO C had this wrong for decades. ISO C 23 now corrects it, through
+ this wording:
+ "If an l length modifier is present, the wint_t argument is converted
+ as if by a call to the wcrtomb function with a pointer to storage of
+ at least MB_CUR_MAX bytes, the wint_t argument converted to wchar_t,
+ and an initial shift state." */
+ ASSERT (memcmp (result, "a\0z 33\0", 6 + 1) == 0);
+ ASSERT (length == 6);
free (result);
}
char *result;
int retval =
my_asprintf (&result, "a%lcz %d", (wint_t) L'\0', 33, 44, 55);
- /* No NUL byte between 'a' and 'z'. This is surprising, but is a
- consequence of how POSIX:2018 and ISO C 23 specify the handling
- of %lc. */
- ASSERT (memcmp (result, "az 33\0", 5 + 1) == 0);
- ASSERT (retval == 5);
+ /* ISO C had this wrong for decades. ISO C 23 now corrects it, through
+ this wording:
+ "If an l length modifier is present, the wint_t argument is converted
+ as if by a call to the wcrtomb function with a pointer to storage of
+ at least MB_CUR_MAX bytes, the wint_t argument converted to wchar_t,
+ and an initial shift state." */
+ ASSERT (memcmp (result, "a\0z 33\0", 6 + 1) == 0);
+ ASSERT (retval == 6);
free (result);
}