bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

vasnprintf-posix: Fix negative width handling for %ls directive


From: Bruno Haible
Subject: vasnprintf-posix: Fix negative width handling for %ls directive
Date: Sat, 28 Jan 2023 18:54:01 +0100

When I
  1. add some unit tests for width given as argument,
  2. create a testdir for the modules
       vasnprintf-posix vasprintf-posix snprintf-posix sprintf-posix
  3. build this testdir on one of these platforms:
       - Solaris 11.4
       - Solaris 9
       - MSVC 14
       - a glibc system with the environment variable settings
         gl_cv_func_snprintf_retval_c99=no gl_cv_func_printf_directive_ls=no

I get a test failure in each of the corresponding tests.

The cause is that FLAG_LEFT is set in the 'flags' variable, but the code
is looking for it in 'dp->flags'.


2023-01-28  Bruno Haible  <bruno@clisp.org>

        vasnprintf-posix: Fix negative width handling for %ls directive.
        Reported by clang via Po Lu <luangruo@yahoo.com>.
        * lib/vasnprintf.c (VASNPRINTF): In the code for %ls in vasnprintf and
        for %s in vasnwprintf, test for the FLAG_LEFT bit in the flags variable.
        * tests/test-vasnprintf-posix.c (test_function): Add tests for width
        given as argument for the directives %s, %ls.
        * tests/test-vasprintf-posix.c (test_function): Likewise.
        * tests/test-snprintf-posix.h (test_function): Likewise.
        * tests/test-sprintf-posix.h (test_function): Likewise.

diff --git a/lib/vasnprintf.c b/lib/vasnprintf.c
index 277c39e3e0..5ab8edbab7 100644
--- a/lib/vasnprintf.c
+++ b/lib/vasnprintf.c
@@ -2551,7 +2551,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                       characters = 0;
                     }
 
-                  if (characters < width && !(dp->flags & FLAG_LEFT))
+                  if (characters < width && !(flags & FLAG_LEFT))
                     {
                       size_t n = width - characters;
                       ENSURE_ALLOCATION (xsum (length, n));
@@ -2612,7 +2612,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                         }
                     }
 
