Boost logo

Boost :

From: Matt Hunt (nekral_at_[hidden])
Date: 2008-02-26 13:07:28


I have encountered a bug when using BOOST_SP_USE_QUICK_ALLOCATOR with
shared_ptr<> objects that are contained in a static container. This bug is
verifiable with Visual Studio 2005 SP1 as well as MinGW GCC 4.2.1.

As an example, I have created a static std::map, which pairs a long with a
boost::shared_ptr<>. This is the scenario where I first encountered the
bug. The boost preprocessor definition BOOST_SP_USE_QUICK_ALLOCATOR is
defined. When the program exists, the application crashes during
deallocation of the shared_ptrs. Under Visual Studio 2005,
MSVCR80d.dllcrashes during _free_dbg() (and likewise
MSVCR80.dll crashes during _free()).

If the map is made a regular member instead of a static member, the program
exits properly. In addition, if the boost quick allocator is disabled, the
program exits properly. In my testing, I have found the key type is
irrelevant, and what the shared_ptr points to also does not matter. The
issue is with the Quick Allocator and the runtime cleanup of static objects.

Here is an example console app. that will produce the problem.

-------------------

// Boost Headers
#define BOOST_SP_USE_QUICK_ALLOCATOR
#include <boost/shared_ptr.hpp>

// STL Map
#include <map>

// Test struct for Shared Pointer
struct tTestItem
{
    long x;
};

// Test Class to use static map
class tTestClass
{
public:
    tTestClass(long id)
    {
        boost::shared_ptr<tTestItem> xTestItem(new tTestItem());
        m_TestMap.insert(std::make_pair<long, boost::shared_ptr<tTestItem>
>(id, xTestItem));
    }

private:
    static std::map<long, boost::shared_ptr<tTestItem> > m_TestMap;
};

// Create Static Instance
std::map<long, boost::shared_ptr<tTestItem> > tTestClass::m_TestMap;

// Simple Main App
int main()
{
    tTestClass class1(1);
    tTestClass class2(2);

    return 0;
}

-------------------

Under Visual Studio, the problem can be detected as follows:

In boost\detail\lwm_win32_cs.hpp, put breakpoints in (1) lightweight_mutex's
ctor, (2) lightweight_mutex's dtor, and (3) scoped_lock's ctor. In
boost\detail\quick_allocator.hpp, put breakpoints in allocator_impl<size,
align_>'s (4) mutex(), (5) alloc(), and (6) dealloc().

Run the program.

(5) [alloc()] fires. We're constructing class1, which is constructing a
shared_ptr.
(4) [mutex()] fires, as alloc() calls mutex().
(1) [lightweight_mutex's ctor] fires, as mutex() constructs a static
lightweight_mutex.
(3) [scoped_lock's ctor] fires, as alloc() then constructs a scoped_lock
from the static lightweight_mutex.
(5), (4), and (3) then fire as we construct class2 (the static
lightweight_mutex has already been constructed, so (1) doesn't run again.)
(2) [lightweight_mutex's dtor] fires, as we exit main() and destroy the
static lightweight_mutex.
(6) [dealloc()] fires, as we exit main() and destroy the static map and its
contained shared_ptrs.
(4) [mutex()] fires, returning a reference to the destroyed static
lightweight_mutex.
(3) [scoped_lock's ctor] fires, which calls EnterCriticalSection() with a
trashed CRITICAL_SECTION, which causes the program to crash.

Please let me know if I am misusing boost functionality in the above test
application.

Sincerely,

Matthew Hunt


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk