Opened 8 years ago

Closed 8 years ago

#11053 closed Bugs (fixed)

The attached code results in a R6025 - pure virtual function call in run_thread_exit_callbacks

Reported by: swebb3@… Owned by: viboes
Milestone: Boost 1.58.0 Component: thread
Version: Boost 1.55.0 Severity: Problem
Keywords: Cc:

Description (last modified by viboes)

Caused when deallocating a thread specific pointer in a object that is inside thread specific data. I suggest changing the code in run_thread_exit_callbacks from

for(std::map<void const*,detail::tss_data_node>::iterator next=current_thread_data->tss_data.begin(),
    current,
    end=current_thread_data->tss_data.end();
    next!=end;)
{
    current=next;
    ++next;
    if(current->second.func && (current->second.value!=0))
    {
        (*current->second.func)(current->second.value);
    }
    current_thread_data->tss_data.erase(current);
}

to

while (!current_thread_data->tss_data.empty())
{
    std::map<void const*,detail::tss_data_node>::iterator current
        = current_thread_data->tss_data.begin();
    if(current->second.func && (current->second.value!=0))
    {
        (*current->second.func)(current->second.value);
    }
    current_thread_data->tss_data.erase(current);
}

Code to reproduce the problem:

#include <boost/thread.hpp>
#include <boost/thread/tss.hpp>
#include <boost/shared_ptr.hpp>
#include <iostream>

struct A
{
    void DoWork()
    {
        std::cout << "A: doing work\n";
        if (!m_ptr.get())
            m_ptr.reset(new WorkSpace());
        // do not very much
        for (size_t i = 0; i < 10; ++i)
            m_ptr->a += 10;
    }

private:
    struct WorkSpace
    {
        int a;
        WorkSpace() : a(0) {}
    };
    boost::thread_specific_ptr<WorkSpace> m_ptr;
};

struct B
{
    void DoWork()
    {
        std::cout << "B: doing work\n";
        if (!m_ptr.get())
            m_ptr.reset(new A());
        m_ptr->DoWork();
    }
private:
    boost::thread_specific_ptr<A> m_ptr;
};

struct C
{
    void DoWork()
    {
        std::cout << "C: doing work\n";
        if (!m_ptr.get())
            m_ptr.reset(new B());
        m_ptr->DoWork();
    }
private:
    boost::thread_specific_ptr<B> m_ptr;
};

int main(int ac, char** av)
{
    std::cout << "test starting\n";
    boost::shared_ptr<C> p_C(new C);
    boost::thread cWorker(&C::DoWork, p_C);
    cWorker.join();
    std::cout << "test stopping\n";
}

Compiler visual studio 2012

Change History (4)

comment:1 by viboes, 8 years ago

Owner: changed from Anthony Williams to viboes
Status: newassigned

Thanks for catching this bug.

It is also reproducible on POSIX platform and the code to be replaced is similar.

comment:2 by viboes, 8 years ago

Description: modified (diff)

comment:4 by viboes, 8 years ago

Resolution: fixed
Status: assignedclosed
Note: See TracTickets for help on using tickets.