PDA

View Full Version : Crash when showing windows



Selven
11th April 2012, 13:06
Hello,

I have a problem when my program starts. It randomly crash (it's not always)... I can run it 10 times correctly but i can also run it 2 times with crashs....

I don't understand what is the problem, it is a random bug, i tryied to put cout on the source, in order to know where it is crash, and it's not at the same "point" every times......

The main cpp is :

VerifFiles verif;
verif.exec();
CZoneDessin fen(0, 0);
fen.show();

If i do :

CZoneDessin fen(0, 0);
fen.show();
The program never crashs with that..

So i think the problem is during the first windows closing and the new is creating... Maybe my syntax isn't correct, or something i do wrong...

The first windows checks some files and if it is ok, the windows will be closed. If not, it will return exit(0), so the program will be closed.
When the first windows (verif) close, i create an instance of czonedessin and i show it (it is the main program).

I can show directly the czonedessin window, but i MUST check somes files before ! So it's why i create an "intermediate" window that do it..

How can i test that, have you an idea ? I don't understand and i think i can't put all the code here because czonedessin have 1222 lines, and a lot of includes .h

Thank's in advance for your time, and i'm very sorry for my bad english,

Berryblue031
11th April 2012, 14:25
I don't understand what is the problem, it is a random bug

I doubt it's random :) it sounds more like a race condition.

Your code for main.cpp looks wierd to me, where is you instance of QApplication? Is VerifFiles a modal dialogue?

You never check the result of VerifFiles before instantiating CZoneDessin, I assume you only want to show it if verification passed

By default QApplication will shut down if no windows are open, this means it will quit after VerifFiles is closed and before CZoneDessin is created to avoid this you need to make sure you set


QApplication::setQuitOnLastWindowClosed(false)

Selven
11th April 2012, 15:44
Hi,
I quote only the minimal part of the main.cpp.
The code is (without include) :

int main(int argc, char *argv[])
{
QApplication app(argc, argv);
VerifFiles verif;
verif.exec();
CZoneDessin fen(0, 0);
fen.show();
return app.exec();
}

The crash is really randomly, it don't crash every times... So it's why it's very strange...

VerifFyles is herited from QDialog, czonedessin is herited from QLabel..
I have a button on my verifFyles windows, connected to a slot. When i push it, i verify somes files and if it's good, i close() the window. So, the main.cpp continue and launch the czonedessin window. If an error occured, when i push the button i detect it and i exit(0). So, it quit the application, not just the window.

When a crash occured, it's when creating the czonedessin instance...

Thank's for your help,

d_stranz
11th April 2012, 16:38
Since you haven't told us anything about the classes in your application or what they do, should we just guess at answers until we get lucky?

- First: If VerifFiles is a GUI class or something else that uses events, nothing will happen until the call to app.exec(). The event loop is not running until that point. So, the call to verif.exec() is only posting events (just like fen.show()), but nothing happens until after the call to app.exec().

- Second: If CZoneDessin somehow depends on what happens in VerifFiles::exec() (or depends on it finishing before being constructed), then this won't happen in your code. Both the VerifFiles and CZoneDessin instances will be constructed, the call to verif.exec() will result in events being posted to the event queue, as will the events involved in fen.show(). Who knows what order these will get processed in?

From other posts you have made, you seem to have a very basic misunderstanding of how Qt and the Qt event loop work. As I said above, nothing happens until app.exec(). It might look like it is, but in reality all that is happening is that your code is putting things in the event queue to be performed after the event loop gets started.

For this reason, if you look at almost any of the Qt example apps, the only things that typically occur are:

- Create a QApplication instance on the stack
- Create an instance of the app's main window widget class on the stack
- Show the main window (which simply queues up a show event and associated processing)
- app.exec()

If you try to do anything else in main() that requires a GUI, it probably won't work, and will lead to weird behavior like you are seeing.

So, you need to restructure your app somehow so that events happen in the order that you expect them to. Like a previous poster said, if the VerifFiles window closes before the CZoneDessin window is shown, then the application could shut down too early. If the CZoneDessin widget is partially destroyed at that point, then that could be the cause of your random crashes.

Selven
11th April 2012, 16:50
Hello,

Thank's a lot for your response,

I think i have another way to do what i want. So in the main.cpp i will just have :

int main(int argc, char *argv[])
{
QApplication app(argc, argv);
CZoneDessin fen;
fen.show();
return app.exec();
}

And in the constructor of czonedessin, on the top, as the first instruction i put my instance of VerifFiles. So, if the result is good, i continue the constructor, if not, i do exit(0) and so, the program will be closed.

Do you think it will works better ?

Edit : i try that and i have somes crash..... same issue....

d_stranz
11th April 2012, 17:49
And in the constructor of czonedessin, on the top, as the first instruction i put my instance of VerifFiles. So, if the result is good, i continue the constructor, if not, i do exit(0) and so, the program will be closed.

Do you think it will works better ?


No, it will not work any better. In the constructor for CZoneDessin, the event loop is not running. Like I said, nothing happens until the event loop runs. So, you build your CZoneDessing instance, the constructor exits, then you are back in main() where you then show() the window. Even then, still nothing happens until the call to app.exec().

So, think about what your new code does:

- It creates a CZoneDessin instance.
- Inside the CZoneDessing constructor, it creates a VerifFiles instance on the stack.
- It calls VerifFiles::exec() with that instance. Remember, all this does is to post events to the queue, but since the event loop isn't running yet, nothing happens on screen yet.
- Because there is no event loop, VerifFiles::exec() returns immediately and the CZoneDessin constructor eventually exits
- When that happens, the VerifFiles instance is destroyed. The events are still on the event queue, but now they refer to an object that is gone.
- Back in main(), you call fen.show() and app.exe()
- The event loop starts, and BOOM!, your program blows up.

So, what you probably want to do is this:

- Implement a handler for the CZoneDessin::showEvent().
- In the CZoneDessin constructor, build your GUI as if everything was normal.
- Move the VerifFiles code to the showEvent()
- In showEvent, create the VerifFiles instance, call exec(), and if it fails, show a fatal error message to the user, then call close(). This will cause the application to exit.
- If VerifFiles succeeds, do nothing and the CZoneDessin widget will be displayed.

Something like this:



// CZoneDessin.h:

class CZoneDessin : public QWidget
{
Q_OBJECT;

//...

protected:
void showEvent( QShowEvent * );
};

// CZoneDessin.cpp:
void CZoneDessin::showEvent( QShowEvent * )
{
VerifFiles verif;
if ( QDialog::Rejected == verif.exec() )
close();
}

Selven
11th April 2012, 18:42
Okay, now i understand how the event loop works, thanks a lot.

On my .h i added the void showEvent, and in the .cpp, I put the instance and exec in this method, like you quoted.

I have random crashes again... Maybe the problem is elsewhere.... A bad pointer or a problem with memory (I don't use malloc). But I don't understand that : if I remove the veriffiles instance and if I launch the czonedessin directly, I don't have any crashes..

Maybe if you have time and if you are interested with that, i can give you the project, but i don't think you want to loose time with that.... ^^
But i don't want abuse and ask for too much,

Thanks for your help, all your responses are very helpful for me !

d_stranz
11th April 2012, 20:45
OK, it sounds like the problem is inside of the VerifFiles dialog class. Try an experiment: instead of using VerifFiles, use one of the existing Qt dialog classes, like QColorDialog.



// CZoneDessin.cpp:
void CZoneDessin::showEvent( QShowEvent * )
{
QColorDialog dlg( this );
if ( QDialog::Rejected == dlg.exec() )
{
QMessageBox::information( this, "Rejected", "QColorDialog rejected" );
close();
}
else
QMessageBox::information( this, "Accepted", "QColorDialog accepted" );
}


The QColorDialog will have OK and Cancel buttons; clicking Cancel with display the "Rejected" message box, clicking OK will display the "Accepted" message box.

If this works without crashing, then the problem is almost certainly inside your VerifFiles class (unless you have a memory corruption before that somewhere).

Selven
11th April 2012, 21:27
Hi,

With your example, the program crashes again but LESS !! In 50 runs, only 3 crashes !
Something is strange : when I click Rejected, the windows closes but the application is still running. However, the attribute app.setQuitOnLastWindowClosed is by default at true.. I don't change it.

My VerifFiles is closed manually : i have a button connected to a slot, when i push it, the slot (lancerApp()) update a bool and do a close() for close the window. How can i change the value of the exec for test it ? Because it's not an Accepted/Rejected dialog buttons.

void VerifFiles::lancerApp()
{
confOK = true;
close();
}

So, there is a bug in VerifFiles, and also in CZoneDessin ?

Thanks a lot for all your help,

d_stranz
11th April 2012, 21:44
The usual behavior in a custom QDialog class is to emit one of the two signals "accepted()" or "rejected()" when the dialog is done. If you do not have OK or Cancel buttons, then you should emit those signals when VerifFiles determines if the result is successful or failed. If you use QDialog::exec() to post the dialog, you should not call "close()" from inside the dialog to close it, let the normal accept/reject mechanism do it for you.



// VerifFiles.cpp
void VerifFiles::lancerApp()
{
emit accepted();
}

// CZoneDessin.cpp
void CZoneDessin::showEvent( QShowEvent * )
{
VerifFiles verif;
if ( QDialog::Rejected == verif.exec() )
close();
}


If you have to have a different code than QDialog::Accepted or QDialog::Rejected, you can emit the "finished( int )" signal instead and put your own integer code in there:



// VerifFiles.cpp
void VerifFiles::lancerApp()
{
emit finished( 42 );
}

// CZoneDessin.cpp
void CZoneDessin::showEvent( QShowEvent * )
{
VerifFiles verif;
if ( 42 == verif.exec() )
close();
}

Selven
11th April 2012, 22:08
//VerifFiles.cpp
void VerifFiles::lancerApp()
{
emit accepted();
}

//CzoneDessin.cpp
void CZoneDessin::showEvent(QShowEvent *)
{
// Affichage de la fenêtre de vérification des fichiers / Auto-configuration
VerifFiles testFichiers;
if(QDialog::Accepted != testFichiers.exec())
close();
}

The emit accepted() seems not close the window when I click the button. I tryied to put a cout on the lancerApp() slots, and the message is successfully displayed.. But the window is still visible and hold the program (CZoneDessin will not be visible while this window is visible)

And the close() in CZoneDessin::showEvent don't close the application, but only the window CZoneDessin (which is not visible at this step). Can i use exit(0) instead close() ?

About crashes, so it's VerifFiles which doing crashes the program ? Without this class, I have always crashes but much less !
VerifFiles analyses 200 files, this class have 400 lines and i can't put them here, it will take too much place..

Thanks for the quality of all your responses

PS : is it not too hard to understand me ? My english is so bad !

d_stranz
11th April 2012, 22:50
Sorry, I was a little bit wrong. Do this instead:



//VerifFiles.cpp
void VerifFiles::lancerApp()
{
accept(); // Note: "accept()", not "accepted()"
}

This should cause the dialog to close. Likewise, use "reject()" instead of "emit rejected()" if the test fails.

Using exit( 0 ) is not a good idea, because it causes an immediate end to the application without allowing Qt to clean up. If you have to, call QCoreApplication::instance()->quit() instead.

Selven
11th April 2012, 23:13
With the accept() it works perfectly when I click my button, the window closes ! Thanks !


//CZoneDessin.cpp
VerifFiles testFichiers;
if(QDialog::Accepted != testFichiers.exec())
QCoreApplication::instance()->quit();

But if the exec don't return Accepted, the application don't quit and the czonedessin window become visible :|
I also tryied qApp->quit() but nothing happens especially



EDIT :
I want to restart my program when someone click on a button of the mainWindow.
So, i find a piece of code :

if(returnValue != 0)
QProcess::startDetached(argv[0], app.arguments());
return returnValue;
So if I do an exit(1) or another value different to 0, the program restarts successfully. What do you think about this code ?

Thanks for all,

Selven
12th April 2012, 13:44
Hi,

About my several crashes, I try another thing on the main.cpp:

// Main.cpp
VerifFiles testFichiers;
QTimer::singleShot(0, &testFichiers, SLOT(exec()));

CZoneDessin fen;
app.connect(&testFichiers, SIGNAL(accepted()), &fen, SLOT(showFullScreen()));

So in 50 runs, i had only 1 crashe... It's negligeable i think ! Maybe this piece of code is a way to find the problem. If you have an idea to modify it and eradicate finally this bug... !


About the quit(), have you an idea ? Because the application don't closes whit that. But exit(0) on a method of CZoneDessin will quit the application correctly... It is very strange.


Thanks a lot for all your help !

d_stranz
12th April 2012, 19:35
So in 50 runs, i had only 1 crashe... It's negligeable i think !

It is never negligible when a program crashes and you do not understand the reason. What would you think if every so often your bank's computer program crashed and erased all the money in your bank account, and your bank tells you, "It only happens about once every 50 times, so we haven't bothered to fix it. So sorry."?

Instead of trying random things to get your program working, go in with the debugger and find out why it crashes. If you have to run it 50 times, so what? At least you find the crash.

The code you show above is probably a good solution; using the single shot time ensures that the dialog will not be shown until the event loop is running, and connecting it to the show slot of the main window is probably also good. Now you need to find out what is wrong with your VerifFiles class (or your CZoneDessin class) that causes random crashes. I am guessing that you have a memory corruption or timing problem somewhere that only gets exposed when the application load in your PC is at a certain level.

Selven
12th April 2012, 21:54
I already try the program with debugger but it never crashe... I can't reproduce the crash with the debugger so i can't use it to know where is the problem.
I tryied to put some breakpoints in the constructor of CZoneDessin, and the program never crash when I go point to point.

So, instead of the debugger (because it never crash with it), I put a lot of "COUT" in the constructor, so I can see where it crashes. But it is not at the same line every times... It's a random line. Sometimes, it's when a QPushButton is created, or a QLabel, or another things :(

A memory corruption? Caused by what ? Bad initialization of pointers ?

d_stranz
13th April 2012, 00:42
Post the source code for your CZoneDessin constructor, we can look to see if there is some obvious mistake.

Selven
13th April 2012, 10:56
I can recommend you to take a dolliprane before read this post... :mad:

Maybe it's important but on my pc i have only 1 crash with 50 runs, but on VMware, with the same distribution (Fedora 16 x64), i have 40 crashs for 50 runs. I tryied to run it with the terminal and when it crashes, it returns "Erreur de segmentation ( core dumped )", so in english i guess "Segmentation fault ( core dumped )". Maybe it can help us...

I remove all the COUT from the CZoneDessin, because it take so much lines,
Note : I don't past the code here before, because it's very hard to understand what it does.. There are a lot of variables types that are personnal classes, so there is much source code (good film !, don't know if you saw it) to past, i will try to past all what you need, i hope i don't forget anything (hum... not sure that i said is understanding, sorry for my english...)


//CZoneDessin.cpp
CZoneDessin::CZoneDessin()
: m_timer_p(new QTimer(this))
{
config = Config::getConfig();
QIcon tairon(":/images/tairona1.jpeg");
this->setWindowIcon (tairon);
fini = false;
this->initGraph();

QSize taille(100,100);

boutonSelecteur = new QPushButton("", this);
boutonSelecteur->setGeometry(ENTETE_POSX+10, ENTETE_POSY+10, 100, 100);
boutonSelecteur->setIcon(QIcon(":/images/Tairona25.jpeg"));
boutonSelecteur->setIconSize(taille);
boutonSelecteur->setFlat(true);

slideTemps = new QSlider(Qt::Horizontal,this);
slideTemps->setRange(+MIN_SLIDE, +MAX_SLIDE);
slideTemps->setGeometry(ENTETE_POSX+200,ENTETE_POSY+90,160,30) ;
slideTemps->setSingleStep(1);
slideTemps->setPageStep(1);
slideTemps->setTickInterval(200);
slideTemps->setTickPosition(QSlider::TicksRight);
slideTemps->setSliderDown (true);
slideTemps->setSliderPosition (MAX_SLIDE);

boutonPlayPause = new QPushButton("", this);
boutonPlayPause->setGeometry(ENTETE_POSX + DATE_POSX + 330, ENTETE_POSY+25, 111, 50);
boutonPlayPause->setIcon(QIcon(":/images/start.png"));
boutonPlayPause->setIconSize(taille);
boutonPlayPause->setFlat(true);

boutonPapa = new QPushButton("", this);
boutonPapa->setGeometry(boutonPlayPause->x()+boutonPlayPause->width()+13, ENTETE_POSY+25, 109, 50);
boutonPapa->setIcon(QIcon(":/images/papa.png"));
boutonPapa->setIconSize(taille);
boutonPapa->setFlat(true);

boutonTailleEcran = new QPushButton("", this);
taille.setWidth(50);
boutonTailleEcran->setGeometry(boutonPapa->x()+boutonPapa->width()+13, ENTETE_POSY+25, 50, 50);
boutonTailleEcran->setIcon(QIcon(":/images/retrecir.png"));
boutonTailleEcran->setIconSize(taille);
boutonTailleEcran->setFlat(true);

boutonConfig = new QPushButton("", this);
boutonConfig->setGeometry(boutonTailleEcran->x()+boutonTailleEcran->width()+13, ENTETE_POSY+25, 50, 50);
boutonConfig->setIcon(QIcon(":/images/configIco.png"));
boutonConfig->setIconSize(taille);
boutonConfig->setFlat(true);

boutonVisu = new QPushButton("", this);
boutonVisu->setGeometry(boutonConfig->x()+boutonConfig->width()+13, ENTETE_POSY+25, 50, 50);
boutonVisu->setIcon(QIcon(":/images/visu.png"));
boutonVisu->setIconSize(taille);
boutonVisu->setFlat(true);

langueAng = new QPushButton("", this);
langueAng->setGeometry(ENTETE_POSX+20, ENTETE_POSY+110, 30, 20);
langueAng->setIcon(QIcon(":/images/EN.png"));
langueAng->setIconSize(taille);
langueAng->setFlat(true);

langueFr = new QPushButton("", this);
langueFr->setGeometry(ENTETE_POSX+60, ENTETE_POSY+110, 30, 20);
langueFr->setIcon(QIcon(":/images/FR.png"));
langueFr->setIconSize(taille);
langueFr->setFlat(true);

flecheBasHaut = new QImage(40, 40, QImage::Format_ARGB32);
flecheDroitGauche = new QImage(100, 40, QImage::Format_ARGB32);
flecheHautBas = new QImage(40, 40, QImage::Format_ARGB32);

PtrCartSV = new Cartouche(this,SUIVISATELLITE_POSX,SUIVISATELLITE_ POSY,SUIVISATELLITE_LARGEUR,SUIVISATELLITE_HAUTEUR );
PtrCartDrops = new Cartouche(this,DROP_POSX,DROP_POSY,DROP_LARGEUR,DR OP_HAUTEUR);
PtrCartTeleport = new Cartouche (this,TELEPORT_POSX, TELEPORT_POSY, TELEPORT_LARGEUR, TELEPORT_HAUTEUR);

setPalette(QPalette(QColor(0, 0,0)));
setAutoFillBackground(true);
ptrLesSatT0=new QImage(LargeurAnime, hauteurAnime+HImgTeleport, QImage::Format_RGB32);//fond NON transparant;
ptrAff2=new QImage(LargeurAnime, hauteurAnime+HImgTeleport, QImage::Format_ARGB32);//fond transparant;
ptrDrop0=new QImage(LargeurAnime, hauteurAnime+HImgTeleport, QImage::Format_ARGB32);//fond transparant;
ptrDrop1=new QImage(LargeurAnime,hauteurAnime+HImgTeleport, QImage::Format_ARGB32);//fond transparant;
DateProchainRafraichissementTeleports=0;

initFond2D();

connect( boutonSelecteur, SIGNAL( clicked() ), SLOT(boutonSelecteurPresse()) );
connect( boutonTailleEcran, SIGNAL( clicked() ), SLOT(BoutonTailleEcranPresse() ) );
connect( boutonPlayPause, SIGNAL( clicked() ), SLOT(BoutonPlayPausePresse() ) );
connect( boutonPapa, SIGNAL( clicked() ), SLOT(BoutonPaPaPresse() ) );
connect( m_timer_p, SIGNAL( timeout() ), SLOT( animer() ) );
connect( &lesObs, SIGNAL( FinTraiteObs() ),this, SLOT(DessineObs() ) );
connect( slideTemps, SIGNAL(valueChanged(int)),this, SLOT(ValSliderTemps(int) ) );
connect( boutonConfig, SIGNAL( clicked() ), SLOT(BoutonConfigPresse() ) );
connect( boutonVisu, SIGNAL( clicked() ), SLOT(BoutonVisuePresse() ) );
}

For CZoneDessin::initGraph() :
http://paste2.org/p/1977687

And for CZoneDessin::initFond2D()

//CZoneDessin.cpp
void CZoneDessin::initFond2D()
{
QPoint p;
int X,Y;
QPainter painter(ptrLesSatT0);
painter.setPen(QColor(255,255,255,255));
for(int i=0;i<gconstellation.nbSatellites;i++)
{
gconstellation.satellite[i]->latX=((gconstellation.satellite[i]->latitudeT0+900)%3600)*LargeurAnime/3600;//3600=angle en dixieme de degré
X=gconstellation.satellite[i]->latX ;
Y=HImgTeleport+gconstellation.satellite[i]->longY;
p.setX( X );
p.setY( Y );
painter.drawImage ( p,imgSat);
painter.drawText ( X , Y-5,gconstellation.satellite[i]->numero);
if(X>=(LargeurAnime-LImgSat)){
X=X-LargeurAnime;
p.setX( X );
painter.drawImage ( p,imgSat);
painter.drawText ( X , Y-5,gconstellation.satellite[i]->numero);
}
}
painter.end();

}

It's hard to understand what CZoneDessin::initGraph() does because there are a lot of variables that are in others files,

about gconstellation and PtrSat,

//CZoneDessin.h
GConstellation gconstellation;
GSatellite *ptrSat;
You have these class here :
http://paste2.org/p/1977685 (very long because it depends of another classes)
And each constructor/methods :
http://paste2.org/p/1977686

about LesLiensEtDebits, it's a TraitementGraph type (constructor, method init(...) and method Traiter(...)) :
http://paste2.org/p/1977678 (it is a thread, i can't put it here, very long)

about lesObs, it's a TraitementObs type (constructor, method init(...) and method Traiter(...)) :
http://paste2.org/p/1977680 (it is a thread again)

----------------------

Maybe I forget something.. You understand now why i can't debug it alone, i don't know where can be the problem,

Thanks in advance for your time and all your help


### EDIT ###
I found a tutorial for debugging this kind of crash (core dumped). So, when my program crashes, it created a core file that can be read with GDB for example. So, with GDB, i open this file and i find a problem in my program.
It is in the thread of TraitementOsb (you have the link before the edit part).

TraitementObs::run()
{
...
ptrIndexTeleport=&(ptrConstel->satellite[i]->versAntenneSol[direction-SV_FL1].indexTeleport);
...
}

satellite is a vector of pointers, but versAntenneSol isn't a pointer....

So I put 2 cout :

//Traitement.cpp
cout << "ptrIndexTeleport n°" << i << " : " << *ptrIndexTeleport << endl;
cout << "ptrIndexAntenneTeleport : " << *ptrIndexAntenneTeleport << endl;
( i is the index of the for() )
And when the program runs perfectly, the first value is 3 for 1st, and 0 for second cout..

But when it crashes, i have random value, example :

ptrIndexTeleport n°1 : 1817910664
ptrIndexAntenneTeleport : 50
It's TOTALLY WRONG because IndexAntenneTeleport is between 0 and 4... WTF
The first value seems to be totally random...

amleto
16th April 2012, 14:40
It's TOTALLY WRONG because IndexAntenneTeleport is between 0 and 4... WTF
The first value seems to be totally random...

Then you have your symptom - now back trace to find the cause - something is setting the wrong value.


All these [] - are they from raw arrays or from std::vector? taking the address of an element of a std::vector could lead to trouble if the vector is later re-allocated!


looking at your code, sorry to rub salt in the wound, but you have brought on these issues yourself with massive functions, raw pointers, raw arrays. It was inevitable that a nasty bug would crop up.

d_stranz
17th April 2012, 00:00
You also don't seem to know anything about layouts or Qt Designer. You are creating all of your push buttons and other GUI elements and positioning them with absolute geometry in the window. We don't even know what kind of QWidget CZoneDessin is; if it is based on QMainQWindow or QDialog, then the code you have posted is almost completely wrong for building a QMainWindow, and might be acceptable (but really isn't) for a QDialog.

Have you looked at any of the Qt tutorials or examples? Can you see the obvious differences between them and your own app?

You seem to have jumped into water that is too deep for you; I would recommend that you swim to shore, get out, and study some of the examples before trying again. :)