From 3a3fae8b8b2139dbcd6ac359bb76f553ba8bf01f Mon Sep 17 00:00:00 2001 From: Jeffrey Walton Date: Sat, 30 Jan 2016 14:01:20 -0500 Subject: [PATCH] Fixed potential ODR violation of non-member function StringNarrow --- misc.cpp | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ misc.h | 26 ++++++++++++------------- 2 files changed, 71 insertions(+), 13 deletions(-) diff --git a/misc.cpp b/misc.cpp index b5a2ea41..f48f5dd9 100644 --- a/misc.cpp +++ b/misc.cpp @@ -133,6 +133,64 @@ bool VerifyBufsEqual(const byte *buf, const byte *mask, size_t count) return acc8 == 0; } +#ifndef CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY_562 +std::string StringNarrow(const wchar_t *str, bool throwOnError) +{ + assert(str); + std::string result; + + // Safer functions on Windows for C&A, https://github.com/weidai11/cryptopp/issues/55 +#if (CRYPTOPP_MSC_VERSION >= 1400) + size_t len=0, size=0; + errno_t err = 0; + + //const wchar_t* ptr = str; + //while (*ptr++) len++; + len = wcslen(str)+1; + + err = wcstombs_s(&size, NULL, 0, str, len*sizeof(wchar_t)); + assert(err == 0); + if (err != 0) {goto CONVERSION_ERROR;} + + result.resize(size); + err = wcstombs_s(&size, &result[0], size, str, len*sizeof(wchar_t)); + assert(err == 0); + + if (err != 0) + { +CONVERSION_ERROR: + if (throwOnError) + throw InvalidArgument("StringNarrow: wcstombs_s() call failed with error " + IntToString(err)); + else + return std::string(); + } + + // The safe routine's size includes the NULL. + if (!result.empty() && result[size - 1] == '\0') + result.erase(size - 1); +#else + size_t size = wcstombs(NULL, str, 0); + assert(size != (size_t)-1); + if (size == (size_t)-1) {goto CONVERSION_ERROR;} + + result.resize(size); + size = wcstombs(&result[0], str, size); + assert(size != (size_t)-1); + + if (size == (size_t)-1) + { +CONVERSION_ERROR: + if (throwOnError) + throw InvalidArgument("StringNarrow: wcstombs() call failed"); + else + return std::string(); + } +#endif + + return result; +} +#endif // StringNarrow and CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY_562 + #if !(defined(_MSC_VER) && (_MSC_VER < 1300)) using std::new_handler; using std::set_new_handler; diff --git a/misc.h b/misc.h index 8ce98da9..90851bec 100644 --- a/misc.h +++ b/misc.h @@ -1060,29 +1060,28 @@ inline void SecureWipeArray(T *buf, size_t n) } //! \brief Converts a wide character C-string to a multibyte string -//! \param str a C-string consiting of wide characters +//! \param str C-string consiting of wide characters //! \param throwOnError specifies the function should throw an InvalidArgument exception on error //! \returns str converted to a multibyte string or an empty string. -//! \details This function converts a wide string to a string using C++ wcstombs under the executing -//! thread's locale. A locale must be set before using this function, and it can be set with setlocale. -//! Upon success, the converted string is returned. Upon failure with throwOnError as false, the -//! function returns an empty string. Upon failure with throwOnError as true, the function throws -//! InvalidArgument exception. +//! \details StringNarrow converts a wide string to a narrow string using C++ std::wcstombs under the executing +//! thread's locale. A locale must be set before using this function, and it can be set with std::setlocale. +//! Upon success, the converted string is returned. +//! \details Upon failure with throwOnError as false, the function returns an empty string. Upon failure with +//! throwOnError as true, the function throws InvalidArgument exception. //! \note If you try to convert, say, the Chinese character for "bone" from UTF-16 (0x9AA8) to UTF-8 -//! (0xE9 0xAA 0xA8), then you should ensure the locales are available. If the locales are not available, -//! then a 0x21 error is returned which eventually results in an InvalidArgument exception +//! (0xE9 0xAA 0xA8), then you must ensure the locale is available. If the locale is not available, +//! then a 0x21 error is returned on Windows which eventually results in an InvalidArgument exception. #ifndef CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY_562 -static inline std::string StringNarrow(const wchar_t *str, bool throwOnError = true) +std::string StringNarrow(const wchar_t *str, bool throwOnError = true); #else static std::string StringNarrow(const wchar_t *str, bool throwOnError = true) -#endif { assert(str); std::string result; // Safer functions on Windows for C&A, https://github.com/weidai11/cryptopp/issues/55 #if (CRYPTOPP_MSC_VERSION >= 1400) - size_t len=0, size = 0; + size_t len=0, size=0; errno_t err = 0; //const wchar_t* ptr = str; @@ -1093,7 +1092,7 @@ static std::string StringNarrow(const wchar_t *str, bool throwOnError = true) assert(err == 0); if (err != 0) {goto CONVERSION_ERROR;} - result.resize(size); + result.resize(size); err = wcstombs_s(&size, &result[0], size, str, len*sizeof(wchar_t)); assert(err == 0); @@ -1113,7 +1112,7 @@ CONVERSION_ERROR: size_t size = wcstombs(NULL, str, 0); assert(size != (size_t)-1); if (size == (size_t)-1) {goto CONVERSION_ERROR;} - + result.resize(size); size = wcstombs(&result[0], str, size); assert(size != (size_t)-1); @@ -1130,6 +1129,7 @@ CONVERSION_ERROR: return result; } +#endif // StringNarrow and CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY_562 #ifdef CRYPTOPP_DOXYGEN_PROCESSING