bug-gnulib@gnu.org mirror (unofficial)
 help / color / mirror / Atom feed
From: Bruno Haible <bruno@clisp.org>
To: bug-gnulib@gnu.org
Subject: vasnprintf-posix: Fix negative width handling for %ls directive
Date: Sat, 28 Jan 2023 18:54:01 +0100	[thread overview]
Message-ID: <3003231.vvmviz7Nmq@nimes> (raw)

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	other threads:[~2023-01-28 17:54 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://lists.gnu.org/mailman/listinfo/bug-gnulib

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=3003231.vvmviz7Nmq@nimes \
    --to=bruno@clisp.org \
    --cc=bug-gnulib@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).