Actually, for number of threads >=3 this patch is better:
--- old/libstdc++-v3/include/bits/basic_string.h	2012-05-30 17:03:15.974035000 -0400
+++ new/libstdc++-v3/include/bits/basic_string.h	2012-05-31 13:06:39.903442000 -0400
@@ -224,14 +224,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	_M_refdata() throw()
 	{ return reinterpret_cast<_CharT*>(this + 1); }
 
 	_CharT*
 	_M_grab(const _Alloc& __alloc1, const _Alloc& __alloc2)
 	{
-	  return (!_M_is_leaked() && __alloc1 == __alloc2)
-	          ? _M_refcopy() : _M_clone(__alloc1);
+          _CharT* res = (_CharT*)0;
+	  if(!_M_is_leaked() && __alloc1 == __alloc2) {
+            res = _M_refcopy();
+          }
+          if (res == (_CharT*)0) {
+            res = _M_clone(__alloc1);
+          }
+          return res;
 	}
 
 	// Create & Destroy
 	static _Rep*
 	_S_create(size_type, size_type, const _Alloc&);
 
@@ -259,13 +265,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	_CharT*
 	_M_refcopy() throw()
 	{
 #if _GLIBCXX_FULLY_DYNAMIC_STRING == 0
 	  if (__builtin_expect(this != &_S_empty_rep(), false))
 #endif
-            __gnu_cxx::__atomic_add_dispatch(&this->_M_refcount, 1);
+          {
+            // Here we try to detect and compensate an unexpected decrement of
+            // _M_refcount from another thread. In the properly designed code
+            // this should not happen ever! If we do nothing about this
+            // condition then the string is going to be freed twice.
+            // Unfortunatelly, some cases that lead to this condition are not
+            // obvious for the developers, e.g. non-constant
+            // methods operator [], at(), begin, end, etc.
+            // In many of these cases the string is not going to be
+            // changed from another thread and it's actually safe to
+            // clone the string.
+            if (__gnu_cxx::__exchange_and_add_dispatch(&this->_M_refcount, 1) < 0) {
+              __gnu_cxx::__atomic_add_dispatch(&this->_M_refcount, -1);
+              return (_CharT*)0;
+            }
+          }
 	  return _M_refdata();
 	}  // XXX MT
 
 	_CharT*
 	_M_clone(const _Alloc&, size_type __res = 0);
       };

Reply via email to