fix possible race condition in Singleton::Ref()

tolerate double destruction of Singleton and g_nullNameValuePairs
fix #include of standard headers
import/raw
weidai 2010-06-18 07:06:59 +00:00
parent a84dd77076
commit 227b0810cf
7 changed files with 45 additions and 57 deletions

View File

@ -30,7 +30,14 @@ const std::string DEFAULT_CHANNEL;
const std::string AAD_CHANNEL = "AAD"; const std::string AAD_CHANNEL = "AAD";
const std::string &BufferedTransformation::NULL_CHANNEL = DEFAULT_CHANNEL; const std::string &BufferedTransformation::NULL_CHANNEL = DEFAULT_CHANNEL;
const NullNameValuePairs g_nullNameValuePairs; class NullNameValuePairs : public NameValuePairs
{
public:
bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const {return false;}
};
simple_ptr<NullNameValuePairs> s_pNullNameValuePairs(new NullNameValuePairs);
const NameValuePairs &g_nullNameValuePairs = *s_pNullNameValuePairs.m_p;
BufferedTransformation & TheBitBucket() BufferedTransformation & TheBitBucket()
{ {

View File

@ -318,14 +318,7 @@ DOCUMENTED_NAMESPACE_BEGIN(Name)
DOCUMENTED_NAMESPACE_END DOCUMENTED_NAMESPACE_END
//! empty set of name-value pairs //! empty set of name-value pairs
class CRYPTOPP_DLL NullNameValuePairs : public NameValuePairs extern CRYPTOPP_DLL const NameValuePairs &g_nullNameValuePairs;
{
public:
bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const {return false;}
};
//! _
extern CRYPTOPP_DLL const NullNameValuePairs g_nullNameValuePairs;
// ******************************************************** // ********************************************************

View File

@ -6,7 +6,6 @@
#include <string.h> // for memcpy and memmove #include <string.h> // for memcpy and memmove
#ifdef _MSC_VER #ifdef _MSC_VER
#include <stdlib.h>
#if _MSC_VER >= 1400 #if _MSC_VER >= 1400
// VC2005 workaround: disable declarations that conflict with winnt.h // VC2005 workaround: disable declarations that conflict with winnt.h
#define _interlockedbittestandset CRYPTOPP_DISABLED_INTRINSIC_1 #define _interlockedbittestandset CRYPTOPP_DISABLED_INTRINSIC_1
@ -101,9 +100,9 @@ struct NewObject
T* operator()() const {return new T;} T* operator()() const {return new T;}
}; };
/*! This function safely initializes a static object in a multithreaded environment without using locks. /*! This function safely initializes a static object in a multithreaded environment without using locks (for portability).
It may leak memory when two threads try to initialize the static object at the same time Note that if two threads call Ref() at the same time, they may get back different references, and one object
but this should be acceptable since each static object is only initialized once per session. may end up being memory leaked. This is by design.
*/ */
template <class T, class F = NewObject<T>, int instance=0> template <class T, class F = NewObject<T>, int instance=0>
class Singleton class Singleton
@ -121,31 +120,23 @@ private:
template <class T, class F, int instance> template <class T, class F, int instance>
const T & Singleton<T, F, instance>::Ref(CRYPTOPP_NOINLINE_DOTDOTDOT) const const T & Singleton<T, F, instance>::Ref(CRYPTOPP_NOINLINE_DOTDOTDOT) const
{ {
static simple_ptr<T> s_pObject; static volatile simple_ptr<T> s_pObject;
static volatile char s_objectState = 0; T *p = s_pObject.m_p;
retry: if (p)
switch (s_objectState) return *p;
T *newObject = m_objectFactory();
p = s_pObject.m_p;
if (p)
{ {
case 0: delete newObject;
s_objectState = 1; return *p;
try
{
s_pObject.m_p = m_objectFactory();
}
catch(...)
{
s_objectState = 0;
throw;
}
s_objectState = 2;
break;
case 1:
goto retry;
default:
break;
} }
return *s_pObject.m_p;
s_pObject.m_p = newObject;
return *newObject;
} }
// ************** misc functions *************** // ************** misc functions ***************
@ -555,7 +546,7 @@ static std::string StringNarrow(const wchar_t *str, bool throwOnError = true)
#pragma warning(disable: 4996) // 'wcstombs': This function or variable may be unsafe. #pragma warning(disable: 4996) // 'wcstombs': This function or variable may be unsafe.
#endif #endif
size_t size = wcstombs(NULL, str, 0); size_t size = wcstombs(NULL, str, 0);
if (size == -1) if (size == size_t(0)-1)
{ {
if (throwOnError) if (throwOnError)
throw InvalidArgument("StringNarrow: wcstombs() call failed"); throw InvalidArgument("StringNarrow: wcstombs() call failed");

View File

@ -69,14 +69,6 @@ being unloaded from L1 cache, until that round is finished.
#include "misc.h" #include "misc.h"
#include "cpu.h" #include "cpu.h"
#ifdef __sun
#include <alloca.h>
#endif
#ifdef __MINGW32__
#include <malloc.h>
#endif
NAMESPACE_BEGIN(CryptoPP) NAMESPACE_BEGIN(CryptoPP)
#ifdef CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS #ifdef CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS

View File

@ -9,8 +9,6 @@
#if defined(CRYPTOPP_MEMALIGN_AVAILABLE) || defined(CRYPTOPP_MM_MALLOC_AVAILABLE) || defined(QNX) #if defined(CRYPTOPP_MEMALIGN_AVAILABLE) || defined(CRYPTOPP_MM_MALLOC_AVAILABLE) || defined(QNX)
#include <malloc.h> #include <malloc.h>
#else
#include <stdlib.h>
#endif #endif
NAMESPACE_BEGIN(CryptoPP) NAMESPACE_BEGIN(CryptoPP)
@ -352,8 +350,11 @@ public:
//! copy contents and size from another SecBlock //! copy contents and size from another SecBlock
void Assign(const SecBlock<T, A> &t) void Assign(const SecBlock<T, A> &t)
{ {
New(t.m_size); if (this != &t)
memcpy_s(m_ptr, m_size*sizeof(T), t.m_ptr, m_size*sizeof(T)); {
New(t.m_size);
memcpy_s(m_ptr, m_size*sizeof(T), t.m_ptr, m_size*sizeof(T));
}
} }
SecBlock<T, A>& operator=(const SecBlock<T, A> &t) SecBlock<T, A>& operator=(const SecBlock<T, A> &t)

View File

@ -9,8 +9,8 @@ NAMESPACE_BEGIN(CryptoPP)
template <class T> class simple_ptr template <class T> class simple_ptr
{ {
public: public:
simple_ptr() : m_p(NULL) {} simple_ptr(T *p = NULL) : m_p(p) {}
~simple_ptr() {delete m_p;} ~simple_ptr() {delete m_p; m_p = NULL;} // set m_p to NULL so double destruction (which might occur in Singleton) will be harmless
T *m_p; T *m_p;
}; };

View File

@ -4,24 +4,28 @@
#include <stddef.h> #include <stddef.h>
#include <assert.h> #include <assert.h>
#include <limits.h> #include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <memory> #include <memory>
#include <string> #include <string>
#include <exception> #include <exception>
#include <typeinfo> #include <typeinfo>
#ifdef _MSC_VER
#include <string.h> // CodeWarrior doesn't have memory.h
#include <algorithm> #include <algorithm>
#include <map> #include <map>
#include <vector> #include <vector>
// re-disable this // for alloca
#pragma warning(disable: 4231) #ifdef __sun
#include <alloca.h>
#elif defined(__MINGW32__)
#include <malloc.h>
#endif #endif
#if defined(_MSC_VER) && defined(_CRTAPI1) #ifdef _MSC_VER
#pragma warning(disable: 4231) // re-disable this
#ifdef _CRTAPI1
#define CRYPTOPP_MSVCRT6 #define CRYPTOPP_MSVCRT6
#endif #endif
#endif
#endif #endif