PDA

View Full Version : How to crash gracefully



rbp
5th May 2009, 04:06
hi,

when a program like Firefox or Sketchup crashes we get a nice Dialog saying what has happened.
How would I implement something like that for my own Qt app?

I naively tried this:


try {
app.exec();
}
catch(...) {
// launch crash dialog
}
which does not work because Qt does not use exceptions.

Is there a platform independent solution to make my app crash gracefully? Or do I need to look into signals on Linux, etc.

Richard

mcosta
5th May 2009, 08:17
I usually use a slot fatalError(const QString&) in program's Main Window and connect this with children's signal fatalError(const QString&).

The code of MainWindow::fatalError can be:


void MainWindow::fatalError(const QString& _details)
{
QMessageBox mbox(
QMessageBox::Critical,
tr("Fatal Error"),
tr("%1 has encountered an error and cannot continue to work.\n"
"Please press OK button to quit.").arg(qApp->applicationName()),
QMessageBox::Ok,
this);

mbox.setDetailedText(_details);

mbox.exec();
qApp->quit();
}

rbp
5th May 2009, 09:03
how do the child widgets know when to emit fatalError()?

mcosta
5th May 2009, 10:37
You can catch failure conditions and emit fatalError

rbp
5th May 2009, 13:09
that seems to be back to my original problem, except with the child widgets instead of the main window. I have found I can't catch errors because Qt doesn't use exceptions.

How do you catch all errors for a widget?

mcosta
5th May 2009, 13:30
Sorry, but I don't understand the question!

Qt don't use exceptions for signaling errors but each method returns a value (typically a boolean) that indicates the result of the executed operations.

You can test this value and emit the fatalError signal.

If you give some examples, I can help you.

rbp
5th May 2009, 13:44
ah OK, yeah I already handle those kind of anticipated errors.

What I'm aiming at is handling unexpected errors - even a great app like Firefox crashes unexpectantly sometimes. See here (http://www.codinghorror.com/blog/archives/001239.html).
If/when my app crashes I want them to send debugging information to a central server. But so far I haven't figured out how to 'catch' the crash.

lni
5th May 2009, 16:35
Don't think you can find any help from here on this issue, see this:
http://www.qtcentre.org/forum/f-qt-programming-2/t-unix-signal-causing-gui-to-exit-20172.html

wysota
5th May 2009, 20:34
If/when my app crashes I want them to send debugging information to a central server. But so far I haven't figured out how to 'catch' the crash.

If your application crashes, you have to be prepared for the crash - you have to expect it to crash in a particular place. Crash is either an unhandled exception that you can catch (Qt doesn't throw exceptions but it doesn't prevent exceptions to be thrown from other classes/functions) or a situation when you violate an OS policy and your application gets terminated. If the crash happens in your code, you can use exceptions and do some cleanup. If the crash happens unexpectedly then using GUI (or network) is probably unsafe anyway as I said in the thread quoted by Ini.

If you force firefox to sigsegv, it won't close gracefully, it will just be terminated. The feedback thingy is probably an external application that gets executed when a crash occurs and that you can do with your application as well upon a sigsegv. But it won't give you much meaningful information (except a backtrace).

lni
5th May 2009, 21:16
If your application crashes, you have to be prepared for the crash - you have to expect it to crash in a particular place. Crash is either an unhandled exception that you can catch (Qt doesn't throw exceptions but it doesn't prevent exceptions to be thrown from other classes/functions) or a situation when you violate an OS policy and your application gets terminated. If the crash happens in your code, you can use exceptions and do some cleanup. If the crash happens unexpectedly then using GUI (or network) is probably unsafe anyway as I said in the thread quoted by Ini.

If you force firefox to sigsegv, it won't close gracefully, it will just be terminated. The feedback thingy is probably an external application that gets executed when a crash occurs and that you can do with your application as well upon a sigsegv. But it won't give you much meaningful information (except a backtrace).

see this: http://www.slb.com/media/services/software/support/gfdk/CSL_Exc.pdf

wysota
5th May 2009, 22:59
see this: http://www.slb.com/media/services/software/support/gfdk/CSL_Exc.pdf

