Posted By: ZippyV | Jul 12th @ 3:57 AM
page 1 of 2
Comments: 26 | Views: 936
ZippyV
ZippyV
Soapbox = Fail
When an exception is thrown in a .net application you get a JIT error dialog that allows you to continue or quit the application. Is it possible to not show this dialog and quit the application so that Windows behaves the same like with native applications (searching for solution, send error report, register the application crash in the Reliability monitor)?
Sven Groot
Sven Groot
You can't have everything; after all, where would you put it?

That's what it does for me. What Windows version and what .Net version?

Hmm... you mention "fatal" exception in the title. What does "fatal" mean?

If we're talking about StackOverflowException/OutOfMemoryException etc. then you should always get that error reporting dialog. I don't think there's any chance to ever see the .NET exceptin dialog in such cases.

If we're talking about "ordinary" exceptions then it depends from where the exceptin is thrown.

  • If it is thrown from the startup code (like main form's constructor for example) you'll tipically get the error reporting dialog.
  • If it is thrown from an "event" (like OnLoad, OnPaint, Click etc.) the exception is caught by the message loop and that .NET exception dialog is displayed. If you want to get the error reporting dialog then you can try to handle Application.ThreadException event and rethrow the exception (you can find the exception in the event args).

Actually I dug a bit and there's this:


Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);


which is better than the ThreadException event because if you rethrow that exception it will mess up the stack trace.


You folks ever hear of error handling?  If you ever see any dialog like this in a production application, you the programmer are not doing your job. 

All errors should be logged and handled.  Using proper error handling it is possible to construct a program which never has a fatal exception.  Yes your OS might crash but your program should not.  In the unlikely event you have a truly fatal error you still should still log the failure and then terminate your application in a clean elegant manner.  If you log all errors you, the programmer, should be able to prevent the future occurrence of that failure.

You see this error only if the run-time environment encounters an error and no error handler is present to handle it.  So the solution is to use error handling logic everywhere.  While technically it is possible to have application level error handling, my experience shows that doing so does not allow for robust error recovery.  The closer you are to the source of the error, the easier it is to recover from it.  Application error handlers are great to provide application wide documentation capabilities.

TommyCarlier
TommyCarlier
Trust me, I'm from the Internets
I actually agree with lensman. Either it's a bug in your code (DivisionByZeroException, NullReferenceException, ...), or it's a runtime exception you haven't caught yourself (IOException, SocketException, ...). If you see this dialog, something is wrong in your code.
Sven Groot
Sven Groot
You can't have everything; after all, where would you put it?
What about an OutOfMemoryException?
figuerres
figuerres
???
I almost agree....

the video onnthe home page right now with anders mentions the very thing I am thinking of.

In a perfect world, yes you can handle all cases.

the world is not perfect.

yes we should do what we can to deal with stuff.

yes if all else fails we should try and log the problem and then die a clean death.

but sometimes stuff happens that you cannot predict or is so far on the edge that it is only goinng to happen very very seldom.

like a stack over/under flow error, out of memory error and a few others that really the only thing you can do is terminate.

or what happens if you are logging errors and writing them to a text or xml file and the file IO code gets a disk error?
all you can do with that is give the user an error message and halt / exit really.... or swallow that error and let the rest of the app do whatever....

the whole thing comes back to a basic issue I think we all deal with...
what does the word "Exception" mean ?

when is a problem "Exceptional" ?

and if it's not then it is a "predictable condition" and that in of it's self means we should write normal code to test for that condition and not let it get into a Catch () {} block.

but it's easy to just wrap stuff in try/catch blocks and try to handle it ...
but that's *NOT* really what they are meant for.

harder work for us to avoid the catch block trap, but better quality if we do.

but I do use a global handler , that is the right thing to do so that when a real "Exceptional Condition" happens we try to log it and figure out how to avoid it later.



TommyCarlier
TommyCarlier
Trust me, I'm from the Internets

I have never encountered an OutOfMemoryException myself. The closest thing I have encountered was a Win32Exception indicating that a handle could not be created, because our app had too many windows with too many controls and no more new handles could be created. Even though we can't stop our users from having too many windows open, we did fix it by keeping track of the windows, when windows got focus, keeping track of resources (handles, GDI-objects, ...) and when a certain treshold was reached, our app would automatically start closing windows we knew we could close (that did not have changes to save) and that hadn't had focus in a while. This was a pretty exceptional situation that only occurred in 1 of our applications, but happened occasionally until we tracked it down. It's a client/server application and each request a client sends to the server contains client data about the resources (how many windows open, how many handles, ...). This is how we spotted the problem. A part of the solution was also to teach the users that it's a good idea to close a window when you no longer need it.

