vasnprintf-posix: Fix crash in narrow %lc directive (regr. 2023-03-21).
authorBruno Haible <bruno@clisp.org>
Sat, 1 Apr 2023 09:45:23 +0000 (11:45 +0200)
committerBruno Haible <bruno@clisp.org>
Sat, 1 Apr 2023 09:45:23 +0000 (11:45 +0200)
* 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
lib/vasnprintf.c
tests/test-snprintf-posix.h
tests/test-sprintf-posix.h
tests/test-vasnprintf-posix.c
tests/test-vasnwprintf-posix.c
tests/test-vasprintf-posix.c

index eea37f348e40a11b93a79bb889f7d80e015ee999..e696a7eba6b4375dbe6fd7da6412fcc7b7c0a942 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+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.
index 8ffab85995e36c8c63def4f672d0bc382c5d4726..90e52d8a96b3066eb9a6b9995c165e3da1a1d1fd 100644 (file)
@@ -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;
index bfc8b9914eb6759e4448b9d6e2356ec8cfaeb50a..90fcf61c5affe1e030ebf1c7b5fd808b5c516929 100644 (file)
@@ -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
index d2f0e579eace94e66e5b316743b8627e98b33b4c..6ea2052186d1a86e580239b6d783923caa0bcd20 100644 (file)
@@ -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
index bc71e02156b57a72e3970ce1fd8c90e8e128229a..9eb042c552623accc61c210935797419ef3e3ed6 100644 (file)
@@ -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
index f0ecfb082ac40c574bd67bbb25c91507e80eed43..74a26079d324454c061f70693aeb77230380a736 100644 (file)
@@ -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
index 6a18413abb187ea3fdc2e60ed3900a87618b174e..e4cc0fb9830d63f4b7e13021a43391f7aa1b9d10 100644 (file)
@@ -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