From b09aadd202db469a8bab163624986961a1472111 Mon Sep 17 00:00:00 2001 From: Martin Storsjo Date: Tue, 3 Nov 2015 20:40:35 +0200 Subject: [PATCH] ucrtbase: Handle the swprintf style termination and return values. When neither the "legacy vsprintf null termination" nor the "standard snprintf behaviour" flags are specified, the functions return -2 when the output string didn't fit (similar to old style msvcrt _snprintf that returned -1), but they are null terminated (similar to the C99 snprintf style behaviour). This is the same way as the C99 swprintf function behaves. Signed-off-by: Martin Storsjo Signed-off-by: Piotr Caban Signed-off-by: Alexandre Julliard --- dlls/msvcrt/msvcrt.h | 3 +++ dlls/msvcrt/wcs.c | 40 ++++++++++++++++++++++++++-------------- dlls/ucrtbase/tests/printf.c | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 14 deletions(-) diff --git a/dlls/msvcrt/msvcrt.h b/dlls/msvcrt/msvcrt.h index a3b259501a3..f11d0a8cfa1 100644 --- a/dlls/msvcrt/msvcrt.h +++ b/dlls/msvcrt/msvcrt.h @@ -1130,6 +1130,9 @@ extern char* __cdecl __unDName(char *,const char*,int,malloc_func_t,free_func_t, #define UCRTBASE_PRINTF_LEGACY_MSVCRT_COMPATIBILITY (0x0008) #define UCRTBASE_PRINTF_LEGACY_THREE_DIGIT_EXPONENTS (0x0010) +#define UCRTBASE_PRINTF_TERMINATION_MASK (UCRTBASE_PRINTF_LEGACY_VSPRINTF_NULL_TERMINATION | \ + UCRTBASE_PRINTF_STANDARD_SNPRINTF_BEHAVIOUR) + #define UCRTBASE_SCANF_SECURECRT (0x0001) #define UCRTBASE_SCANF_LEGACY_WIDE_SPECIFIERS (0x0002) #define UCRTBASE_SCANF_LEGACY_MSVCRT_COMPATIBILITY (0x0004) diff --git a/dlls/msvcrt/wcs.c b/dlls/msvcrt/wcs.c index 0bfddbb215c..169012cd261 100644 --- a/dlls/msvcrt/wcs.c +++ b/dlls/msvcrt/wcs.c @@ -701,10 +701,10 @@ static int puts_clbk_str_c99_a(void *ctx, int len, const char *str) if(!out->buf) return len; - if(out->len - 1 < len) { - memcpy(out->buf, str, out->len - 1); - out->buf += out->len - 1; - out->len = 1; + if(out->len < len) { + memcpy(out->buf, str, out->len); + out->buf += out->len; + out->len = 0; return len; } @@ -724,12 +724,18 @@ int CDECL MSVCRT__stdio_common_vsprintf( unsigned __int64 options, char *str, MS struct _str_ctx_a ctx = {len, str}; int ret; - if (options != UCRTBASE_PRINTF_LEGACY_VSPRINTF_NULL_TERMINATION && - options != UCRTBASE_PRINTF_STANDARD_SNPRINTF_BEHAVIOUR) + if (options & ~UCRTBASE_PRINTF_TERMINATION_MASK) FIXME("options %s not handled\n", wine_dbgstr_longlong(options)); - ret = pf_printf_a(options & UCRTBASE_PRINTF_STANDARD_SNPRINTF_BEHAVIOUR ? puts_clbk_str_c99_a : puts_clbk_str_a, + ret = pf_printf_a(puts_clbk_str_c99_a, &ctx, format, locale, FALSE, FALSE, arg_clbk_valist, NULL, &valist); puts_clbk_str_a(&ctx, 1, &nullbyte); + + if(options & UCRTBASE_PRINTF_LEGACY_VSPRINTF_NULL_TERMINATION) + return ret>len ? -1 : ret; + if(ret>=len) { + if(len) str[len-1] = 0; + return (options & UCRTBASE_PRINTF_STANDARD_SNPRINTF_BEHAVIOUR) ? ret : -2; + } return ret; } @@ -1148,10 +1154,10 @@ static int puts_clbk_str_c99_w(void *ctx, int len, const MSVCRT_wchar_t *str) if(!out->buf) return len; - if(out->len - 1 < len) { - memcpy(out->buf, str, (out->len - 1)*sizeof(MSVCRT_wchar_t)); - out->buf += out->len - 1; - out->len = 1; + if(out->len < len) { + memcpy(out->buf, str, out->len*sizeof(MSVCRT_wchar_t)); + out->buf += out->len; + out->len = 0; return len; } @@ -1171,12 +1177,18 @@ int CDECL MSVCRT__stdio_common_vswprintf( unsigned __int64 options, MSVCRT_wchar struct _str_ctx_w ctx = {len, str}; int ret; - if (options != UCRTBASE_PRINTF_LEGACY_VSPRINTF_NULL_TERMINATION && - options != UCRTBASE_PRINTF_STANDARD_SNPRINTF_BEHAVIOUR) + if (options & ~UCRTBASE_PRINTF_TERMINATION_MASK) FIXME("options %s not handled\n", wine_dbgstr_longlong(options)); - ret = pf_printf_w(options & UCRTBASE_PRINTF_STANDARD_SNPRINTF_BEHAVIOUR ? puts_clbk_str_c99_w : puts_clbk_str_w, + ret = pf_printf_w(puts_clbk_str_c99_w, &ctx, format, locale, FALSE, FALSE, arg_clbk_valist, NULL, &valist); puts_clbk_str_w(&ctx, 1, &nullbyte); + + if(options & UCRTBASE_PRINTF_LEGACY_VSPRINTF_NULL_TERMINATION) + return ret>len ? -1 : ret; + if(ret>=len) { + if(len) str[len-1] = 0; + return (options & UCRTBASE_PRINTF_STANDARD_SNPRINTF_BEHAVIOUR) ? ret : -2; + } return ret; } diff --git a/dlls/ucrtbase/tests/printf.c b/dlls/ucrtbase/tests/printf.c index 99d756e9fdc..ce47e2abd86 100644 --- a/dlls/ucrtbase/tests/printf.c +++ b/dlls/ucrtbase/tests/printf.c @@ -120,6 +120,21 @@ static void test_snprintf (void) ok (buffer[valid] == '\0', "\"%s\": Missing null termination (ret %d) - is %d\n", fmt, n, buffer[valid]); } + + /* swprintf style termination */ + for (i = 0; i < sizeof tests / sizeof tests[0]; i++) { + const char *fmt = tests[i]; + const int expect = strlen(fmt) >= bufsiz ? -2 : strlen(fmt); + const int n = vsprintf_wrapper (0, buffer, bufsiz, fmt); + const int valid = n < 0 ? bufsiz - 1 : n; + + ok (n == expect, "\"%s\": expected %d, returned %d\n", + fmt, expect, n); + ok (!memcmp (fmt, buffer, valid), + "\"%s\": rendered \"%.*s\"\n", fmt, valid, buffer); + ok (buffer[valid] == '\0', + "\"%s\": Missing null termination (ret %d) - is %d\n", fmt, n, buffer[valid]); + } } static int __cdecl vswprintf_wrapper(unsigned __int64 options, wchar_t *str, @@ -177,6 +192,23 @@ static void test_swprintf (void) ok (buffer[valid] == '\0', "\"%s\": Missing null termination (ret %d) - is %d\n", narrow_fmt, n, buffer[valid]); } + + /* swprintf style termination */ + for (i = 0; i < sizeof tests / sizeof tests[0]; i++) { + const wchar_t *fmt = tests[i]; + const int expect = wcslen(fmt) >= bufsiz ? -2 : wcslen(fmt); + const int n = vswprintf_wrapper (0, buffer, bufsiz, fmt); + const int valid = n < 0 ? bufsiz - 1 : n; + + WideCharToMultiByte (CP_ACP, 0, buffer, -1, narrow, sizeof(narrow), NULL, NULL); + WideCharToMultiByte (CP_ACP, 0, fmt, -1, narrow_fmt, sizeof(narrow_fmt), NULL, NULL); + ok (n == expect, "\"%s\": expected %d, returned %d\n", + narrow_fmt, expect, n); + ok (!memcmp (fmt, buffer, valid * sizeof(wchar_t)), + "\"%s\": rendered \"%.*s\"\n", narrow_fmt, valid, narrow); + ok (buffer[valid] == '\0', + "\"%s\": Missing null termination (ret %d) - is %d\n", narrow_fmt, n, buffer[valid]); + } } static int __cdecl vfprintf_wrapper(FILE *file, -- 2.11.4.GIT