QT + STL + Crash



  • Hallo.
    ich habe hier eine etwas komplexe Software, die zufällig aber innerhalb von 10 Versuchen reproduzierbar abstürzt, wo ich aber einfach keinen Fehler finden kann.

    Ich muss zu Anfang anfügen, dass dieser Quellcode nicht von mir ist.

    Sowohl das Core-File als auch der Valgrind - Ausdruck zeigen auf die selben Stellen. (Deshalb werde ich jetzt mal das valgrind - Log posten, da es mehr Infos enthält als das corefile)

    ==16134== Invalid read of size 4
    ==16134== at 0x5C62FF7: std::_Rb_tree_increment(std::_Rb_tree_node_base*) (tree.cc:65)
    ==16134== by 0x805CD6B: std::_Rb_tree_iterator<std::pair<unsigned const, nCFG_FILE_PARSER::tParam> >::operator++(int) (stl_tree.h:191)
    ==16134== by 0x8054FEC: cCfgHmi::GetTaskParams() (ccfghmi.cpp:1188)
    ==16134== by 0x8055A23: cCfgHmi::TaskSelected(int, int) (ccfghmi.cpp:1092)
    ==16134== by 0x805F18F: cCfgHmi::qt_metacall(QMetaObject::Call, int, void**) (ccfghmi_moc.cc:101)
    ==16134== by 0x4D71B32: QMetaObject::metacall(QObject*, QMetaObject::Call, int, void**) (in /MIL/RSN/DEV/RTS_HEAD/lib/Linux-glibc-GNU4-debug/libQtCore.so.4.6.0)
    ==16134== by 0x4D7F2E6: QMetaObject::activate(QObject*, QMetaObject const*, int, void**) (in /MIL/RSN/DEV/RTS_HEAD/lib/Linux-glibc-GNU4-debug/libQtCore.so.4.6.0)
    ==16134== by 0x4874F18: QTableWidget::cellClicked(int, int) (in /MIL/RSN/DEV/RTS_HEAD/lib/Linux-glibc-GNU4-debug/libQtGui.so.4.6.0)
    ==16134== by 0x4876C4B: QTableWidgetPrivate::_q_emitItemClicked(QModelIndex const&) (in /MIL/RSN/DEV/RTS_HEAD/lib/Linux-glibc-GNU4-debug/libQtGui.so.4.6.0)
    ==16134== by 0x487B34D: QTableWidget::qt_metacall(QMetaObject::Call, int, void**) (in /MIL/RSN/DEV/RTS_HEAD/lib/Linux-glibc-GNU4-debug/libQtGui.so.4.6.0)
    ==16134== by 0x8062F0B: cChapterTasksTable::qt_metacall(QMetaObject::Call, int, void**) (cchaptertaskstable_moc.cc:72)
    ==16134== by 0x4D71B32: QMetaObject::metacall(QObject*, QMetaObject::Call, int, void**) (in /MIL/RSN/DEV/RTS_HEAD/lib/Linux-glibc-GNU4-debug/libQtCore.so.4.6.0)
    ==16134== Address 0x9467084 is 12 bytes inside a block of size 36 free'd
    ==16134== at 0x402679A: operator delete(void*) (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
    ==16134== by 0x805CE8C: __gnu_cxx::new_allocator<std::_Rb_tree_node<std::pair<unsigned const, nCFG_FILE_PARSER::tParam> > >::deallocate(std::_Rb_tree_node<std::pair<unsigned const, nCFG_FILE_PARSER::tParam> >, unsigned) (new_allocator.h:97)
    ==16134== by 0x805CEB1: std::_Rb_tree<unsigned, std::pair<unsigned const, nCFG_FILE_PARSER::tParam>, std::_Select1st<std::pair<unsigned const, nCFG_FILE_PARSER::tParam> >, std::less<unsigned>, std::allocator<std::pair<unsigned const, nCFG_FILE_PARSER::tParam> > >::_M_put_node(std::_Rb_tree_node<std::pair<unsigned c
    onst, nCFG_FILE_PARSER::tParam> >
    ) (stl_tree.h:371)
    ==16134== by 0x805D849: std::_Rb_tree<unsigned, std::pair<unsigned const, nCFG_FILE_PARSER::tParam>, std::_Select1st<std::pair<unsigned const, nCFG_FILE_PARSER::tParam> >, std::less<unsigned>, std::allocator<std::pair<unsigned const, nCFG_FILE_PARSER::tParam> > >::_M_destroy_node(std::_Rb_tree_node<std::pair<unsign
    ed const, nCFG_FILE_PARSER::tParam> >) (stl_tree.h:401)
    ==16134== by 0x805D8B1: std::_Rb_tree<unsigned, std::pair<unsigned const, nCFG_FILE_PARSER::tParam>, std::_Select1st<std::pair<unsigned const, nCFG_FILE_PARSER::tParam> >, std::less<unsigned>, std::allocator<std::pair<unsigned const, nCFG_FILE_PARSER::tParam> > >::_M_erase(std::_Rb_tree_node<std::pair<unsigned cons
    t, nCFG_FILE_PARSER::tParam> >
    ) (stl_tree.h:1325)
    ==16134== by 0x805DB9E: std::_Rb_tree<unsigned, std::pair<unsigned const, nCFG_FILE_PARSER::tParam>, std::_Select1st<std::pair<unsigned const, nCFG_FILE_PARSER::tParam> >, std::less<unsigned>, std::allocator<std::pair<unsigned const, nCFG_FILE_PARSER::tParam> > >::clear() (stl_tree.h:711)
    ==16134== by 0x805DC04: std::map<unsigned, nCFG_FILE_PARSER::tParam, std::less<unsigned>, std::allocator<std::pair<unsigned const, nCFG_FILE_PARSER::tParam> > >::clear() (stl_map.h:509)
    ==16134== by 0x5BF95FC: nCFG_FILE_PARSER::cTorpoCfgIF::getAllParamsFromDataStruct(nCFG_FILE_PARSER::cData, std::map<unsigned, nCFG_FILE_PARSER::tParam, std::less<unsigned>, std::allocator<std::pair<unsigned const, nCFG_FILE_PARSER::tParam> > >&) (cfg_logic.cc:643)
    ==16134== by 0x5BFB5BE: nCFG_FILE_PARSER::cTorpoCfgIF::getSubChapterParam(unsigned, unsigned, std::map<unsigned, nCFG_FILE_PARSER::tParam, std::less<unsigned>, std::allocator<std::pair<unsigned const, nCFG_FILE_PARSER::tParam> > >&, bool&) (cfg_logic.cc:703)
    ==16134== by 0x8053D4A: cCfgHmi::TaskParamChanged(QTableWidgetItem*) (ccfghmi.cpp:1581)
    ==16134== by 0x805F1D3: cCfgHmi::qt_metacall(QMetaObject::Call, int, void**) (ccfghmi_moc.cc:103)
    ==16134== by 0x4D71B32: QMetaObject::metacall(QObject*, QMetaObject::Call, int, void**) (in /MIL/RSN/DEV/RTS_HEAD/lib/Linux-glibc-GNU4-debug/libQtCore.so.4.6.0)

    Bevor ich jetzt hunderte Zeilen Quelcode poste, würde mich erstmal interessieren
    was folgende zeile bei valgrind bedeutet.

    Address 0x9467084 is 12 bytes inside a block of size 36 free

    Wenn jemand eine bestimmt Quellcodestelle für mehr Information sehen möchte, dann bitte einfach bescheid sagen, dann poste ich die.

    Für das erste, zeige ich de STelle, die als letztes von valgrind angeführt ist.

    (Line 1187) map<unsigned int, nCFG_FILE_PARSER::tParam>::iterator  Iterator;
    (Line 1188) for (Iterator = m_TaskParamMap.begin(); Iterator != m_TaskParamMap.end(); Iterator++)
            {
    //          cout << endl << Iterator->first << " : ";  // Key
    //          cout << Iterator->second.Name << endl;     // Name
    //          cout << Iterator->second.Value << endl;    // Value
    //          cout << Iterator->second.Unit << endl;     // Unit
    
              // Store the Map-Index in all Items
              m_ppTasksParamsItems[iItemIdx * 3]->setData(eROLE_ID, Iterator->first);
              m_ppTasksParamsItems[iItemIdx * 3 + 1]->setData(eROLE_ID, Iterator->first);
              m_ppTasksParamsItems[iItemIdx * 3 + 2]->setData(eROLE_ID, Iterator->first);
    
              TmpStr = Iterator->second.Name.c_str();
    
              m_ppTasksParamsItems[iItemIdx * 3]->setText(TmpStr);
    
              TmpStr = Iterator->second.Value.c_str();
    
              m_ppTasksParamsItems[iItemIdx * 3 + 1]->setText(TmpStr);
    
              TmpStr = Iterator->second.Unit.c_str();
    
              m_ppTasksParamsItems[iItemIdx * 3 + 2]->setText(TmpStr);
    
              // Set the alignments of the Items
              m_ppTasksParamsItems[iItemIdx * 3 + 1]->setTextAlignment(Qt::AlignCenter);
              m_ppTasksParamsItems[iItemIdx * 3 + 2]->setTextAlignment(Qt::AlignCenter);
    
              // Set the Font
              QFont  Font;
    
              Font.setBold(true);
    
              m_ppTasksParamsItems[iItemIdx * 3 + 1]->setFont(Font);
    
              // Set the Color
              m_ppTasksParamsItems[iItemIdx * 3]->setForeground(m_StandardColor);
              m_ppTasksParamsItems[iItemIdx * 3 + 1]->setForeground(m_SelectionColor);
              m_ppTasksParamsItems[iItemIdx * 3 + 2]->setForeground(m_StandardColor);
    
              // Set Flags
              m_ppTasksParamsItems[iItemIdx * 3]->setFlags(0);
              m_ppTasksParamsItems[iItemIdx * 3 + 2]->setFlags(0);
    
              // Set Items to the Table
              m_pTaskParams->setItem(iItemIdx, 0, m_ppTasksParamsItems[iItemIdx * 3]);
              m_pTaskParams->setItem(iItemIdx, 1, m_ppTasksParamsItems[iItemIdx * 3 + 1]);
              m_pTaskParams->setItem(iItemIdx, 2, m_ppTasksParamsItems[iItemIdx * 3 + 2]);
    
              iItemIdx++;
            }
    

    Wenn man vor dieser Schleife eine überprüfung der map macht und mittels iterator alle werte der maps ausgeben läßt sind sie grundsätzlich immer richtig.

    erst beim durchlaufen dieser Schleife, geht irgend etwas schief.

    mfg



  • Hmm, ich sehe gerade, dass hier bei STL Containern (hier std::map) über die "Array-Operatoren" gegangen wird. Diese Operatoren führen keinen Range-Check (keine Tests auf Arraygrenzen) durch.

    Eventuell ist es für die Fehlersuche besser die at() Methode zu benutzen, die wirft bei einem Fehlgriff wenigstens eine Exception. Bei dem [] knallt es nämlich nur, wenn der Zugriff über eine Pagegrenze (4k) hinausgeht oder in einen anderen benutzen Bereich gegriffen wird. Eventuell ist das auch schon die Lösung deines Problems, ein verdeckter Fehlgriff.

    PS: Kann es sein, dass du QT 4.6.0 benutzt? Soweit ich weiß, ist das kein finaler Release, der finale dürfte 4.6.3 sein.



  • Nach weiteren debuggen mittels cout, sieht es inzwischen so aus, als wenn Qt die events per eigenem Thread verwaltet, so dass der eine Thread in der Iterator-schleife drinne ist und der andere Thread die Variable löscht.

    ...wir machen hier jetzt mal die STL-Variable Thread-Sicher.



  • Akiko schrieb:

    Hmm, ich sehe gerade, dass hier bei STL Containern (hier std::map) über die "Array-Operatoren" gegangen wird. Diese Operatoren führen keinen Range-Check (keine Tests auf Arraygrenzen) durch.

    Eventuell ist es für die Fehlersuche besser die at() Methode zu benutzen, die wirft bei einem Fehlgriff wenigstens eine Exception. Bei dem [] knallt es nämlich nur, wenn der Zugriff über eine Pagegrenze (4k) hinausgeht oder in einen anderen benutzen Bereich gegriffen wird. Eventuell ist das auch schon die Lösung deines Problems, ein verdeckter Fehlgriff.

    PS: Kann es sein, dass du QT 4.6.0 benutzt? Soweit ich weiß, ist das kein finaler Release, der finale dürfte 4.6.3 sein.

    Diese mpp-Variablen sind leider etwas unglücklich gewählt und aufgebaut (man hätte es auch anders machen können als ein C-Feld auf nen Pointer auf nen Pointer.)

    Allerdings sind sie m.E. syntaktisch vollständig und richtig und bisher hat valgrind diese Konstruke nie angemeckert in der Software.

    aber, wie bekomme ich die Qt-Version heraus?



  • HeroHolger schrieb:

    Diese mpp-Variablen sind leider etwas unglücklich gewählt und aufgebaut (man hätte es auch anders machen können als ein C-Feld auf nen Pointer auf nen Pointer.)

    Allerdings sind sie m.E. syntaktisch vollständig und richtig und bisher hat valgrind diese Konstruke nie angemeckert in der Software.

    aber, wie bekomme ich die Qt-Version heraus?

    Hmm, solche Konstruktionen hatten wir in unseren Turbinenüberachungsprogrammen auch. Haben wir nach und nach durch Vektoren ersetzt. Pointer und C-Konstrukte machen in solchen Programmen immer wieder Ärger. Auf Valgrind würde ich hier auch nicht vertrauen, nach dem Ersatz durch die Vektoren sind nämlich of-by-one Fehlgriffe offensichtlich geworden. Valgrind neigt auch ein wenig zu Falsepositives. Ich würde den Quelltext auch noch mal an Cppcheck verfüttern (in Verbindung mit --enable=all) bekommt man da hin und wieder einen Aha-Effekt. 😉

    (in /MIL/RSN/DEV/RTS_HEAD/lib/Linux-glibc-GNU4-debug/libQtCore.so.4.6.0)

    Da steht im Prinzip die Version, aber ob das jetzt ein direkter Pfad in das System ist oder nur eine Ausgabe von einer alten ld-Information ist, weiß ich nicht. Das müsstet ihr aber am besten wissen, ihr seid die Entwickler. In der Regel ist die originale Lib immer die libXXX.so mit mehreren Softlinks darauf. Sind meist 2 oder 3 Softlinks, einer mit der Majorversion, einer mit Major- und Minorversion und wenn der Installter (bzw die Distribution) gut war, noch einen weiteren Link mit Major-, Minor- und Bugfixversion. Das sind diese Nummern hinter dem *.so.


Anmelden zum Antworten