Opened 11 years ago
Last modified 11 years ago
#5673 new Bugs
Quick allocator error in multi thread
| Reported by: | Owned by: | Peter Dimov | |
|---|---|---|---|
| Milestone: | To Be Determined | Component: | smart_ptr |
| Version: | Boost 1.44.0 | Severity: | Problem |
| Keywords: | Cc: |
Description
Compiler: MSVS 2008 use macros BOOST_SP_USE_QUICK_ALLOCATOR
Exception (Access vialation by reading address) occured by constructor of shared_ptr.
Cause of exception is multi thread creation of static mutex in quick allocator.
shared_ptr call quick allocator. quick allocator use next code:
lightweight_mutex::scoped_lock lock( mutex() );
function mutex() return internal static variable:
boost_1_44_0\boost\smart_ptr\detail\quick_allocator.hpp
template<unsigned size, unsigned align_> struct allocator_impl
{
...
static lightweight_mutex & mutex()
{
static freeblock< sizeof( lightweight_mutex ), boost::alignment_of< lightweight_mutex >::value > fbm;
static lightweight_mutex * pm = new( &fbm ) lightweight_mutex;
return *pm;
}
...
}
2 thread call mutex() (first time for this instantiation of template class allocator_impl). One start init pm and go to sleep. Other check that pm is initialized and return its value (in my case NULL) and raise exception.
Initialization of static variable in C++ is not safe for multi thread. This code is incorrect. In dependence from realization of static variable you will be have access vialation or memory leak - flag of static variable initialization (construction) set before or after initialization.
In MSVS 2008 flag set before and you take access vialation.
Decision
Not resolve, but minimize problem.
Idea:
As I understand, This problem can appear in first initialization of every instantiation of shared_ptr - first use every instantiation of allocator_impl.
If you synchronize of initialization pm then problem can appear only first initialization of any instantiation of shared_ptr. And I can create first fictive shared_ptr in non-multi thread and then normal use shared_ptr in multi thread.
Realization:
boost_1_44_0\boost\smart_ptr\detail\quick_allocator.hpp
lightweight_mutex & global_mutex()
{
static freeblock< sizeof( lightweight_mutex ), boost::alignment_of< lightweight_mutex >::value > fbm;
static lightweight_mutex * pm = new( &fbm ) lightweight_mutex;
return *pm;
}
template<unsigned size, unsigned align_> struct allocator_impl
{
static lightweight_mutex & mutex()
{
static freeblock< sizeof( lightweight_mutex ), boost::alignment_of< lightweight_mutex >::value > fbm;
static lightweight_mutex * pm = NULL;
if(pm == NULL)
{
lightweight_mutex::scoped_lock lock( global_mutex() );
if(pm == NULL)
{
pm = new( &fbm ) lightweight_mutex;
}
}
return *pm;
}
}
Change History (3)
comment:1 by , 11 years ago
| Component: | None → smart_ptr |
|---|---|
| Owner: | set to |
comment:2 by , 11 years ago
comment:3 by , 11 years ago
With global_mutex I can protect me from crash.
At start (then I have only one thread) I can create first fictive shared_ptr. It initialize global_mutex. And next usage of any shared_ptr will be synchronize.
Now I not sure in usage of shared_ptr because first usage new instantiation could use new mutex and produce crash.

Hi, why does this global_mutex minimize the problem?
Now thread A gets until gloabal_mutex init pm and then sleeps. During that time thread B goes to global_mutex and will get e.g. NULL and crash.
Am I missing something?