summaryrefslogtreecommitdiff
path: root/src/pugixml.cpp
diff options
context:
space:
mode:
authorArseny Kapoulkine <arseny.kapoulkine@gmail.com>2017-06-15 23:35:20 -0700
committerArseny Kapoulkine <arseny.kapoulkine@gmail.com>2017-06-15 23:35:20 -0700
commit95f013ba80fbe5a6c7423771d9c7715397f7585d (patch)
tree86c3dd5f6d03528df507e5937df469d02cba66e7 /src/pugixml.cpp
parent207bc788e93a40460c36bfbb9f2af9927b87de9b (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.
Diffstat (limited to 'src/pugixml.cpp')
-rw-r--r--src/pugixml.cpp38
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