Discussion:
fix vasnprintf on MSVC 14
(too old to reply)
Bruno Haible
2017-04-21 15:26:23 UTC
Permalink
Raw Message
On MSVC 14, vasnprintf fails even for simple requests like
printf ("%d", 12345). The reason is that the code currently assumes
that snprintf and _snprintf operate the same way, and that therefore
when HAVE_SNPRINTF_RETVAL_C99 = 1, _snprintf has a C99 compliant return
value. This is not the case, because the doc [1] says
"Beginning with the UCRT in Visual Studio 2015 and Windows 10,
snprintf is no longer identical to _snprintf. The snprintf
function behavior is now C99 standard compliant."

It would be possible to use _snprintf in older versions of Windows
and snprintf in newer ones / with newer versions of MSVC, but I don't
much like this, because this may lead to trouble when binaries are
built on older Windows version / with older MSVC tools and then run
on newer Windows versions. It's simpler to stay with using _snprintf
always.


2017-04-21 Bruno Haible <***@clisp.org>

vasnprintf: Fix for MSVC 14.
* lib/vasnprintf.c (USE_MSVC__SNPRINTF): New macro.
Everywhere, use !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF instead
of !HAVE_SNPRINTF_RETVAL_C99.

diff --git a/lib/vasnprintf.c b/lib/vasnprintf.c
index 4962e58..839f790 100644
--- a/lib/vasnprintf.c
+++ b/lib/vasnprintf.c
@@ -156,6 +156,7 @@
# define SNPRINTF snwprintf
# else
# define SNPRINTF _snwprintf
+# define USE_MSVC__SNPRINTF 1
# endif
# else
/* Unix. */
@@ -181,7 +182,9 @@
/* Here we need to call the native snprintf, not rpl_snprintf. */
# undef snprintf
# else
+ /* MSVC versions < 14 did not have snprintf, only _snprintf. */
# define SNPRINTF _snprintf
+# define USE_MSVC__SNPRINTF 1
# endif
# else
/* Unix. */
@@ -208,7 +211,7 @@
#undef remainder
#define remainder rem

-#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99) && !WIDE_CHAR_VERSION
+#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF) && !WIDE_CHAR_VERSION
# if (HAVE_STRNLEN && !defined _AIX)
# define local_strnlen strnlen
# else
@@ -224,7 +227,7 @@ local_strnlen (const char *string, size_t maxlen)
# endif
#endif

-#if (((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99) && WIDE_CHAR_VERSION) || ((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL)) && !WIDE_CHAR_VERSION && DCHAR_IS_TCHAR)) && HAVE_WCHAR_T
+#if (((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF) && WIDE_CHAR_VERSION) || ((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL)) && !WIDE_CHAR_VERSION && DCHAR_IS_TCHAR)) && HAVE_WCHAR_T
# if HAVE_WCSLEN
# define local_wcslen wcslen
# else
@@ -247,7 +250,7 @@ local_wcslen (const wchar_t *s)
# endif
#endif

-#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99) && HAVE_WCHAR_T && WIDE_CHAR_VERSION
+#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF) && HAVE_WCHAR_T && WIDE_CHAR_VERSION
# if HAVE_WCSNLEN
# define local_wcsnlen wcsnlen
# else
@@ -1517,7 +1520,7 @@ is_borderline (const char *digits, size_t precision)

#endif

-#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99
+#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF

/* Use a different function name, to make it possible that the 'wchar_t'
parametrization and the 'char' parametrization get compiled in the same
@@ -2392,7 +2395,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
}
}
#endif
-#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL)) && HAVE_WCHAR_T
+#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL)) && HAVE_WCHAR_T
else if (dp->conversion == 's'
# if WIDE_CHAR_VERSION
&& a.arg[dp->arg_index].type != TYPE_WIDE_STRING
@@ -4591,10 +4594,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
int has_width;
#endif
-#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
+#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
size_t width;
#endif
-#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || NEED_PRINTF_UNBOUNDED_PRECISION
+#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_UNBOUNDED_PRECISION
int has_precision;
size_t precision;
#endif
@@ -4623,7 +4626,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
has_width = 0;
#endif
-#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
+#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
width = 0;
if (dp->width_start != dp->width_end)
{
@@ -4657,7 +4660,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
}
#endif

-#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || NEED_PRINTF_UNBOUNDED_PRECISION
+#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_UNBOUNDED_PRECISION
has_precision = 0;
precision = 6;
if (dp->precision_start != dp->precision_end)
@@ -5127,7 +5130,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
/* Look at the snprintf() return value. */
if (retcount < 0)
{
-# if !HAVE_SNPRINTF_RETVAL_C99
+# if !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF
/* HP-UX 10.20 snprintf() is doubly deficient:
It doesn't understand the '%n' directive,
*and* it returns -1 (rather than the length


[1] https://msdn.microsoft.com/en-us/library/2ts7cx93.aspx
[2] https://msdn.microsoft.com/en-us/library/2ts7cx93(v=vs.120).aspx
Loading...