I didn't want to sound arrogant, because I have seen that dialog myself a lot. But I'm not afraid to admit that if I see it, I know there's a bug in my code that needs fixing. It's not always my code's fault (external factors cannot be eliminated), but I should at least let the application handle it gracefully. If it's an IOException when opening a file the user selected, I can just show an error dialog explaining the file could not be opened. You just have to have the habit of using try-catch at the right places and checking the documentation of certain methods to see which exception can be thrown. If you have this habit, you'll pretty quickly know exactly when to expect an IOException or a SocketException, especially when you develop communication software.

Sven Groot
Sven Groot
You can't have everything; after all, where would you put it?
I agree with you in general, but there is a class of errors where you can do nothing except terminate. IOException is not one of them, for sure. And even if a NullReferenceException is a bug, there's still nothing you can do to safely recover from it since your app is likely going to be in an inconsistent state after that. So if it happens in a production app, yes it's a bug, but you still want to log it and terminate, not try to handle it.

I usually put some code in Application.ThreadException which throws up a dialog which allows the user to send an error report (with the complete exception info, including stack trace etc. and some diagnostic info like the version of the OS and the CLR) to me (instead of Microsoft), then terminate after that. That way I can fix the bug in future versions.

I recently got a whole bunch of OutOfMemoryErrors in Java even though the system and the JVM weren't anywhere near out of memory. I believe it was a bug with the Sun JVM when used on RHEL3 (as the problem did not occur on other Linux distributions).
TommyCarlier
TommyCarlier
Trust me, I'm from the Internets

The bug was that you were using Java. And Linux.

Wink

Sven Groot
Sven Groot
You can't have everything; after all, where would you put it?

Unfortunately I had no choice in the matter on this occasion. I reformatted the servers in question with Ubuntu Server 8.04 and now all is fine though. Smiley

The problem on RHEL3 was that it refused to create more than 23 threads (I created a simple test program that just looped and created threads and it always crashed at the 24th thread). The JVM would be using 40MB RAM at that point even though the system has 2GB RAM so it was obviously not a real out of memory situation. On my Ubuntu desktop installation in VMWare the same test program would crash only after more than 4000 threads, even though that VM had onlky 512MB RAM.

Wow... such a simple question resulted in a thread that's likely to have a second page Smiley

Since Zippy mentioned "register the application crash in the Reliability monitor" I'd assume he has a very specific reason for asking this. After all he may very well log all exceptions but prefer that error reporting dialog and what goes with it to what the framework provides (for the record, the .NET dialog is not even a .NET specific dialog but a WinForms one).

And there's too much generalization going on here. You can't handle everything, sooner or later an exception will find its way out of your program and some sort of error dialog will pop up. If it's the WinForm's exception dialog or a custom one that will allow the user to report the error to the devloper that's for the developer to decide.

For example I'm currenly dealing with some error reports that involve various methods from System.Drawing throwing AccessViolationException. It's not a single exception, it's a cascade of exceptions. Some code throws one exception, the program tries to put up a custom exception dialog which in turn causes other System.Drawing related exceptions then there's some repainting on the main form and other exceptions. In the end the whole thing blows up and I cannot do much about it.

In this specific case it would be quite interesting to do what ZippyV asked for because such an exception is very likely caused by a bug in  GDI+/video driver/.NET runtime rather than application's code.

 

Out of memory is still a programming design issue. 

A program must take into consideration the targeted environment.  When working with a database a common programming flaw is to bring too many rows and fields into memory.  For example "select * from tablename".  Do you really need every column in a given row or only two of the columns?  What happens to your program if 80,000 rows are returned instead of the expected 8 rows?

In long running programs, relying upon garbage collection to clean up resources is a serious breech of programming protocol.  A good program uses resources and releases them in a timely manner.  You should be a good steward of resources as they are limited in nature.  Just because the system has 4GB of physical memory does not mean you should use it all.  You are after all most likely not working for Microsoft and consuming all system resources is not a valid option.





  • In a perfect world, yes you can handle all cases.  The world is not perfect.
