Modify

Opened 6 years ago

Last modified 6 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;
     }
}

Attachments (0)

Change History (3)

comment:1 Changed 6 years ago by Steven Watanabe

Component: Nonesmart_ptr
Owner: set to Peter Dimov

comment:2 Changed 6 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 6 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.

Modify Ticket

Change Properties
Set your email in Preferences
Action
as new The owner will remain Peter Dimov.

Add Comment


E-mail address and name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.