Seite 1 von 1
[gelöst] Absturz bei Programmende
Verfasst: 6. Mai 2009 23:01
von qtNiko
hi,
wenn ich mein Qt-Programm (4.3.2) auf SuSe Linux beende, erhalte ich eine Fehlermeldung auf der Konsole. Das Programmfenster ist dann zwar weg, aber das Programm selbst offensichtlich nicht, da es mit "top" auf der Konsole noch zu sehen ist.
Das Programm lässt sich danach problemlos wieder starten, und es läuft auch fehlerfrei.
Mein Main-Programm enthält auch lastWindowClosed():
Code: Alles auswählen
QApplication app(argc, argv);
SimuDesign simWindow;
simWindow.show();
app.connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit()));
return app.exec();
Beim Beenden des Programms wird noch closeEvent(QCloseEvent *event) aufgerufen, weil ein paar Aufräumarbeiten nötig sind. Innerhalb closeEvent(QCloseEvent *event) rufe ich dann, wenn alles aufgeräumt ist, event->accept() auf. Damit sollte das Programm beendet werden - tut es aber nicht!
Der Anfang der Fehlermeldung auf Konsole sieht so aus:
Code: Alles auswählen
*** glibc detected *** /home/niksch/workspace/...: munmap_chunk(): invalid pointer: 0xbfdb188c ***
======= Backtrace: =========
/lib/libc.so.6[0xb707e4b6]
/usr/lib/libstdc++.so.6(_ZdlPv+0x21)[0xb7235a61]
/home/niksch/workspace/...[0x80a6ad3]
/usr/local/Trolltech/Qt-4.3.2/lib/libQtCore.so.4(_ZN7QObject5eventEP6QEvent+0x3a4)[0xb74736a4]
... usw.
Bei Bedarf kann ich auch die ganze Fehlermeldung posten.
Hat jemand eine Idee, woher der "invalid pointer" kommen könnte?
Ich stehe momentan völlig auf dem Schlauch.
Verfasst: 7. Mai 2009 07:49
von AuE
zeig mal dein on_close Methode....
Verfasst: 7. Mai 2009 09:37
von franzf
Das kommt wenn z.B. ein Objekt mehrfach zerstört wird.
Ich hatte das mal mit einem static-Widget in ner Methode (Singleton). Das lag in nem Layout. Beim Zerstören des Widget, in dem das Layout lag, wurde einfach das static-Widget mit zerstört. Bei Programmende wollte das static-Widget auch automatisch zerstört werden (kein Pointer), war aber schon weg -> munmap.
In Antico z.B. war das noch schlimmer:
Code: Alles auswählen
class Super {
private:
AndereKlasse m_member;
public:
~Super() {
delete &m_member;
}
};
Das endet genau so böse...
// nachtrag:
Hier zum ausprobieren, vllt. hast du ja auch sowas.
Code: Alles auswählen
#include <QtGui>
static QLabel* label()
{
static QLabel l("LAAABBBEEELL");
return &l;
}
int main( int argc, char** argv )
{
QApplication app( argc, argv );
QWidget w;
QHBoxLayout l;
l.addWidget(label());
w.setLayout(&l);
w.show();
return app.exec();
}
Verfasst: 7. Mai 2009 22:37
von qtNiko
AuE wollte mein close-Event sehen:
Code: Alles auswählen
void SimuDesign::closeEvent(QCloseEvent *event) {
// wird aufgerufen beim Schließen des Hauptfensters
// Klick auf Beenden --> Slot close() --> closeEvent()
bool fertig = true;
ULONG * ptr;
blinking_off(); // Timer stoppen
if (aktSimStatus == Run)
pushButtReset->click(); // Simulation stoppen
if (wkspcChanged) {
int rv = QMessageBox::warning(this, tr("PC-Simulation"),
tr("Workspace-Einstellungen wurden verändert\n"
"Wollen Sie die Einstellungen speichern?"),
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
if (rv == QMessageBox::Yes)
saveWorkspaceAs();
if (rv == QMessageBox::Cancel) fertig = false; // Fenster wird nicht geschlossen
}
if(fertig) {
if (simArt > 1) {
remove_feip_process(); // ein zweiter Prozess
remove(MAP_STRING); // eine Datei
}
// Speicher freigeben:
ptr = (ULONG *)allocate_mem(JA, 1); // 1 ist beliebig
free(ptr);
printf("Event-accept: Programm beenden");
event->accept(); // Programm beenden
}
else {
printf("Event-ignore: weitermachen");
event->ignore(); // Programm und Fenster weiterlaufen lassen
}
// close() schließt das Hauptfenster und damit automatisch das Programm
// mit QApplication.quitOnLastWindowClosed()=false würde das Programm
// nicht beendet, sondern nur das Hauptfenster unsichtbar (wirklich?)
} //closeEvent()
Hilft das weiter?
Verfasst: 7. Mai 2009 23:15
von franzf
Code: Alles auswählen
// Speicher freigeben:
ptr = (ULONG *)allocate_mem(JA, 1); // 1 ist beliebig
free(ptr);
Aber das machst du nicht auch noch in ~SimuDesign, oder?
Und die beiden remove-Aufrufe machen was?
Das closeEvent() wird beim Schließen abgearbeitet. In deinem Fall kommt danach noch der Destruktor. Also keine Sachen im closeEvent machen, die du auch noch im Destruktor erledigen willst!
Verfasst: 8. Mai 2009 07:42
von AuE
Auf den ersten Blick erkenne ich auch nur das was der Franz scho gesagt hat.
Die onclose läuft noch ganz gut durch?
Schau mal mit dem Debugger wann er abkackt!
Verfasst: 8. Mai 2009 10:37
von qtNiko
hi,
also, der Destructor, ~SimuDesign(), ist bei mir völlig leer.
Der erste remove_xxx-Aufruf löscht einen Prozess, der sonst weiterlaufen würde.
Der zweite remove_xxx-Aufruf löscht eine Datei, die im Zusammenhang mit dem Prozess steht, d.h. wenn diese Datei bestehen bliebe, dann würde das Programm bei einem erneuten Aufruf annehmen, dass der Prozess noch läuft. Das ist vielleicht nicht gerade besonders elegant, funktioniert aber.
Was hat es mit dem QApplication.quitOnLastWindowClosed() auf sich?
Wenn ich bereits app.connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit())) im main-Progr. stehen habe, brauche ich dann noch ein setQuitOnLastWindowClosed(true)?
Verfasst: 8. Mai 2009 11:00
von AuE
Wo kackt es dir ab???
zu den anderen Aussagen.....
Was macht denn move_xxx?? Löscht das nur die ptr oder fährt es auch den prozess herunter?
Zum thema läuft der process: (Win only)
Code: Alles auswählen
bool process_manager::IsProcessRunning()
{
bool bRet = false;
HANDLE hProcessSnap;
PROCESSENTRY32 pe32;
// Take a snapshot of all processes in the system.
hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
if( hProcessSnap == INVALID_HANDLE_VALUE )
{
return false;
}
// Set the size of the structure before using it.
pe32.dwSize = sizeof( PROCESSENTRY32 );
// Retrieve information about the first process,
// and exit if unsuccessful
if( !Process32First( hProcessSnap, &pe32 ) )
{
CloseHandle( hProcessSnap ); // Must clean up the snapshot object!
return false;
}
// Now walk the snapshot of processes, and
// display information about each process in turn
do
{
std::string thisProc(pe32.szExeFile/*, sizeof(pe32.szExeFile)/sizeof(TCHAR)*/);
//string_support::str_trim_right(thisProc);
if ( thisProc.compare(_process_name) == 0 )
{
//_process_name = executable;
_processID = pe32.th32ProcessID;
if (!_isActive) // ist der Prozess noch nicht aktiv so wird ein neues Handle vergeben
_hHandleProcess = hProcessSnap; // we dont know the real HANDLE... but we´ll correct later-> so HANDLE != INVALID
_isInit = true;
_isActive = true;
bRet = true;
break;
}
} while( Process32Next( hProcessSnap, &pe32 ) );
CloseHandle( hProcessSnap );
return bRet;
}
oder noch besser übern mutex.... (denke mal auchso nur win)
Code: Alles auswählen
_
hnd_proc_mutex = ::CreateMutex( NULL, NULL, unique_name.c_str() );
/*Return Values
If the function succeeds, the return value is a handle to the newly created mutex object.
If the function fails, the return value is NULL. To get extended error information, call GetLastError.
*/
_is_exclusive = GetLastError() != ERROR_ALREADY_EXISTS;
Verfasst: 8. Mai 2009 23:34
von qtNiko
hi,
habe schon verschiedenes probiert, aber das Programm lebt weiter.
Wo kackt es dir ab???
Mit dem Debugger kann ich das komplette closeEvent() fehlerlos durchsteppen. Wenn ich danach noch weitersteppe, kommen diverse Qt-Module, die ich gar nicht kenne. Ich habe aber einfach mal weitergesteppt und nach etwas Auffälligem Ausschau gehalten. Dabei fiel mir in qwidget.cpp ein "q->setAttribute(Qt::WA_DeleteOnClose, false)" auf. Die Doku sagt dazu, dass damit WA_DeleteOnClose = false gesetzt wird. Das erklärt schon mal, warum das Programm weiterläuft. Mir ist aber immer noch nicht klar, warum.
Als ich alles nach closeEvent() mit dem Debugger im Einzelschritt durchsteppte, kam ich problemlos bis zum Ende, und es kam komischerweise keine Fehlermeldung auf der Konsole, wie in meinem ursprünglichen posting gemeldet.
zu:
Was macht denn move_xxx?? Löscht das nur die ptr oder fährt es auch den prozess herunter?
remove_xxx löscht den Prozess - definitiv. Außerdem habe ich das Problem auch, wenn die beiden remove_xx-statements, die ja in einem if-Block stehen, nicht durchlaufen werden.
Verfasst: 9. Mai 2009 08:16
von franzf
qtNiko hat geschrieben:Dabei fiel mir in qwidget.cpp ein "q->setAttribute(Qt::WA_DeleteOnClose, false)" auf. Die Doku sagt dazu, dass damit WA_DeleteOnClose = false gesetzt wird. Das erklärt schon mal, warum das Programm weiterläuft. Mir ist aber immer noch nicht klar, warum.
Bei dir ist das doch egal. Du hast das eine Fenster, um das es dir geht. Wenn du das schließt, ist doch das Programm sowieso zu Ende, und es wird zerstört.
Kannst du dein Projekt nicht einfach mal als Zip anhängen, wenn es zu groß ist so weit reduzieren, dass der Fehler reproduzierbar bleibt?
So bleibt nämlich nur rätseln, was da im Hintergrund eigentlich passiert. Denn irgendwo hast du ein Objekt, welches schon zerstört wurde und nochmal zerstört werden will...
Grüße
Franz
Verfasst: 9. Mai 2009 10:04
von AlexDu
Hallo,
ich hatte mich auch mal mit so einem rätselhaftem Absturz beim Beenden rumgeschlagen. Nach einem "Clean all" und "Build" war das Problem weg.
HTH,
Alex
Verfasst: 9. Mai 2009 17:36
von SkyperHH
Wenn Du unter Linux unterwegs bist, könnte Dir
valgrind -->
http://www.valgrind.org zeigen, wo es im Speicher hakt. Man überwacht mit
--leak-check=summary|full den Speicher und sieht, an welcher stelle man "ein zweites mal" was löschen möchte, oder wo man zugreift, obwohl das betreffende schon im Nirvana entsorgt ist. Mehr zu den Paramtern
--help | manpage, no Gui

.
Zu Windows und valgrind kann ich nichts sagen, unter Linux habe ich damit meine Probleme sehr gut im Griff bekommen.

Verfasst: 11. Mai 2009 19:57
von qtNiko
halli, hallo,
ich hab' den Fehler. Es war, wie so oft, einfach ein Programmfehler.

Eine Warteschleife wurde nicht beendet, und so lief das Programm munter weiter, obwohl drumherum alles beendet war.
Danke für die vielen Tipps. Sie haben mich letztlich auf die richtige Spur gebracht.