Search code examples
visual-c++shared-ptraccess-violation

Access violation, when using shared_ptr on legacy code


I implement a new module using shared_ptr etc. in our legacy app, however I get a access violation, when shared_ptr is calling the destructor.

app:

case ENUM_DATA:
{
    std::tr1::shared_ptr<CDataMsg> msg(new CDataMsg(_stringmsg)); // _stringmsg is initialized before
    Process(msg);
    break;
}

Process():

bool Process(std::tr1::shared_ptr<CDataMsg> msg)
{
    try
    {
        switch (msg->getDataType())
        {
            case ENUM_MYDATATYPE:
            {
                std::tr1::shared_ptr<CMyData> base(msg->getData());
                std::tr1::shared_ptr<CMyDataChild> data(std::tr1::static_pointer_cast<CMyDataChild>(base));

                // do some stuff with data
                std::tr1::shared_ptr<CRequest> request(new CRequest(data->getParam1(), data->getParam2()));
                handler->AddRequest(request->getBin());
                break;
            }
            default:;
        }
        return true;
    }
    catch (...)
    {
        // exception handling
    }
    return false;
}

Destructor:

CDataMsg::~CDataMsg()
{
    if (m_data)
        delete m_data;
    m_data = NULL;
}

m_data is a CMyData* (cannot be changed at this point).

CDataMsg is a container, which holds data of type CMyData. CmyDataChild is a subclass of CMyData, which is used here.

I have breakpoint in the destructor, but the debugger stops only, when shared_ptr is calling it and then I get the access violation already.


Solution

  • As you have confirmed in your comment msg->getData() returns a pointer to a member variable of msg (presumably m_data) and it will be deleted when this switch block scope exits:

    case ENUM_MYDATATYPE:
    {
        std::tr1::shared_ptr<CMyData> base(msg->getData());
        std::tr1::shared_ptr<CMyDataChild>
            data(std::tr1::static_pointer_cast<CMyDataChild>(base));
    
        // do some stuff with data
        std::tr1::shared_ptr<CRequest>
            request(new CRequest(data->getParam1(), data->getParam2()));
        handler->AddRequest(request->getBin());
        break;
    }
    

    The destructor of msg will be invoked later when this switch block scope exits:

    case ENUM_DATA:
    {
        std::tr1::shared_ptr<CDataMsg> msg(new CDataMsg(_stringmsg));
        Process(msg);
        break;
    }
    

    and attempt to redelete the member variable m_data.

    Also:

    case ENUM_MYDATATYPE:
    {
        std::tr1::shared_ptr<CMyData> base(msg->getData());
        std::tr1::shared_ptr<CMyDataChild>
            data(std::tr1::static_pointer_cast<CMyDataChild>(base));
        ...
    }
    

    data is pointing to the same object as base. When this scope exits base will be deleteded twice.