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 <br...@clisp.org> vasnprintf-posix: Fix negative width handling for %ls directive. Reported by clang via Po Lu <luang...@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". */