From 95f013ba80fbe5a6c7423771d9c7715397f7585d Mon Sep 17 00:00:00 2001 From: Arseny Kapoulkine Date: Thu, 15 Jun 2017 23:35:20 -0700 Subject: Refactor snprintf support Instead of branching code at each invocation site, use variadic macros to create a wrapping macro that use snprintf for the buffer of a statically known size. Variadic macros are supported by all C++11 compilers, as is snprintf; on MSVC 2005+ we don't necessarily have snprintf, but we can use _snprintf_s with _TRUNCATE to get the same behavior. In all other cases we fall back to sprintf, that (theoretically) can lead to a stack buffer overflow. In practice all snprintfs used in pugixml use buffers that should be large enough to never be overflown but snprintf is safe even if this is not the case. --- src/pugixml.cpp | 38 ++++++++++++-------------------------- 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/src/pugixml.cpp b/src/pugixml.cpp index 518ceec..62d0711 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -127,10 +127,16 @@ using std::memset; # define PUGI__MSVC_CRT_VERSION _MSC_VER #endif -#if (defined(PUGI__MSVC_CRT_VERSION) && (PUGI__MSVC_CRT_VERSION >= 1900)) || (__cplusplus >= 201103) -# define PUGI__HAVE_SNPRINTF +// Not all platforms have snprintf; we define a wrapper that uses snprintf if possible. This only works with buffers with a known size. +#if __cplusplus >= 201103 +# define PUGI__SNPRINTF(buf, ...) snprintf(buf, sizeof(buf), __VA_ARGS__) +#elif defined(_MSC_VER) && _MSC_VER >= 1400 +# define PUGI__SNPRINTF(buf, ...) _snprintf_s(buf, sizeof(buf), _TRUNCATE, __VA_ARGS__) +#else +# define PUGI__SNPRINTF sprintf #endif +// We put implementation details into an anonymous namespace in source mode, but have to keep it in non-anonymous namespace in header-only mode to prevent binary bloat. #ifdef PUGIXML_HEADER_ONLY # define PUGI__NS_BEGIN namespace pugi { namespace impl { # define PUGI__NS_END } } @@ -4636,14 +4642,7 @@ PUGI__NS_BEGIN PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, float value) { char buf[128]; -#if defined(PUGI__HAVE_SNPRINTF) - snprintf(buf, 128, "%.9g", value); -#elif defined(PUGI__MSVC_CRT_VERSION) - _snprintf(buf, 128, "%.9g", value); - buf[127] = '\0'; -#else - sprintf(buf, "%.9g", value); -#endif + PUGI__SNPRINTF(buf, "%.9g", value); return set_value_ascii(dest, header, header_mask, buf); } @@ -4652,14 +4651,7 @@ PUGI__NS_BEGIN PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, double value) { char buf[128]; -#if defined(PUGI__HAVE_SNPRINTF) - snprintf(buf, 128, "%.17g", value); -#elif defined (PUGI__MSVC_CRT_VERSION) - _snprintf(buf, 128, "%.17g", value); - buf[127] = '\0'; -#else - sprintf(buf, "%.17g", value); -#endif + PUGI__SNPRINTF(buf, "%.17g", value); return set_value_ascii(dest, header, header_mask, buf); } @@ -8015,14 +8007,7 @@ PUGI__NS_BEGIN PUGI__FN void convert_number_to_mantissa_exponent(double value, char (&buffer)[32], char** out_mantissa, int* out_exponent) { // get a scientific notation value with IEEE DBL_DIG decimals -#if defined(PUGI__HAVE_SNPRINTF) - snprintf(buffer, 32, "%.*e", DBL_DIG, value); -#elif defined(PUGI__MSVC_CRT_VERSION) - _snprintf(buffer, 32, "%.*e", DBL_DIG, value); - buffer[31] = '\0'; -#else - sprintf(buffer, "%.*e", DBL_DIG, value); -#endif + PUGI__SNPRINTF(buffer, "%.*e", DBL_DIG, value); // get the exponent (possibly negative) char* exponent_string = strchr(buffer, 'e'); @@ -12616,6 +12601,7 @@ namespace pugi #undef PUGI__DMC_VOLATILE #undef PUGI__UNSIGNED_OVERFLOW #undef PUGI__MSVC_CRT_VERSION +#undef PUGI__SNPRINTF #undef PUGI__NS_BEGIN #undef PUGI__NS_END #undef PUGI__FN -- cgit v1.2.3