diff options
author | Arseny Kapoulkine <arseny.kapoulkine@gmail.com> | 2017-06-15 23:35:20 -0700 |
---|---|---|
committer | Arseny Kapoulkine <arseny.kapoulkine@gmail.com> | 2017-06-15 23:35:20 -0700 |
commit | 95f013ba80fbe5a6c7423771d9c7715397f7585d (patch) | |
tree | 86c3dd5f6d03528df507e5937df469d02cba66e7 | |
parent | 207bc788e93a40460c36bfbb9f2af9927b87de9b (diff) |
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.
-rw-r--r-- | src/pugixml.cpp | 38 |
1 files 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 |