summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog12
-rw-r--r--lib/vasnprintf.c12
-rw-r--r--tests/test-snprintf-posix.h18
-rw-r--r--tests/test-sprintf-posix.h16
-rw-r--r--tests/test-vasnprintf-posix.c18
-rw-r--r--tests/test-vasnwprintf-posix.c29
-rw-r--r--tests/test-vasprintf-posix.c20
7 files changed, 119 insertions, 6 deletions
diff --git a/ChangeLog b/ChangeLog
index eea37f348e..e696a7eba6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,17 @@
2023-04-01 Bruno Haible <bruno@clisp.org>
+ 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 <bruno@clisp.org>
+
stddef: Fix __need_wint_t handling in case of two stddef.h overrides.
* lib/stddef.in.h: Replace _GL_STDDEF_WINT_T with a symbol that depends
on the @GUARD_PREFIX@.
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