Opened 7 years ago

Last modified 7 years ago

#5673 new Bugs

Quick allocator error in multi thread

Reported by: Yury Podpruzhnikov <QWERTYura@…> 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 Changed 7 years ago by Steven Watanabe

Component: Nonesmart_ptr
Owner: set to Peter Dimov

comment:2 Changed 7 years ago by f@…

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?

comment:3 Changed 7 years ago by Yury Podpruzhnikov <QWERTYura@…>

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.

Note: See TracTickets for help on using tickets.