-                  if (characters < width && (dp->flags & FLAG_LEFT))
+                  if (characters < width && (flags & FLAG_LEFT))
                     {
                       size_t n = width - characters;
                       ENSURE_ALLOCATION (xsum (length, n));
@@ -2768,7 +2768,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                     /* w doesn't matter.  */
                     w = 0;
 
-                  if (w < width && !(dp->flags & FLAG_LEFT))
+                  if (w < width && !(flags & FLAG_LEFT))
                     {
                       size_t n = width - w;
                       ENSURE_ALLOCATION (xsum (length, n));
@@ -2836,7 +2836,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                   length += tmpdst_len;
 #  endif
 
-                  if (w < width && (dp->flags & FLAG_LEFT))
+                  if (w < width && (flags & FLAG_LEFT))
                     {
                       size_t n = width - w;
                       ENSURE_ALLOCATION (xsum (length, n));
diff --git a/tests/test-snprintf-posix.h b/tests/test-snprintf-posix.h
index 42662a498e..e5c1d3f89d 100644
--- a/tests/test-snprintf-posix.h
+++ b/tests/test-snprintf-posix.h
@@ -2886,6 +2886,66 @@ test_function (int (*my_snprintf) (char *, size_t, const 
char *, ...))
 
   /* Test the support of the %s format directive.  */
 
+  { /* Width.  */
+    int retval =
+      my_snprintf (result, sizeof (result), "%10s %d", "xyz", 33, 44, 55);
+    ASSERT (strcmp (result, "       xyz 33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
+  { /* Width given as argument.  */
+    int retval =
+      my_snprintf (result, sizeof (result), "%*s %d", 10, "xyz", 33, 44, 55);
+    ASSERT (strcmp (result, "       xyz 33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
+  { /* Negative width given as argument (cf. FLAG_LEFT below).  */
+    int retval =
+      my_snprintf (result, sizeof (result), "%*s %d", -10, "xyz", 33, 44, 55);
+    ASSERT (strcmp (result, "xyz        33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
+  { /* FLAG_LEFT.  */
+    int retval =
+      my_snprintf (result, sizeof (result), "%-10s %d", "xyz", 33, 44, 55);
+    ASSERT (strcmp (result, "xyz        33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
+#if HAVE_WCHAR_T
+  static wchar_t L_xyz[4] = { 'x', 'y', 'z', 0 };
+
+  { /* Width.  */
+    int retval =
+      my_snprintf (result, sizeof (result), "%10ls %d", L_xyz, 33, 44, 55);
+    ASSERT (strcmp (result, "       xyz 33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
+  { /* Width given as argument.  */
+    int retval =
+      my_snprintf (result, sizeof (result), "%*ls %d", 10, L_xyz, 33, 44, 55);
+    ASSERT (strcmp (result, "       xyz 33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
+  { /* Negative width given as argument (cf. FLAG_LEFT below).  */
+    int retval =
+      my_snprintf (result, sizeof (result), "%*ls %d", -10, L_xyz, 33, 44, 55);
+    ASSERT (strcmp (result, "xyz        33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
+  { /* FLAG_LEFT.  */
+    int retval =
+      my_snprintf (result, sizeof (result), "%-10ls %d", L_xyz, 33, 44, 55);
+    ASSERT (strcmp (result, "xyz        33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+#endif
+
   /* To verify that these tests succeed, it is necessary to run them under
      a tool that checks against invalid memory accesses, such as ElectricFence
      or "valgrind --tool=memcheck".  */
diff --git a/tests/test-sprintf-posix.h b/tests/test-sprintf-posix.h
index 3b54cabd64..011df3b46a 100644
--- a/tests/test-sprintf-posix.h
+++ b/tests/test-sprintf-posix.h
@@ -2872,6 +2872,66 @@ test_function (int (*my_sprintf) (char *, const char *, 
...))
 
   /* Test the support of the %s format directive.  */
 
+  { /* Width.  */
+    int retval =
+      my_sprintf (result, "%10s %d", "xyz", 33, 44, 55);
+    ASSERT (strcmp (result, "       xyz 33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
+  { /* Width given as argument.  */
+    int retval =
+      my_sprintf (result, "%*s %d", 10, "xyz", 33, 44, 55);
+    ASSERT (strcmp (result, "       xyz 33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
+  { /* Negative width given as argument (cf. FLAG_LEFT below).  */
+    int retval =
+      my_sprintf (result, "%*s %d", -10, "xyz", 33, 44, 55);
+    ASSERT (strcmp (result, "xyz        33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
+  { /* FLAG_LEFT.  */
+    int retval =
+      my_sprintf (result, "%-10s %d", "xyz", 33, 44, 55);
+    ASSERT (strcmp (result, "xyz        33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
+#if HAVE_WCHAR_T
+  static wchar_t L_xyz[4] = { 'x', 'y', 'z', 0 };
+
+  { /* Width.  */
+    int retval =
+      my_sprintf (result, "%10ls %d", L_xyz, 33, 44, 55);
+    ASSERT (strcmp (result, "       xyz 33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
+  { /* Width given as argument.  */
+    int retval =
+      my_sprintf (result, "%*ls %d", 10, L_xyz, 33, 44, 55);
+    ASSERT (strcmp (result, "       xyz 33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
+  { /* Negative width given as argument (cf. FLAG_LEFT below).  */
+    int retval =
+      my_sprintf (result, "%*ls %d", -10, L_xyz, 33, 44, 55);
+    ASSERT (strcmp (result, "xyz        33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+
+  { /* FLAG_LEFT.  */
+    int retval =
+      my_sprintf (result, "%-10ls %d", L_xyz, 33, 44, 55);
+    ASSERT (strcmp (result, "xyz        33") == 0);
+    ASSERT (retval == strlen (result));
+  }
+#endif
+
   /* To verify that these tests succeed, it is necessary to run them under
      a tool that checks against invalid memory accesses, such as ElectricFence
      or "valgrind --tool=memcheck".  */
diff --git a/tests/test-vasnprintf-posix.c b/tests/test-vasnprintf-posix.c
index 6c81c7c5f4..93d2bc5a38 100644
--- a/tests/test-vasnprintf-posix.c
+++ b/tests/test-vasnprintf-posix.c
@@ -3711,6 +3711,90 @@ test_function (char * (*my_asnprintf) (char *, size_t *, 
const char *, ...))
 
   /* Test the support of the %s format directive.  */
 
+  { /* Width.  */
+    size_t length;
+    char *result =
+      my_asnprintf (NULL, &length, "%10s %d", "xyz", 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "       xyz 33") == 0);
+    ASSERT (length == strlen (result));
+    free (result);
+  }
+
+  { /* Width given as argument.  */
+    size_t length;
+    char *result =
+      my_asnprintf (NULL, &length, "%*s %d", 10, "xyz", 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "       xyz 33") == 0);
+    ASSERT (length == strlen (result));
+    free (result);
+  }
+
+  { /* Negative width given as argument (cf. FLAG_LEFT below).  */
+    size_t length;
+    char *result =
+      my_asnprintf (NULL, &length, "%*s %d", -10, "xyz", 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "xyz        33") == 0);
+    ASSERT (length == strlen (result));
+    free (result);
+  }
+
+  { /* FLAG_LEFT.  */
+    size_t length;
+    char *result =
+      my_asnprintf (NULL, &length, "%-10s %d", "xyz", 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "xyz        33") == 0);
+    ASSERT (length == strlen (result));
+    free (result);
+  }
+
+#if HAVE_WCHAR_T
+  static wchar_t L_xyz[4] = { 'x', 'y', 'z', 0 };
+
+  { /* Width.  */
+    size_t length;
+    char *result =
+      my_asnprintf (NULL, &length, "%10ls %d", L_xyz, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "       xyz 33") == 0);
+    ASSERT (length == strlen (result));
+    free (result);
+  }
+
+  { /* Width given as argument.  */
+    size_t length;
+    char *result =
+      my_asnprintf (NULL, &length, "%*ls %d", 10, L_xyz, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "       xyz 33") == 0);
+    ASSERT (length == strlen (result));
+    free (result);
+  }
+
+  { /* Negative width given as argument (cf. FLAG_LEFT below).  */
+    size_t length;
+    char *result =
+      my_asnprintf (NULL, &length, "%*ls %d", -10, L_xyz, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "xyz        33") == 0);
+    ASSERT (length == strlen (result));
+    free (result);
+  }
+
+  { /* FLAG_LEFT.  */
+    size_t length;
+    char *result =
+      my_asnprintf (NULL, &length, "%-10ls %d", L_xyz, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "xyz        33") == 0);
+    ASSERT (length == strlen (result));
+    free (result);
+  }
+#endif
+
   /* To verify that these tests succeed, it is necessary to run them under
      a tool that checks against invalid memory accesses, such as ElectricFence
      or "valgrind --tool=memcheck".  */
diff --git a/tests/test-vasprintf-posix.c b/tests/test-vasprintf-posix.c
index 5bef8d4a2a..3bfc18bb75 100644
--- a/tests/test-vasprintf-posix.c
+++ b/tests/test-vasprintf-posix.c
@@ -3696,6 +3696,90 @@ test_function (int (*my_asprintf) (char **, const char 
*, ...))
 
   /* Test the support of the %s format directive.  */
 
+  { /* Width.  */
+    char *result;
+    int retval =
+      my_asprintf (&result, "%10s %d", "xyz", 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "       xyz 33") == 0);
+    ASSERT (retval == strlen (result));
+    free (result);
+  }
+
+  { /* Width given as argument.  */
+    char *result;
+    int retval =
+      my_asprintf (&result, "%*s %d", 10, "xyz", 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "       xyz 33") == 0);
+    ASSERT (retval == strlen (result));
+    free (result);
+  }
+
+  { /* Negative width given as argument (cf. FLAG_LEFT below).  */
+    char *result;
+    int retval =
+      my_asprintf (&result, "%*s %d", -10, "xyz", 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "xyz        33") == 0);
+    ASSERT (retval == strlen (result));
+    free (result);
+  }
+
+  { /* FLAG_LEFT.  */
+    char *result;
+    int retval =
+      my_asprintf (&result, "%-10s %d", "xyz", 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "xyz        33") == 0);
+    ASSERT (retval == strlen (result));
+    free (result);
+  }
+
+#if HAVE_WCHAR_T
+  static wchar_t L_xyz[4] = { 'x', 'y', 'z', 0 };
+
+  { /* Width.  */
+    char *result;
+    int retval =
+      my_asprintf (&result, "%10ls %d", L_xyz, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "       xyz 33") == 0);
+    ASSERT (retval == strlen (result));
+    free (result);
+  }
+
+  { /* Width given as argument.  */
+    char *result;
+    int retval =
+      my_asprintf (&result, "%*ls %d", 10, L_xyz, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "       xyz 33") == 0);
+    ASSERT (retval == strlen (result));
+    free (result);
+  }
+
+  { /* Negative width given as argument (cf. FLAG_LEFT below).  */
+    char *result;
+    int retval =
+      my_asprintf (&result, "%*ls %d", -10, L_xyz, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "xyz        33") == 0);
+    ASSERT (retval == strlen (result));
+    free (result);
+  }
+
+  { /* FLAG_LEFT.  */
+    char *result;
+    int retval =
+      my_asprintf (&result, "%-10ls %d", L_xyz, 33, 44, 55);
+    ASSERT (result != NULL);
+    ASSERT (strcmp (result, "xyz        33") == 0);
+    ASSERT (retval == strlen (result));
+    free (result);
+  }
+#endif
+
   /* To verify that these tests succeed, it is necessary to run them under
      a tool that checks against invalid memory accesses, such as ElectricFence
      or "valgrind --tool=memcheck".  */






reply via email to

[Prev in Thread] Current Thread [Next in Thread]