From 46c9cc725cf325f2990056526a00848a11d37fa8 Mon Sep 17 00:00:00 2001 From: Jeffrey Walton Date: Wed, 15 Mar 2017 06:20:45 -0400 Subject: [PATCH] Use C++03 Singleton on select Microsoft platforms (Issues 372, 373, 389, 391) We are back to the "... one object may end up being memory leaked" if faced with concurrent initialization --- config.h | 100 +++++++++++++++++++++++++++++---------------------- misc.h | 22 +++++++----- trdlocal.cpp | 2 ++ 3 files changed, 72 insertions(+), 52 deletions(-) diff --git a/config.h b/config.h index a3b2f31b..8607cbb6 100644 --- a/config.h +++ b/config.h @@ -787,113 +787,127 @@ NAMESPACE_END // C++11 or C++14 is available #if defined(CRYPTOPP_CXX11) -// atomics: MS at VS2012 (17.00); GCC at 4.4; Clang at 3.1/3.2; Intel 13.0; SunCC 12.5. +// Compatibility with non-clang compilers. +#ifndef __has_feature +# define __has_feature(x) 0 +#endif + +// atomics: MS at VS2012 (17.00); GCC at 4.4; Clang at 3.1/3.2; Intel 13.0; SunCC 5.14. #if (CRYPTOPP_MSC_VERSION >= 1700) # define CRYPTOPP_CXX11_ATOMICS 1 +#elif __has_feature(cxx_atomic) +# define CRYPTOPP_CXX11_ATOMICS 1 #elif (__INTEL_COMPILER >= 1300) # define CRYPTOPP_CXX11_ATOMICS 1 -#elif defined(__clang__) -# if __has_feature(cxx_atomic) -# define CRYPTOPP_CXX11_ATOMICS 1 -# endif #elif (CRYPTOPP_GCC_VERSION >= 40400) # define CRYPTOPP_CXX11_ATOMICS 1 #elif (__SUNPRO_CC >= 0x5140) # define CRYPTOPP_CXX11_ATOMICS 1 #endif // atomics -// synchronization: MS at VS2012 (17.00); GCC at 4.4; Clang at 3.3; Xcode 5.0; Intel 12.0; SunCC 12.4. +// synchronization: MS at VS2012 (17.00); GCC at 4.4; Clang at 3.3; Xcode 5.0; Intel 12.0; SunCC 5.13. // TODO: verify Clang and Intel versions; find __has_feature(x) extension for Clang #if (CRYPTOPP_MSC_VERSION >= 1700) # define CRYPTOPP_CXX11_SYNCHRONIZATION 1 -#elif (__INTEL_COMPILER >= 1200) -# define CRYPTOPP_CXX11_SYNCHRONIZATION 1 #elif (CRYPTOPP_LLVM_CLANG_VERSION >= 30300) || (CRYPTOPP_APPLE_CLANG_VERSION >= 50000) # define CRYPTOPP_CXX11_SYNCHRONIZATION 1 +#elif (__INTEL_COMPILER >= 1200) +# define CRYPTOPP_CXX11_SYNCHRONIZATION 1 #elif (CRYPTOPP_GCC_VERSION >= 40400) # define CRYPTOPP_CXX11_SYNCHRONIZATION 1 #elif (__SUNPRO_CC >= 0x5130) # define CRYPTOPP_CXX11_SYNCHRONIZATION 1 #endif // synchronization -// alignof/alignas: MS at VS2015 (19.00); GCC at 4.8; Clang at 3.3; Intel 15.0; SunCC 12.4. +// Dynamic Initialization and Destruction with Concurrency ("Magic Statics") +// MS at VS2015 (19.00); GCC at 4.3; LLVM Clang at 2.9; Apple Clang at 4.0; Intel 11.1; SunCC 5.13. +// Microsoft's implementation only works for Vista and above, so its further +// limited. http://connect.microsoft.com/VisualStudio/feedback/details/1789709 +#if (CRYPTOPP_MSC_VERSION >= 1900) && ((WINVER >= 0x0600 /*_WIN32_WINNT_VISTA*/) || (_WIN32_WINNT >= 0x0600 /*_WIN32_WINNT_VISTA*/)) +# define CRYPTOPP_CXX11_DYNAMIC_INIT 1 +#elif (CRYPTOPP_LLVM_CLANG_VERSION >= 20900) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40000) +# define CRYPTOPP_CXX11_DYNAMIC_INIT 1 +#elif (__INTEL_COMPILER >= 1110) +# define CRYPTOPP_CXX11_DYNAMIC_INIT 1 +#elif (CRYPTOPP_GCC_VERSION >= 40300) +# define CRYPTOPP_CXX11_DYNAMIC_INIT 1 +#elif (__SUNPRO_CC >= 0x5130) +# define CRYPTOPP_CXX11_DYNAMIC_INIT 1 +#endif // Dynamic Initialization compilers + +// alignof/alignas: MS at VS2015 (19.00); GCC at 4.8; Clang at 3.0; Intel 15.0; SunCC 5.13. #if (CRYPTOPP_MSC_VERSION >= 1900) # define CRYPTOPP_CXX11_ALIGNAS 1 -# define CRYPTOPP_CXX11_ALIGNOF 1 +#elif __has_feature(cxx_alignas) +# define CRYPTOPP_CXX11_ALIGNAS 1 #elif (__INTEL_COMPILER >= 1500) # define CRYPTOPP_CXX11_ALIGNAS 1 -# define CRYPTOPP_CXX11_ALIGNOF 1 -#elif defined(__clang__) -# if __has_feature(cxx_alignas) -# define CRYPTOPP_CXX11_ALIGNAS 1 -# endif -# if __has_feature(cxx_alignof) -# define CRYPTOPP_CXX11_ALIGNOF 1 -# endif #elif (CRYPTOPP_GCC_VERSION >= 40800) # define CRYPTOPP_CXX11_ALIGNAS 1 -# define CRYPTOPP_CXX11_ALIGNOF 1 #elif (__SUNPRO_CC >= 0x5130) # define CRYPTOPP_CXX11_ALIGNAS 1 -# define CRYPTOPP_CXX11_ALIGNOF 1 -#endif // alignof/alignas +#endif // alignas -// noexcept: MS at VS2015 (19.00); GCC at 4.6; Clang at 3.0; Intel 14.0; SunCC 12.4. +// alignof: MS at VS2015 (19.00); GCC at 4.5; Clang at 2.9; Intel 15.0; SunCC 5.13. #if (CRYPTOPP_MSC_VERSION >= 1900) +# define CRYPTOPP_CXX11_ALIGNOF 1 +#elif __has_feature(cxx_alignof) +# define CRYPTOPP_CXX11_ALIGNOF 1 +#elif (__INTEL_COMPILER >= 1500) +# define CRYPTOPP_CXX11_ALIGNOF 1 +#elif (CRYPTOPP_GCC_VERSION >= 40500) +# define CRYPTOPP_CXX11_ALIGNOF 1 +#elif (__SUNPRO_CC >= 0x5130) +# define CRYPTOPP_CXX11_ALIGNOF 1 +#endif // alignof + +// noexcept: MS at VS2015 (19.00); GCC at 4.6; Clang at 3.0; Intel 14.0; SunCC 5.13. +#if (CRYPTOPP_MSC_VERSION >= 1900) +# define CRYPTOPP_CXX11_NOEXCEPT 1 +#elif __has_feature(cxx_noexcept) # define CRYPTOPP_CXX11_NOEXCEPT 1 #elif (__INTEL_COMPILER >= 1400) # define CRYPTOPP_CXX11_NOEXCEPT 1 -#elif defined(__clang__) -# if __has_feature(cxx_noexcept) -# define CRYPTOPP_CXX11_NOEXCEPT 1 -# endif #elif (CRYPTOPP_GCC_VERSION >= 40600) # define CRYPTOPP_CXX11_NOEXCEPT 1 #elif (__SUNPRO_CC >= 0x5130) # define CRYPTOPP_CXX11_NOEXCEPT 1 #endif // noexcept compilers -// variadic templates: MS at VS2013 (18.00); GCC at 4.3; Clang at 2.9; Intel 12.1; SunCC 12.4. +// variadic templates: MS at VS2013 (18.00); GCC at 4.3; Clang at 2.9; Intel 12.1; SunCC 5.13. #if (CRYPTOPP_MSC_VERSION >= 1800) # define CRYPTOPP_CXX11_VARIADIC_TEMPLATES 1 +#elif __has_feature(cxx_variadic_templates) +# define CRYPTOPP_CXX11_VARIADIC_TEMPLATES 1 #elif (__INTEL_COMPILER >= 1210) # define CRYPTOPP_CXX11_VARIADIC_TEMPLATES 1 -#elif defined(__clang__) -# if __has_feature(cxx_variadic_templates) -# define CRYPTOPP_CXX11_VARIADIC_TEMPLATES 1 -# endif #elif (CRYPTOPP_GCC_VERSION >= 40300) # define CRYPTOPP_CXX11_VARIADIC_TEMPLATES 1 #elif (__SUNPRO_CC >= 0x5130) # define CRYPTOPP_CXX11_VARIADIC_TEMPLATES 1 #endif // variadic templates -// constexpr: MS at VS2015 (19.00); GCC at 4.6; Clang at 3.0; Intel 16.0; SunCC 12.4. +// constexpr: MS at VS2015 (19.00); GCC at 4.6; Clang at 3.1; Intel 16.0; SunCC 5.13. // Intel has mis-supported the feature since at least ICPC 13.00 #if (CRYPTOPP_MSC_VERSION >= 1900) # define CRYPTOPP_CXX11_CONSTEXPR 1 +#elif __has_feature(cxx_constexpr) +# define CRYPTOPP_CXX11_CONSTEXPR 1 #elif (__INTEL_COMPILER >= 1600) # define CRYPTOPP_CXX11_CONSTEXPR 1 -#elif defined(__clang__) -# if __has_feature(cxx_constexpr) -# define CRYPTOPP_CXX11_CONSTEXPR 1 -# endif #elif (CRYPTOPP_GCC_VERSION >= 40600) # define CRYPTOPP_CXX11_CONSTEXPR 1 #elif (__SUNPRO_CC >= 0x5130) # define CRYPTOPP_CXX11_CONSTEXPR 1 #endif // constexpr compilers -// nullptr_t: MS at VS2010 (16.00); GCC at 4.6; Clang at 3.3; Intel 12.0; SunCC 12.4. -// Intel has upported the feature since at least ICPC 12.00 +// nullptr_t: MS at VS2010 (16.00); GCC at 4.6; Clang at 3.3; Intel 10.0; SunCC 5.13. #if (CRYPTOPP_MSC_VERSION >= 1600) # define CRYPTOPP_CXX11_NULLPTR 1 -#elif (__INTEL_COMPILER >= 1200) +#elif __has_feature(cxx_nullptr) +# define CRYPTOPP_CXX11_NULLPTR 1 +#elif (__INTEL_COMPILER >= 1000) # define CRYPTOPP_CXX11_NULLPTR 1 -#elif defined(__clang__) -# if __has_feature(cxx_nullptr) -# define CRYPTOPP_CXX11_NULLPTR 1 -# endif #elif (CRYPTOPP_GCC_VERSION >= 40600) # define CRYPTOPP_CXX11_NULLPTR 1 #elif (__SUNPRO_CC >= 0x5130) diff --git a/misc.h b/misc.h index 0841045c..6bb2d4c2 100644 --- a/misc.h +++ b/misc.h @@ -290,7 +290,7 @@ struct NewObject //! \brief Restricts the instantiation of a class to one static object without locks //! \tparam T the class or type //! \tparam F the object factory for T -//! \tparam instance the initiali instance count +//! \tparam instance an instance counter for the class object //! \details This class safely initializes a static object in a multithreaded environment. For C++03 //! and below it will do so without using locks for portability. If two threads call Ref() at the same //! time, they may get back different references, and one object may end up being memory leaked. This @@ -298,8 +298,14 @@ struct NewObject //! local storage on early Windows platforms, like Windows XP and Windows 2003. //! \details For C++11 and above, a standard double-checked locking pattern with thread fences //! are used. The locks and fences are standard and do not hinder portability. -//! \sa Double-Checked -//! Locking is Fixed In C++11 +//! \details Microsoft's C++11 implementation provides the necessary primitive support on Windows Vista and +//! above when using Visual Studio 2015 (cl.exe version 19.00). If C++11 is desired, you should +//! set WINVER or _WIN32_WINNT to 0x600 (or above), and compile with Visual Studio 2015. +//! \sa Double-Checked Locking +//! is Fixed In C++11, Dynamic +//! Initialization and Destruction with Concurrency and +//! Thread Local Storage (TLS) on MSDN. +//! \since Crypto++ 5.2 template , int instance=0> class Singleton { @@ -316,13 +322,15 @@ private: //! \brief Return a reference to the inner Singleton object //! \tparam T the class or type //! \tparam F the object factory for T +//! \tparam instance an instance counter for the class object //! \details Ref() is used to create the object using the object factory. The //! object is only created once with the limitations discussed in the class documentation. //! \sa Double-Checked Locking is Fixed In C++11 -#if defined(CRYPTOPP_CXX11_ATOMICS) && defined(CRYPTOPP_CXX11_SYNCHRONIZATION) +//! \since Crypto++ 5.2 template const T & Singleton::Ref(CRYPTOPP_NOINLINE_DOTDOTDOT) const { +#if defined(CRYPTOPP_CXX11_ATOMICS) && defined(CRYPTOPP_CXX11_SYNCHRONIZATION) && defined(CRYPTOPP_CXX11_DYNAMIC_INIT) static std::mutex s_mutex; static std::atomic s_pObject; @@ -344,11 +352,7 @@ template std::atomic_thread_fence(std::memory_order_release); return *newObject; -} #else -template -const T & Singleton::Ref(CRYPTOPP_NOINLINE_DOTDOTDOT) const -{ static volatile simple_ptr s_pObject; T *p = s_pObject.m_p; MEMORY_BARRIER(); @@ -370,8 +374,8 @@ const T & Singleton::Ref(CRYPTOPP_NOINLINE_DOTDOTDOT) const MEMORY_BARRIER(); return *newObject; -} #endif +} // ************** misc functions *************** diff --git a/trdlocal.cpp b/trdlocal.cpp index beb21e98..a4c3b683 100644 --- a/trdlocal.cpp +++ b/trdlocal.cpp @@ -26,6 +26,8 @@ ThreadLocalStorage::Err::Err(const std::string& operation, int error) { } +// Windows: "a process may have up to TLS_MINIMUM_AVAILABLE indexes (guaranteed to be greater than +// or equal to 64)", https://support.microsoft.com/en-us/help/94804/info-thread-local-storage-overview ThreadLocalStorage::ThreadLocalStorage() { #ifdef HAS_WINTHREADS