I'm not sure what point are you trying to give by referring that document. C++ has its own exception system which seems a bit more advanced than that of CSL (still crappy though). And by the way, SIGSEGV and SIGBUS are not exceptions (they are much more serious than exceptions, they are "generated" by the operating system), let's not mix the concepts (it's as if we said C was an object oriented language because it supported structures).

lni
5th May 2009, 23:32
I'm not sure what point are you trying to give by referring that document. C++ has its own exception system which seems a bit more advanced than that of CSL (still crappy though). And by the way, SIGSEGV and SIGBUS are not exceptions (they are much more serious than exceptions, they are "generated" by the operating system), let's not mix the concepts (it's as if we said C was an object oriented language because it supported structures).

You may be right that CSL is crappy. But that codes work. That is probably one of the reasons that Schlumberger software has had much better sale than most other competitors.

The concept is easy to understand, when an exception or signal is raised, the signal handler catch and throw an exception, and event handler process the exception and never let the exception handler return out of the function. If the exception handler return from the function, it will go back to where it crashes, which will trigger exception handler again, causing a dead loop.

So the idea is to throw out of the crash point, and let the program return back to the normal event loop, the problem is then solved... Schlumberger can do it, I think Qt can do it too...

Let's not talk about SEGV, let's do "man abort", and see what is said: "The abort() function shall cause abnormal process termination to occur, unless the signal SIGABRT is being caught and the signal handler does not return". I just don't know how to do it in Qt...Perhaps you know it...

There is no example on Qt for this: http://doc.trolltech.com/main-snapshot/unix-signals.html

wysota
6th May 2009, 00:30
You may be right that CSL is crappy.
I meant C++ exceptions were crappy :) I didn't use CSL so I won't claim to know it enough to give opinions about it.


The concept is easy to understand, when an exception or signal is raised, the signal handler catch and throw an exception, and event handler process the exception and never let the exception handler return out of the function. If the exception handler return from the function, it will go back to where it crashes, which will trigger exception handler again, causing a dead loop.

So the idea is to throw out of the crash point, and let the program return back to the normal event loop, the problem is then solved... Schlumberger can do it, I think Qt can do it too...
Which doesn't change the fact that without apriori knowledge it's not safe to do practically anything after a SIGSEGV that involves any code that was operating during the SIGSEGV (hence it's not safe to use Qt is its event loop was active when the signal was raised).


Let's not talk about SEGV, let's do "man abort", and see what is said: "The abort() function shall cause abnormal process termination to occur, unless the signal SIGABRT is being caught and the signal handler does not return". I just don't know how to do it in Qt...Perhaps you know it...
Handling abort() is very easy, you don't even need to handle signals to do that. There is a callback you might register that will be called when abort occurs. I can't find a reference to it but it should work as atexit(). Or maybe I'm wrong and the function is not in the standard... Nevertheless you can still use signal() or sigaction() to register a handler that will be called on abort() and can handle cleanup.

Which again doesn't change the fact that if abort is called from within an event handler, making any GUI calls won't make sense. And there are lots of cases where the application is aborted not from within the application (with abort()) but by the operating system (with SIGSEGV for example). If memory (like the stack) gets corrupted, there is really nothing you can do...


There is no example on Qt for this: http://doc.trolltech.com/main-snapshot/unix-signals.html

Everything that applies to handling unix signals in general applies to handling them from within Qt based applications.

lni
6th May 2009, 00:38
Handling abort() is very easy, you don't even need to handle signals to do that. There is a callback you might register that will be called when abort occurs. I can't find a reference to it but it should work as atexit(). Or maybe I'm wrong and the function is not in the standard... Nevertheless you can still use signal() or sigaction() to register a handler that will be called on abort() and can handle cleanup.
.

Can you give a simple example on this? Let's just handle abort() for now. Thanks

rbp
6th May 2009, 01:29
I agree with you wysota that we need to test our apps.
But unfortunately even the best software teams release code with bugs. And it will be easier to fix them if I can access data from the crash.


If you force firefox to sigsegv, it won't close gracefully, it will just be terminated. The feedback thingy is probably an external application that gets executed when a crash occurs and that you can do with your application as well upon a sigsegv. But it won't give you much meaningful information (except a backtrace).

that's exactly what I'm after - how to respond to the program crash and access debugging data such as a backtrace.
Are Unix signals (http://doc.trolltech.com/main-snapshot/unix-signals.html) the way to go? Including on Windows?


Ini: what you are after sounds ambitious - that would be awesome if you could achieve it! Have you made progress since you posted that thread last month? From your comments it seems you are still at the same point as me of trying to respond to a crash.

lni
6th May 2009, 04:51
Ini: what you are after sounds ambitious - that would be awesome if you could achieve it! Have you made progress since you posted that thread last month? From your comments it seems you are still at the same point as me of trying to respond to a crash.

I have some progress, but not what I hope.

I can intercept SEGV and bail out the function, return back to event loop, pretending nothing has happened (of course I can tell users that a SEGV has been caught, and ask him/her to review the input parameters and try again), and it only works in optimized mode....However, when abort() is called, it goes to endless loop in the signal handling function...

If anyone interested, I can share the codes, but you promise that if you fix or solve a problem, you return the codes to me...

rbp
6th May 2009, 05:00
If anyone interested, I can share the codes, but you promise that if you fix or solve a problem, you return the codes to me...

I am interested!
If I work out how to catch other crash cases I will certainly post here.

btw, what platform are you developing for?

wysota
6th May 2009, 08:31
Can you give a simple example on this? Let's just handle abort() for now. Thanks


#include <signal.h>
#include <stdlib.h>
#include <stdio.h>

void handler(int s){
printf("abort intercepted\n");
}

int main(){
signal(SIGABRT, handler);
abort();
return 0;
}



I agree with you wysota that we need to test our apps.
But unfortunately even the best software teams release code with bugs. And it will be easier to fix them if I can access data from the crash.
For a backtrace to be meaninful, the application has to be built in debug mode and giving end-users a debug release of the program is not the wisest thing to do. So if you want "crash handling" it would only make sense while developing. This in turn means you have access to a debugger and can have a regular backtrace output.

But let's assume there are testers that are to report crashes, in that case having a backtrace printed from within the application might be a nice thing. To have a backtrace printed, simply use the backtrace() or backtrace_symbols() which are a GNU extension to C (so they should be available with GCC and family). There are probably equivalents for non-GNU environments as well.


that's exactly what I'm after - how to respond to the program crash and access debugging data such as a backtrace.
Are Unix signals (http://doc.trolltech.com/main-snapshot/unix-signals.html) the way to go? Including on Windows?
As far as I know you can use those signals on Windows as well but I'm not sure if they are invoked in the same conditions as on Unix.

If you want to be able to issue a full report from your application, there is a simple way to do it. Start your application as a child process of another application that will act as a feedback manager. The parent can monitor the state of the child and when it terminates, it can read its stderr (that can contain a backtrace) and can send the data to the producer or do a number of different things.

In this thread we are really dealing with two completely different things. One is crash reporting and the other is crash recovery. While the first is basically possible in almost any conditions, the latter will most likely fail when the application crashes because it went out of control (i.e. overwritten its stack pointing the instruction pointer into garbage).

lni
6th May 2009, 15:52
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>

void handler(int s){
printf("abort intercepted\n");
}

int main(){
signal(SIGABRT, handler);
abort();
return 0;
}


I mean to handle abort() in the Qt loop. That is, the handler will throw exception, and then caught by Qt event loop. The event loop will ignore it, and the GUI will stay alive...

Imagine abort is triggered by "assert( 0 )", it is not a live and dead situation, so I don't want the application to die...

wysota
6th May 2009, 16:13
I mean to handle abort() in the Qt loop. That is, the handler will throw exception, and then caught by Qt event loop. The event loop will ignore it, and the GUI will stay alive...
Unfortunately abort() does something more than just raise SIGABRT. It is meant to abort the application, not let it live. If you handle a signal, the execution will go back to the place it has been when the signal occured. You can cheat by using "goto" from within the signal handler but it's very risky and won't let you continue normal execution because the stack will be corrupted.

If you want, you can substitute abort() with some other function that will not terminate the application. Just make sure "your" implementation of abort() is linked to the application before the "real" one (i.e. using LD_SO_PRELOAD on Linux).


Imagine abort is triggered by "assert( 0 )", it is not a live and dead situation, so I don't want the application to die...

So don't use assert(). You can use Q_ASSERT or Q_ASSERT_X instead which are a noop in release mode. Besides, if you fear things such as assert(), then simply do a gracefull error check and recovery instead of asserting.

lni
6th May 2009, 16:36
Besides, if you fear things such as assert(), then simply do a gracefull error check and recovery instead of asserting.

In a perfect world, we all should be doing that. Unfortunately, no one can write a bug free software. Nobody wants to be hit by a car, it is just the car hits people :)

Anyway, I have a crash test, if anyone fix or solve a problem, please include in this thread so we all get benefit of it.

wysota
6th May 2009, 16:46
In a perfect world, we all should be doing that. Unfortunately, no one can write a bug free software. Nobody wants to be hit by a car, it is just the car hits people :)

Does it matter if instead of assert() you call myAssert()? Especially that AFAIR it's a macro anyway...


void myAssert(bool t){
if(t) return;
QMessageBox::critical(0, "Assert", "An assert has occured, the application will close");
abort();
}

rbp
8th May 2009, 08:54
If you want to be able to issue a full report from your application, there is a simple way to do it. Start your application as a child process of another application that will act as a feedback manager. The parent can monitor the state of the child and when it terminates, it can read its stderr (that can contain a backtrace) and can send the data to the producer or do a number of different things.

I tried this suggested method with QProcess and was able to catch the crash. However the Windows crash dialog also came up, which would be confusing for the user.
Do you know how to make Windows leave me alone? Do I need to suppress signals like SIGABRT?
Alternatively maybe I could try and access the Windows crash data...

Sorry that this question is moving out of Qt territory and into C++/Windows programming. If you think it's too off topic I could reask it in a more relevant forum.
I'm usually a Linux programmer so this kind of stuff is particularly frustrating!