I completely agree the world is not perfect.  We are however working within the world of computers.  Nothing happens unless you tell it to or by your inaction cause it happen.  We are after all at the most basic level working with a bunch of 0's and 1's.   Blushing

  • but sometimes stuff happens that you cannot predict or is so far on the edge that it is only goinng to happen very very seldom. like a stack over/under flow error, out of memory error and a few others that really the only thing you can do is terminate.
While I agree there is sometimes nothing can be done, this is a rare not common occurrence.  Memory overflows boil down to a bad program design.  Opening to many resources without cleaning things up yourself.  Stack overflows occur either due to recursion or too many large objects being passed into methods.  A redesign to pass by reference might be in order.

  • or what happens if you are logging errors and writing them to a text or xml file and the file IO code gets a disk error?

You are correct.  How do you handle errors in an error handler?  Again, try to handle them but some are "fatal".  Your code should however document that point in your code and provide a message to the user.  If your program is a service of course then you can't do this as no UI exists.  Again, this is a question of design.  The failures within an error handler should be rare.  If they are common, again you have a design issue.

  • what does the word "Exception" mean ?
Technically any deviation from the expected is an exception.  We are after all doing "complete" validation of all input right?? :->

  • and if it's not then it is a "predictable condition" and that in of it's self means we should write normal code to test for that condition and not let it get into a Catch () {} block.
I would argue that try/catch block should still be used.  Yes standard things should be handled in code.  Providing a interactive user with a message "you may not enter zero for the monthly balance" is better than division by zero errors.  In all cases you should still document the failure.  If you should a message to someone is your choice.

but it's easy to just wrap stuff in try/catch blocks and try to handle it ...
but that's *NOT* really what they are meant for.

  • harder work for us to avoid the catch block trap, but better quality if we do.
I completely agree.  We are after all only human.  I view try/catches as a way to fine tune your programmed error processing over time.  You can after all log variable states within your capture blocks.


littleguru
littleguru
allein, allein,... allein, allein!

My stand here is to better don't catch an exception that you can't catch instead of catching them for the sake of doing so. Something that isn't catchable shouldn't be catched and result in a (clean) crash. That would also make the user aware of the problem and report it. Otherwise you try to somehow recover and that might fail and result in a semi-valid state.

Why did the exception happen in the first place? Well, because there was something going wrong, really wrong, and that should also result in something going really wrong (probably crash) instead of a desperate catch that doesn't work out.

Btw. how could you ever catch (in a reasonable way) all cases that might result in a crash?

I have never encountered an error which could not be captured.  In my view crashes are an unacceptable solutions to poor programming.  Physically failing hardware is one thing, incorrectly coded software is another.

  • Why did the exception happen in the first place? Well, because there was something going wrong, really wrong, and that should also result in something going really wrong (probably crash) instead of a desperate catch that doesn't work out.

Are you going to start arguing that "rebooting the system", "uninstall/reinstall the program", or "use FDISK" are valid error recovery techniques?  Meeting 70% of user needs is not, and never will be, an acceptable solution.  I write applications that are used in an entprise operating 24x7x365 with 700+ active users at a given moment.  My goals are to exceed expectations, not meet the minimums.  Software development is a long term process.  A delivered product is never complete it simply a point in time of the on-going development process.

Accepting that something is going wrong and allowing it to fail is a strategy.  A better strategy is to capture the failure, document where it took place, what the variables are, what was the stack and memory conditions are all valuable points of information in resolving problems.  For example if your method expects the value of "x" to be between 5 and 20, would it not be a good idea to know the value is -5?  A properly logged error is a starting point for your next revision of the program in question.  Capturing errors closest to the point of failure allow for greater resolution of variables.  Scope blocks access to variables when you bubble errors outwards.  Please note that I keeping saying "logged errors" and not "displayed errors".  Most end users could care less about the details.  They just want an application which keeps working.  If it is going to die a horrible death a warning is nice but displaying a stack display to an end-user is basically pointless.  In all cases the logged errors are your resource for details of the failure.

What actions you do when something fails is a programming choice.  For example, coding your program in a transactional nature is a good idea.  All methods should have a clearly defined entrance and single exit point.  Everything should return with a success/failure indictation and appropiate error paths followed.  Stopping the process is equally as important as executing the process.



Sven Groot
Sven Groot
You can't have everything; after all, where would you put it?
That is what littleguru is arguing. What he means is that after you've done that, you shouldn't try to recover and continue execution. If you do that, you're likely to cause another, related failure at some later point which will be much harder to diagnose.

Crash the program (and log all possible data about the failure as you do so), don't try to continue running in an inconsistent state.