Any decent way to catch unhandled exceptions?

BlitzMax Forums/BlitzMax Programming/Any decent way to catch unhandled exceptions?

Grey Alien(Posted 2015) [#1]
It's been years since I brought this topic up. Back in the day I added some code to my framework to handle unplanned exceptions (i.e. not ones I've raised, but bugs that you didn't account for) but I thought I'd check in to see if anything has changed or there are better ways to do things.

Basically I wrap my whole game in Try Catch and then handle the raised error (I detect it as an object and then query the type and do different things). This doesn't work for divide by zero errors btw (see example code).

*The main problem* is that this works well in Debug mode, but when you compile a Release build, it's rare that anything is caught (unless you raised the error with your own code). So you can't exit gracefully and log the error or even say sorry :-) Instead an error will be shown by the OS, which might be OK in Windowed mode, but it's bad in full screen mode as the user can't see it unless they alt+tab out of the crashed game. (This happen to a few customers of my games)

Ideally the game would gracefully bomb out of full screen mode and show an error that the user can report back. Anyone got something like that that works?

Here's some example code to show what I mean.

SuperStrict
Try
		Local DebugMode:Int=0
		?Debug
		DebugMode = 1
		?
		Print "DEBUG="+DebugMode  
		
		Local TestType:Int = 1
		
		Select TestType
			Case 1
			'Null object
			'Caught in debug mode only
			'Release mode shows "EXCEPTION_ACCESS_VIOLATION"
			Local i:TImage
			DrawImage i, 0, 0
			
			Case 2
			'Divide by zero
			'Not caught in debug mode
			'Release mode shows "EXCEPTION_INT_DIVIDE_BY_ZERO"
			Local zero:Int = 0
			Print 100/zero
	
			Case 3
			'Array out of bounds
			'Caught in debug mode only
			'Release mode shows nothing!
			Local a:Int[10]
			a[11] = 1
	
			Case 4
			'File handling fail (just results in a null object)
			'Caught in debug mode only
			'Release mode shows "EXCEPTION_ACCESS_VIOLATION"
			Local f:TStream = ReadStream("nothing")
			Print ReadLine(f)		
		End Select
Catch o:Object
		Print "CAUGHT"
End Try


Thanks!


Brucey(Posted 2015) [#2]
There's a SIGFPE signal for floating point exceptions, that you could maybe handle and do something with - like dump to a logfile or some such.
However, the program *will* exit on return from your handler.

Divide by zero is a programming error, not an exception as such. Better to test your uncertain divides (for zero) before you crash your program :-)

Local f:TStream = ReadStream("nothing")
Print ReadLine(f)

If you are *really* coding like this, and not checking for "If f Then", then you only have yourself to blame.
You should be coding defensively. Assume that these kind of calls can return Null, and deal with them appropriately.


Grey Alien(Posted 2015) [#3]
No I'm not coding like that. I always check f :-)

I'm just using that as an example of maybe something that could go wrong and not be handled. Like what if f existed but Readline failed in some other way?

So anyway, it sounds like there isn't a decent top level way to trap an error and bomb out of full screen mode and show it.


Yasha(Posted 2015) [#4]
Remember that in general programming there's a distinction between errors and exceptions. One's a programmer mistake, the other is unusual control flow around a problematic but fundamentally legitimate operation.

BlitzMax happens to make (some) errors available as exceptions in Debug mode so you can handle them in code (the most intuitive way to handle anything) while developing your program. They're shouldn't be expected to still be reported in Release mode, and fundamentally there is no good way to handle many of them because they can theoretically leave your program in the kind of inconsistent state that makes reliable recovery impossible (trying to continue in Debug mode makes sense only because the program is implicitly running on the machine of someone who understands and can see/change the source). In the case of out-of-bounds access it's usually not even possible to detect it in any reasonable way.


If you're expecting people to see and report bugs, they're not really customers - they're testers. May as well give them a Debug build. A program experiencing array-out-of-bounds errors is not complete.


Brucey(Posted 2015) [#5]
Well, a stream-related error should throw a TStreamException (if either of the low level ReadBytes, WriteBytes or SkipBytes fail).
You can Catch that.


Grey Alien(Posted 2015) [#6]
OK thanks. Yeah it's just that ideally for a release build I wanted it to close full screen and show some kind of error instead of hang (in the event of a rare unhandled bug), which players hate.

But, yeah, if I get customers with a problem like that then I can send them a debug build and see if that throws up an error which is only trapped in debug mode as that might help narrow it down.