In ucrtbase (but not in msvcrt), when a printf format specifier has two width specifiers (both a '*' and an explicit number), only the latter should take effect. (In msvcrt, the width of one is combined with the other).
This patch builds on the prior patch which implements the msvcrt behaviour, and needs to be applied on top of it: msvcrt: The '*' character should be interpreted as the beginning of the width specification[1,2]
It also supercedes the previous (incorrect) patch which used the ucrtbase behaviour on msvcrt as well: msvcrt: printf: Later width specifiers should override earlier ones[3]
For further details, see [4], [5], and [6].
[1]: https://source.winehq.org/patches/data/218904 [2]: https://www.winehq.org/pipermail/wine-devel/2021-November/200009.html [3]: https://www.winehq.org/pipermail/wine-devel/2021-November/200040.html [4]: https://www.winehq.org/pipermail/wine-devel/2021-November/200039.html [5]: https://github.com/ValveSoftware/Proton/issues/5258#issuecomment-962423092 [6]: https://www.winehq.org/pipermail/wine-devel/2021-November/200063.html
Signed-off-by: David Gow david@davidgow.net --- dlls/msvcrt/printf.h | 6 ++++++ dlls/ucrtbase/tests/printf.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+)
diff --git a/dlls/msvcrt/printf.h b/dlls/msvcrt/printf.h index 40a8a13d861..52dec97f8bc 100644 --- a/dlls/msvcrt/printf.h +++ b/dlls/msvcrt/printf.h @@ -1050,6 +1050,12 @@ int FUNC_NAME(pf_printf)(FUNC_NAME(puts_clbk) pf_puts, void *puts_ctx, const API flags.LeftAlign = TRUE; flags.FieldLength = -flags.FieldLength; } + + /* On ucrtbase, we ignore all but the last specifier. */ +#if _MSVCR_VER >= 140 + if (*p >= '0' && *p <= '9') + flags.FieldLength = 0; +#endif }
while (*p >= '0' && *p <= '9') { diff --git a/dlls/ucrtbase/tests/printf.c b/dlls/ucrtbase/tests/printf.c index 4f20ccff9a4..328300d7827 100644 --- a/dlls/ucrtbase/tests/printf.c +++ b/dlls/ucrtbase/tests/printf.c @@ -845,6 +845,35 @@ static void test_printf_fp(void) } }
+static void test_printf_width_specifiers(void) +{ + char buf[150]; + int r; + + /* In msvcrt, multiple width specifiers will 'stack', producing + * a longer width. In ucrtbase, only the last width specifier will + * take effect. */ + r = vsprintf_wrapper(0, buf, sizeof(buf), "%0*02d", 1, 0); + ok(r==2, "r = %d\n", r); + ok(!strcmp(buf, "00"), "failed: "%s"\n", buf); + + r = vsprintf_wrapper(0, buf, sizeof(buf), "%0*02d", 2, 17); + ok(r==2, "r = %d\n", r); + ok(!strcmp(buf, "17"), "failed: "%s"\n", buf); + + r = vsprintf_wrapper(0, buf, sizeof(buf), "%*1d", 1, 3); + ok(r==1, "r = %d\n", r); + ok(!strcmp(buf, "3"), "failed: "%s"\n", buf); + + r = vsprintf_wrapper(0, buf, sizeof(buf), "%0*0d", 1, 2); + ok(r==1, "r = %d\n", r); + ok(!strcmp(buf, "2"), "failed: "%s"\n", buf); + + r = vsprintf_wrapper(0, buf, sizeof(buf), "% *2d", 0, 7); + ok(r==2, "r = %d\n", r); + ok(!strcmp(buf, " 7"), "failed: "%s"\n", buf); +} + START_TEST(printf) { ok(_set_invalid_parameter_handler(test_invalid_parameter_handler) == NULL, @@ -862,4 +891,5 @@ START_TEST(printf) test_printf_c99(); test_printf_natural_string(); test_printf_fp(); + test_printf_width_specifiers(); }
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=101426
Your paranoid android.
=== build (build log) ===
error: patch failed: dlls/msvcrt/printf.h:1050 Task: Patch failed to apply
=== debiant2 (build log) ===
error: patch failed: dlls/msvcrt/printf.h:1050 Task: Patch failed to apply
=== debiant2 (build log) ===
error: patch failed: dlls/msvcrt/printf.h:1050 Task: Patch failed to apply
Thanks, David. I've resent the patches squashed together and with the added ucrtbase tests.
Andrew
On Mon, Nov 08, 2021 at 07:06:26PM +0800, David Gow wrote:
In ucrtbase (but not in msvcrt), when a printf format specifier has two width specifiers (both a '*' and an explicit number), only the latter should take effect. (In msvcrt, the width of one is combined with the other).
This patch builds on the prior patch which implements the msvcrt behaviour, and needs to be applied on top of it: msvcrt: The '*' character should be interpreted as the beginning of the width specification[1,2]
It also supercedes the previous (incorrect) patch which used the ucrtbase behaviour on msvcrt as well: msvcrt: printf: Later width specifiers should override earlier ones[3]
For further details, see [4], [5], and [6].
Signed-off-by: David Gow david@davidgow.net