From 154a389b7cc0654a4fbec0faf4f0ddc3e89a947a Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Sat, 1 Apr 2023 11:45:23 +0200 Subject: [PATCH] vasnprintf-posix: Fix crash in narrow %lc directive (regr. 2023-03-21). * lib/vasnprintf.c (VASNPRINTF): Negative results of local_wcrtomb can now occur; handle them. * tests/test-vasnprintf-posix.c (test_function): Test %lc directive with a wint_t argument that is not a valid wide character. * tests/test-snprintf-posix.h (test_function): Likewise. * tests/test-sprintf-posix.h (test_function): Likewise. * tests/test-vasnwprintf-posix.c (test_function): Likewise. * tests/test-vasprintf-posix.c (test_function): Likewise. --- ChangeLog | 12 ++++++++++++ lib/vasnprintf.c | 12 ++++++------ tests/test-snprintf-posix.h | 18 ++++++++++++++++++ tests/test-sprintf-posix.h | 16 ++++++++++++++++ tests/test-vasnprintf-posix.c | 18 ++++++++++++++++++ tests/test-vasnwprintf-posix.c | 29 +++++++++++++++++++++++++++++ tests/test-vasprintf-posix.c | 20 ++++++++++++++++++++ 7 files changed, 119 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index eea37f348e..e696a7eba6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2023-04-01 Bruno Haible + + vasnprintf-posix: Fix crash in narrow %lc directive (regr. 2023-03-21). + * lib/vasnprintf.c (VASNPRINTF): Negative results of local_wcrtomb can + now occur; handle them. + * tests/test-vasnprintf-posix.c (test_function): Test %lc directive with + a wint_t argument that is not a valid wide character. + * tests/test-snprintf-posix.h (test_function): Likewise. + * tests/test-sprintf-posix.h (test_function): Likewise. + * tests/test-vasnwprintf-posix.c (test_function): Likewise. + * tests/test-vasprintf-posix.c (test_function): Likewise. + 2023-04-01 Bruno Haible stddef: Fix __need_wint_t handling in case of two stddef.h overrides. diff --git a/lib/vasnprintf.c b/lib/vasnprintf.c index 8ffab85995..90e52d8a96 100644 --- a/lib/vasnprintf.c +++ b/lib/vasnprintf.c @@ -3418,8 +3418,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, count = local_wcrtomb (cbuf, arg, &state); if (count < 0) - /* Inconsistency. */ - abort (); + /* Cannot convert. */ + goto fail_with_EILSEQ; characters = count; } } @@ -3517,9 +3517,9 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, # endif count = local_wcrtomb (cbuf, arg, &state); - if (count <= 0) - /* Inconsistency. */ - abort (); + if (count < 0) + /* Cannot convert. */ + goto fail_with_EILSEQ; ENSURE_ALLOCATION (xsum (length, count)); memcpy (result + length, cbuf, count); length += count; @@ -6816,7 +6816,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, errno = ENOMEM; goto fail_with_errno; -#if ENABLE_UNISTDIO || ((!USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_DIRECTIVE_LS || ENABLE_WCHAR_FALLBACK) && HAVE_WCHAR_T) +#if ENABLE_UNISTDIO || ((!USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_DIRECTIVE_LS || ENABLE_WCHAR_FALLBACK) && HAVE_WCHAR_T) || ((NEED_PRINTF_DIRECTIVE_LC || ENABLE_WCHAR_FALLBACK) && HAVE_WINT_T && !WIDE_CHAR_VERSION) fail_with_EILSEQ: errno = EILSEQ; goto fail_with_errno; diff --git a/tests/test-snprintf-posix.h b/tests/test-snprintf-posix.h index bfc8b9914e..90fcf61c5a 100644 --- a/tests/test-snprintf-posix.h +++ b/tests/test-snprintf-posix.h @@ -3089,6 +3089,24 @@ test_function (int (*my_snprintf) (char *, size_t, const char *, ...)) ASSERT (memcmp (result, "az 33\0", 5 + 1) == 0); ASSERT (retval == 5); } + + static wint_t L_invalid = (wchar_t) 0x76543210; + + { /* Invalid wide character. + The conversion may succeed or may fail, but it should not abort. */ + int retval = + my_snprintf (result, sizeof (result), + "%lc %d", L_invalid, 33, 44, 55); + (void) retval; + } + + { /* Invalid wide character and width. + The conversion may succeed or may fail, but it should not abort. */ + int retval = + my_snprintf (result, sizeof (result), + "%10lc %d", L_invalid, 33, 44, 55); + (void) retval; + } #endif /* Test the support of the 'x' conversion specifier for hexadecimal output of diff --git a/tests/test-sprintf-posix.h b/tests/test-sprintf-posix.h index d2f0e579ea..6ea2052186 100644 --- a/tests/test-sprintf-posix.h +++ b/tests/test-sprintf-posix.h @@ -3067,6 +3067,22 @@ test_function (int (*my_sprintf) (char *, const char *, ...)) ASSERT (memcmp (result, "az 33\0", 5 + 1) == 0); ASSERT (retval == 5); } + + static wint_t L_invalid = (wchar_t) 0x76543210; + + { /* Invalid wide character. + The conversion may succeed or may fail, but it should not abort. */ + int retval = + my_sprintf (result, "%lc %d", L_invalid, 33, 44, 55); + (void) retval; + } + + { /* Invalid wide character and width. + The conversion may succeed or may fail, but it should not abort. */ + int retval = + my_sprintf (result, "%10lc %d", L_invalid, 33, 44, 55); + (void) retval; + } #endif /* Test the support of the 'x' conversion specifier for hexadecimal output of diff --git a/tests/test-vasnprintf-posix.c b/tests/test-vasnprintf-posix.c index bc71e02156..9eb042c552 100644 --- a/tests/test-vasnprintf-posix.c +++ b/tests/test-vasnprintf-posix.c @@ -4015,6 +4015,24 @@ test_function (char * (*my_asnprintf) (char *, size_t *, const char *, ...)) ASSERT (length == 5); free (result); } + + static wint_t L_invalid = (wchar_t) 0x76543210; + + { /* Invalid wide character. + The conversion may succeed or may fail, but it should not abort. */ + size_t length; + char *result = + my_asnprintf (NULL, &length, "%lc %d", L_invalid, 33, 44, 55); + free (result); + } + + { /* Invalid wide character and width. + The conversion may succeed or may fail, but it should not abort. */ + size_t length; + char *result = + my_asnprintf (NULL, &length, "%10lc %d", L_invalid, 33, 44, 55); + free (result); + } #endif /* Test the support of the 'x' conversion specifier for hexadecimal output of diff --git a/tests/test-vasnwprintf-posix.c b/tests/test-vasnwprintf-posix.c index f0ecfb082a..74a26079d3 100644 --- a/tests/test-vasnwprintf-posix.c +++ b/tests/test-vasnwprintf-posix.c @@ -4020,6 +4020,35 @@ test_function (wchar_t * (*my_asnwprintf) (wchar_t *, size_t *, const wchar_t *, ASSERT (length == 6); free (result); } + + static wint_t L_invalid = (wchar_t) 0x76543210; + + { /* Invalid wide character. */ + size_t length; + wchar_t *result = + my_asnwprintf (NULL, &length, L"%lc %d", L_invalid, 33, 44, 55); + /* No failure is allowed: ISO C says "the wint_t argument is converted + to wchar_t and written." */ + ASSERT (result != NULL); + ASSERT (result[0] == (wchar_t) 0x76543210); + ASSERT (wmemcmp (result + 1, L" 33\0", 3 + 1) == 0); + ASSERT (length == 4); + free (result); + } + + { /* Invalid wide character and width. */ + size_t length; + wchar_t *result = + my_asnwprintf (NULL, &length, L"%10lc %d", L_invalid, 33, 44, 55); + /* No failure is allowed: ISO C says "the wint_t argument is converted + to wchar_t and written." */ + ASSERT (result != NULL); + ASSERT (wmemcmp (result, L" ", 9) == 0); + ASSERT (result[9] == (wchar_t) 0x76543210); + ASSERT (wmemcmp (result + 10, L" 33\0", 3 + 1) == 0); + ASSERT (length == 13); + free (result); + } #endif /* Test the support of the 'x' conversion specifier for hexadecimal output of diff --git a/tests/test-vasprintf-posix.c b/tests/test-vasprintf-posix.c index 6a18413abb..e4cc0fb983 100644 --- a/tests/test-vasprintf-posix.c +++ b/tests/test-vasprintf-posix.c @@ -3954,6 +3954,26 @@ test_function (int (*my_asprintf) (char **, const char *, ...)) ASSERT (retval == 5); free (result); } + + static wint_t L_invalid = (wchar_t) 0x76543210; + + { /* Invalid wide character. + The conversion may succeed or may fail, but it should not abort. */ + char *result; + int retval = + my_asprintf (&result, "%lc %d", L_invalid, 33, 44, 55); + if (retval >= 0) + free (result); + } + + { /* Invalid wide character and width. + The conversion may succeed or may fail, but it should not abort. */ + char *result; + int retval = + my_asprintf (&result, "%10lc %d", L_invalid, 33, 44, 55); + if (retval >= 0) + free (result); + } #endif /* Test the support of the 'x' conversion specifier for hexadecimal output of -- 2.39.5