Борьба - еще одна проблема с повреждением памяти, неправильное размещение (C++, VS 2008)

Я прочитал много сообщений о повреждении памяти, и кажется, что это может быть довольно сложной проблемой. Когда я запускаю свой код на моей машине с Linux, он работает нормально, и valgrind не сообщает об утечках или ошибках. Однако, когда я запускаю код на компьютере своей лаборатории с Windows с VS2008, я получаю неверную ошибку alloc, останавливаясь с _RAISE(nomem). Это кажется мне странным, потому что я ожидал, что Вальгринд поймает его.

void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
    {       // try to allocate size bytes
    void *p;
    while ((p = malloc(size)) == 0)
            if (_callnewh(size) == 0)
            {       // report no memory
            static const std::bad_alloc nomem;
            _RAISE(nomem);
            }

    return (p);
    }

Из того, что я прочитал, кажется, что эта проблема часто возникает из-за того, что после конца выделенного блока памяти происходит запись или после того, как он был освобожден, но мне не повезло определить, где это может происходить. Вот мой стек вызовов после попытки запустить сборку Release.

KernelBase.dll!_RaiseException@16()  + 0x58 bytes   
msvcr90.dll!_CxxThrowException(void * pExceptionObject=0x0040f6d4, const _s__ThrowInfo * pThrowInfo=0x6f63d604)  Line 161   C++
msvcr90.dll!operator new(unsigned int size=4)  Line 63 + 0x17 bytes C++
tempMem.exe!std::vector<unsigned char,std::allocator<unsigned char> >::vector<unsigned char,std::allocator<unsigned char> >(const std::vector<unsigned char,std::allocator<unsigned char> > & _Right=[...]())  Line 500 + 0x31 bytes    C++
tempMem.exe!DendriteSegment::DendriteSegment(const DendriteSegment & __that={...})  + 0x4a bytes    C++
tempMem.exe!std::list<DendriteSegment,std::allocator<DendriteSegment> >::_Buynode(std::_List_nod<DendriteSegment,std::allocator<DendriteSegment> >::_Node * _Next=0x005d84d0, std::_List_nod<DendriteSegment,std::allocator<DendriteSegment> >::_Node * _Prev=0x0093af50, const DendriteSegment & _Val={...})  Line 1208    C++
tempMem.exe!TP::adaptSegments(Cell * & cellToAdapt=0x005d8450, std::list<segUpdate,std::allocator<segUpdate> > & segUpdateList=[1]({segToUpdate=0x00000000 synapseChanges=[0]() newSynapsesToAdd=[2](0x005bc8f8 {DSlist=[19]({sequenceSegment=true synapse=[3](0x005d79a0 {DSlist={...} connected=0x005d7af8 currentState=0x005d79c0 ...},0x005d7ef8 {DSlist={...} connected=0x005d8050 currentState=0x005d7f18 ...},0x005d8450 {DSlist={...} connected=0x005d85a8 currentState=0x005d8470 ...}) permanence=[3](80 'P',80 'P',80 'P') ...},.  ), bool posReinforce=true)  Line 701 + 0x1b bytes C++
tempMem.exe!Level::TPlearning()  Line 236 + 0x26 bytes  C++
tempMem.exe!main(int argc=, char * * argv=)  Line 96    C++
msvcr90.dll!_encode_pointer(void * ptr=0x6f5d3607)  Line 114 + 0x5 bytes    C
0069ee20()  
msvcr90.dll!_initterm(void (void)* * pfbegin=0x00000001, void (void)* * pfend=0x000a1ef8)  Line 903 C
tempMem.exe!__tmainCRTStartup()  Line 582 + 0x17 bytes  C
kernel32.dll!@BaseThreadInitThunk@12()  + 0x12 bytes    
ntdll.dll!___RtlUserThreadStart@8()  + 0x27 bytes   
ntdll.dll!__RtlUserThreadStart@8()  + 0x1b bytes

Когда я запускаю сеанс отладки, я получаю другую ошибку (хотя, похоже, это происходит не всегда...)

return HeapAlloc(_crtheap, 0, size ? size : 1);

отсюда

#ifdef _WIN64
return HeapAlloc(_crtheap, 0, size ? size : 1);
#else  /* _WIN64 */
if (__active_heap == __SYSTEM_HEAP) {
    return HeapAlloc(_crtheap, 0, size ? size : 1);
} else
if ( __active_heap == __V6_HEAP ) {
    if (pvReturn = V6_HeapAlloc(size)) {
        return pvReturn;
    }
}

В этом случае стек вызовов

 ntdll.dll!_RtlpBreakPointHeap@4()  + 0x23 bytes    
ntdll.dll!@RtlpAllocateHeap@24()  + 0x57dbc bytes   
ntdll.dll!_RtlAllocateHeap@12()  + 0x502a bytes 
ntdll.dll!_RtlDebugAllocateHeap@12()  + 0xb5 bytes  
ntdll.dll!@RtlpAllocateHeap@24()  + 0x57c17 bytes   
ntdll.dll!_RtlAllocateHeap@12()  + 0x502a bytes 
msvcr90d.dll!_heap_alloc_base(unsigned int size=38)  Line 105 + 0x28 bytes  C
msvcr90d.dll!_heap_alloc_dbg_impl(unsigned int nSize=2, int nBlockUse=1, const char * szFileName=0x00000000, int nLine=0, int * errno_tmp=0x0052f284)  Line 427 + 0x9 bytes C++
msvcr90d.dll!_nh_malloc_dbg_impl(unsigned int nSize=2, int nhFlag=0, int nBlockUse=1, const char * szFileName=0x00000000, int nLine=0, int * errno_tmp=0x0052f284)  Line 239 + 0x19 bytes   C++
msvcr90d.dll!_nh_malloc_dbg(unsigned int nSize=2, int nhFlag=0, int nBlockUse=1, const char * szFileName=0x00000000, int nLine=0)  Line 296 + 0x1d bytes    C++
msvcr90d.dll!malloc(unsigned int nSize=2)  Line 56 + 0x15 bytes C++
msvcr90d.dll!operator new(unsigned int size=2)  Line 59 + 0x9 bytes C++
tempMem.exe!std::_Allocate(unsigned int _Count=2)  Line 43 + 0xc bytes  C++
tempMem.exe!std::allocator<uint8_t>::allocate(unsigned int _Count=2)  Line 145 + 0x13 bytes C++
tempMem.exe!std::::_Buy(unsigned int _Capacity=2)  Line 1115 + 0x14 bytes   C++
tempMem.exe!std::::vector(const std::vector<uint8_t, std::allocator<uint8_t> > & _Right=[2](80 'P',80 'P'))  Line 501 + 0x2b bytes  C++
tempMem.exe!DendriteSegment::DendriteSegment()  + 0x8b bytes    C++
tempMem.exe!std::_Construct(DendriteSegment * _Ptr=0x007e7490, const DendriteSegment & _Val={...})  Line 52 + 0x97 bytes    C++
tempMem.exe!std::allocator<DendriteSegment>::construct(DendriteSegment * _Ptr=0x007e7490, const DendriteSegment & _Val={...})  Line 155 + 0x15 bytes    C++
tempMem.exe!std::::_Buynode(std::_List_nod<DendriteSegment, std::allocator<DendriteSegment> >::_Node * _Next=0x00637f60, std::_List_nod<DendriteSegment, std::allocator<DendriteSegment> >::_Node * _Prev=0x00bfcb50, const DendriteSegment & _Val={...})  Line 1199 + 0x47 bytes   C++
tempMem.exe!std::::_Insert(std::list<DendriteSegment, std::allocator<DendriteSegment> >::_Const_iterator<1> _Where={sequenceSegment=true synapse=[0]() permanence=[0]() ...}, const DendriteSegment & _Val={...})  Line 718 + 0x65 bytes    C++
tempMem.exe!std::::push_back(const DendriteSegment & _Val={...})  Line 670 + 0x6f bytes C++
tempMem.exe!TP::adaptSegments(Cell * & cellToAdapt=0x00637ee8, std::list<segUpdate, std::allocator<segUpdate> > & segUpdateList=[1](...), bool posReinforce=true)  Line 701 + 0x16 bytes    C++
tempMem.exe!TP::phase3()  Line 949 + 0x3e bytes C++
tempMem.exe!Col::TPphase3()  Line 398 + 0xd bytes   C++
tempMem.exe!Level::TPlearning()  Line 236 + 0x4a bytes  C++
tempMem.exe!Network::runTPlearning()  Line 93 + 0xd bytes   C++
tempMem.exe!main(int argc=1, char * * argv=0x006f62a0)  Line 93 + 0xd bytes C++
tempMem.exe!__tmainCRTStartup()  Line 582 + 0x19 bytes  C
tempMem.exe!mainCRTStartup()  Line 399  C
kernel32.dll!@BaseThreadInitThunk@12()  + 0x12 bytes    
ntdll.dll!___RtlUserThreadStart@8()  + 0x27 bytes   
ntdll.dll!__RtlUserThreadStart@8()  + 0x1b bytes    

Я впервые отлаживаю проблему такого типа, и я надеюсь, что просто упускаю из виду / неправильно понимаю нечто очевидное...

Вот код для функции adaptSegments, которая соответствует этой строке из стека вызовов (Release)

tempMem.exe!TP::adaptSegments(Cell * & cellToAdapt=0x005d8450, std::list<segUpdate,std::allocator<segUpdate> > & segUpdateList=[1]({segToUpdate=0x00000000 synapseChanges=[0]() newSynapsesToAdd=[2](0x005bc8f8 {DSlist=[19]({sequenceSegment=true synapse=[3](0x005d79a0 {DSlist={...} connected=0x005d7af8 currentState=0x005d79c0 ...},0x005d7ef8 {DSlist={...} connected=0x005d8050 currentState=0x005d7f18 ...},0x005d8450 {DSlist={...} connected=0x005d85a8 currentState=0x005d8470 ...}) permanence=[3](80 'P',80 'P',80 'P') ...},.  ), bool posReinforce=true)  Line 701 + 0x1b bytes

bool TP::adaptSegments(Cell *& cellToAdapt,
std::list<segUpdate> & segUpdateList, bool posReinforce)
{
std::list<segUpdate>::iterator curSegUpdate;
std::list<activeSynapsePair>::iterator curSyn;
std::list<Cell *>::iterator synToAdd;
int size = 0;

//for each segUpdate element in the cell's segUpdateList
for (curSegUpdate = segUpdateList.begin(); 
        curSegUpdate != segUpdateList.end(); ++curSegUpdate)
{
    //if the segment already exists
    if (curSegUpdate->segToUpdate != NULL)
    {
        //if sequence segment flag is true, set it on DS
        if(curSegUpdate->sequenceSegment == true)
        {curSegUpdate->segToUpdate->sequenceSegment = true;} 
        if (posReinforce == true)
        {
            //for each synapses permanence pair in segUpdate
            for (curSyn = (curSegUpdate->
            synapseChanges.begin());
            curSyn !=(curSegUpdate->synapseChanges.end());
            ++curSyn)
            {
                //decrement inactive synapses
                if (curSyn->second == false)
                {
                    if (*(curSyn->first)-
                        permanenceDec < 0)
                        {*(curSyn->first) = 0;}
                    else
                    {*(curSyn->first)-=
                            permanenceDec;}
                }
                //increment active synapses
                else if (curSyn->second == true)
                {
                    if (*(curSyn->first)+
                        permanenceInc > 100)
                        {*(curSyn->first) =100;}
                    else
                    {*(curSyn->first)+=
                            permanenceInc;}
                }
            }
        }
        else if (posReinforce == false)
        {
            //for each synapses permanence pair in segUpdate
            for (curSyn = (curSegUpdate->
                synapseChanges.begin());
            curSyn !=(curSegUpdate->synapseChanges.end());
            ++curSyn)
            {
                //decrement active synapses
                if (curSyn->second == true)
                {
                    if (*(curSyn->first)-
                        permanenceDec < 0)
                        {*(curSyn->first) = 0;}
                    else
                    {*(curSyn->first)-=
                            permanenceDec;}
                }
            }
        }
        //if adding synapses to an existing segment
        if (curSegUpdate->newSynapsesToAdd.empty()==false)
        {
            if (curSegUpdate->segToUpdate->synapse.size()
                                <MAX_NUM_SYN)
            {
            //for each synapses in newSynapses
            for (synToAdd = 
                curSegUpdate->newSynapsesToAdd.begin();
                synToAdd != curSegUpdate->
                newSynapsesToAdd.end(); ++synToAdd)
            {
                //add new synapse to list
                curSegUpdate->segToUpdate->
                    synapse.push_back(*synToAdd);
                //and permenance with initialPerm
                curSegUpdate->segToUpdate->
                permanence.push_back(initialPerm);
            }
            }//if less than MAX_NUM_SYN
        }
    }//end if segment already exists

//if segment doesn't exist, create a new segment & add synapses
    else if (curSegUpdate->segToUpdate == NULL)
    {
        size = curSegUpdate->newSynapsesToAdd.size();
        if (size != 0)
        {
        DendriteSegment myNewSeg; //create a new DS
        //set sequenceSegment flag if it is true
        if (curSegUpdate->sequenceSegment == true)
        {myNewSeg.sequenceSegment = true;} 

        std::copy(curSegUpdate->newSynapsesToAdd.begin(),
            curSegUpdate->newSynapsesToAdd.end(), 
            std::back_inserter(myNewSeg.synapse));

        myNewSeg.permanence.resize(size, initialPerm);      

        //then add it to the cells list of DS
        cellToAdapt->DSlist.push_back(myNewSeg);
        }//if size not 0
    }
}
return true;}

Мой следующий шаг - попробовать Application Verifier. Я попробовал Intel Inspector XE 2011, но он не обнаружил каких-либо проблем с памятью.

Обновление: с помощью gflags я обнаружил, что причина моих проблем в том, что у меня есть указатели на элементы в std::vector. myVector.push_back(newElem) использовался для добавления элементов в векторы, в результате чего указатели на элементы в векторе становились плохими. Я заменил векторы на std::list, у которого нет такой же проблемы (см. Здесь)

1 ответ

Решение

Попробуйте gflags в наборе инструментов отладки Microsoft для Windows (http://www.google.ca/search?sourceid=chrome&ie=UTF-8&q=debugging+tools+for+windows). Он позволяет вам работать с кучей отладки, которая улавливает проблемы по мере их возникновения, а не случайные проблемы, возникающие в течение длительного времени после сайта, где произошел сбой.

Другие вопросы по тегам