Unhandled Exception Issues

I’m seeing a problem with Xojo 2017r2 /r2.1 that I have not seen before.

In my App object, I have code in the UnhandledException event to basically alert me any time as user encounters one of these (it’s been great at fixing bugs over the years) and to also keep the app from crashing on the user when one does happen.

However, in my latest release, I have been getting some reports of unhandled exception errors and the program crashing. I’ve even seen it myself. It’s odd because my code is still there but it seems like the framework is not raising the event like it should.

The last compiled build I did was before r2 I believe. And I’ve never seen this behavior before now…

Anyone else see this?

Thanks,

Jon

I am not sure, but I have the feeling I’m seeing the same here with out in-house App, which I can’t share and so can’t use for a FR.

OK. So it’s not just me.

Throwing an exception with code in the unhandled exception event of the app, should NEVER then cause an unhandled exception error.

That’s the purpose of the event! I am going to try to duplicate this in a simple app. Let’s see if I can…

Uh no. If you write code in the App.UnhandledException event that raises another exception you’ll most likely end up with a StackOverflowException in the end. It’ll just keep calling itself over and over until it crashes.

That said, you should be coding very defensively in that event and don’t rely on exception handling for program flow.

Seeing the code you’ve put in the UnhandledException event might prove useful in tracking this down.

Greg,

I never had a problem with this until now. It’s always worked fine. I know one of the crashes I had was definitely due to a stack overflow like you stated. And that was an error I did fix. But others seem to be related to IteratorException errors in the framework (see:

Here’s my code (and yes the “Return True” on the OutOfMemoryException is probably not the best but the issue that would rarely raise that has gone away with 64 bit now).

So the code basically alerts the user of the problem, creates a log file with the stack info and then uploads it to my FTP server.

Dim type as String

If error IsA OutOfMemoryException Then
  Return True
End If

Dim mystack() as string = error.Stack

If error <> Nil Then
  type = Introspection.GetType(error).Name
  
  ErrorMessage ="An unhandled error occured.  A crash log file with today's date has been created in your application folder.  Please send this to support@justaddsoftware.net "+EndofLine+EndofLine+ _
  "Information about the error: "+type + EndOfLine + EndOfLine +Join(error.Stack, EndOfLine).Left(200)+EndofLine+EndofLine+"Please cancel out of what you were doing and try again."+EndOfLine+EndOfLine+ _
  app.LongVersion+"   "+Str(MajorVersion) + "." + Str(MinorVersion) + "." _
  + Str(BugVersion) + "." + Str(NonReleaseVersion)
  
  ErrorTimer.Mode = Timer.ModeSingle
  ErrorTimer.Reset
  
End If

Dim d as new Date
Dim f as folderitem = GetFolderItem("MediaSwitcherLog_"+str(d.month)+"-"+str(d.day)+"-"+str(d.year)+"_"+str(d.Hour)+"-"+str(d.Minute)+"-"+str(d.Second)+".txt")

If f.Exists Then
  f = GetFolderItem("MediaSwitcherLog_"+str(d.month)+"-"+str(d.day)+"-"+str(d.year)+"_"+str(d.Hour)+"-"+str(d.Minute)+"-"+str(d.Second)+"-a.txt")
End If

#pragma BreakOnExceptions Off
try
  Dim bs as binarystream = binarystream.create(f)
  bs.Write type+EndOfLine
  bs.write Join(error.Stack, EndOfLine)
  bs.Write   app.LongVersion+"   "+Str(MajorVersion) + "." + Str(MinorVersion) + "."+ Str(BugVersion) + "." + Str(NonReleaseVersion)
  bs = nil
catch
end try

Dim bs as BinaryStream = BinaryStream.Open(f)
Dim uftp as New FTPUploadClass
uftp.UploadFTP("MS_ExceptionError_From_"+App.RegName+"-"+App.RegEmail+"_"+Xojo.Core.Date.Now.ToText+".txt", bs)

Return True

Why isn’t this forbidden? That is, why doesn’t it cause immediate program termination?

Stack overflow is immediate on my 4+ GHz machine. :slight_smile:

90% of the time if the Xojo framework does not catch the error then a misbehaving plugin can be suspected.

Because in the App.UnhandledException event you could have a case statement that does different things for different exceptions. So just because you throw an exception one time when the event is called, doesn’t mean that if it’s called from within the event that it’s always going to do the same thing over and over and over again. That’s Greg’s point with being careful in there and coding defensively. Which is good advice.

[quote=352180:@Phillip Zedalis]Stack overflow is immediate on my 4+ GHz machine. :slight_smile:

90% of the time if the Xojo framework does not catch the error then a misbehaving plugin can be suspected.[/quote]

Or a bug in the Xojo Framework. I believe I was seeing one report from a customer where Xojo.Core.Timer.CancelCall was throwing an iterator exception (I now have <https://xojo.com/issue/40246> and <https://xojo.com/issue/49717> open about this.). I haven’t been able to duplicate it but it caused him some headache. I had to code out my use of the Xojo.Core.Timer functions and go with a standard timer that I add as a property and add handlers for and all. Much less convenient but until Xojo takes the time to fix the CancelCall method, it’s going to continue to cause headaches.

[quote=352139:@Jon Ogden]Greg,

I never had a problem with this until now. It’s always worked fine. I know one of the crashes I had was definitely due to a stack overflow like you stated. And that was an error I did fix. But others seem to be related to IteratorException errors in the framework (see:

Here’s my code (and yes the “Return True” on the OutOfMemoryException is probably not the best but the issue that would rarely raise that has gone away with 64 bit now).

So the code basically alerts the user of the problem, creates a log file with the stack info and then uploads it to my FTP server.

[code]
Dim type as String

If error IsA OutOfMemoryException Then
Return True
End If

Dim mystack() as string = error.Stack

If error <> Nil Then
type = Introspection.GetType(error).Name

ErrorMessage ="An unhandled error occured. A crash log file with today’s date has been created in your application folder. Please send this to support@justaddsoftware.net "+EndofLine+EndofLine+ _
"Information about the error: “+type + EndOfLine + EndOfLine +Join(error.Stack, EndOfLine).Left(200)+EndofLine+EndofLine+“Please cancel out of what you were doing and try again.”+EndOfLine+EndOfLine+ _
app.LongVersion+” "+Str(MajorVersion) + “.” + Str(MinorVersion) + “.” _

  • Str(BugVersion) + “.” + Str(NonReleaseVersion)

ErrorTimer.Mode = Timer.ModeSingle
ErrorTimer.Reset

End If

Dim d as new Date
Dim f as folderitem = GetFolderItem(“MediaSwitcherLog_”+str(d.month)+"-"+str(d.day)+"-"+str(d.year)+"_"+str(d.Hour)+"-"+str(d.Minute)+"-"+str(d.Second)+".txt")

If f.Exists Then
f = GetFolderItem(“MediaSwitcherLog_”+str(d.month)+"-"+str(d.day)+"-"+str(d.year)+"_"+str(d.Hour)+"-"+str(d.Minute)+"-"+str(d.Second)+"-a.txt")
End If

#pragma BreakOnExceptions Off
try
Dim bs as binarystream = binarystream.create(f)
bs.Write type+EndOfLine
bs.write Join(error.Stack, EndOfLine)
bs.Write app.LongVersion+" "+Str(MajorVersion) + “.” + Str(MinorVersion) + “.”+ Str(BugVersion) + “.” + Str(NonReleaseVersion)
bs = nil
catch
end try

Dim bs as BinaryStream = BinaryStream.Open(f)
Dim uftp as New FTPUploadClass
uftp.UploadFTP(“MS_ExceptionError_From_”+App.RegName+"-"+App.RegEmail+"_"+Xojo.Core.Date.Now.ToText+".txt", bs)

Return True

[/code][/quote]

You probably miss some code that could help.

If f = nil then some error can occour.
the first binarystream.Create(f) and the first binarystream.Open(f) can be using a Nil folderitem for whatever reason.

If f.Exists and f <> Nil Then

and:
If you catch an error on the binary stream you are still opening the bottom binary stream. It’s better to just use try - catch - end try on both binary stream instances.

try
Dim bs as BinaryStream = BinaryStream.Open(f)
Dim uftp as New FTPUploadClass
uftp.UploadFTP("MS_ExceptionError_From_"+App.RegName+"-"+App.RegEmail+"_"+Xojo.Core.Date.Now.ToText+".txt", bs)
catch 
'do something
end try

I use Xojo.Core.Timer.CallLater quite extensively and never seen an issue just FYI.

[quote=352042:@Jon Ogden]OK. So it’s not just me.

Throwing an exception with code in the unhandled exception event of the app, should NEVER then cause an unhandled exception error.

That’s the purpose of the event! I am going to try to duplicate this in a simple app. Let’s see if I can…[/quote]

Well if you have exception handling basicly like so,
in App.UnhandledException:

'Do something and end with "i handled it" 
Return true

If the next piece of code throws an exception, you’d end up in the same event. It could happen over and over again.
You would or could endup with a crashing application.

If you have well written exception handling in your code, inside the App.UnhandledException event, you would never endup with an unstable application in the end. Use Try catch wherever you can and return true or false based the right outcome.

I’ve had this too, but only with a TCPSocket.Write() command where the TCPSocket was out of scope, just before it was called. Let’s say Xojo.Core.Timer.CallLater( 1000, AddressOf Socket.WriteSomeCommand ), when the socket was Nil before it was called i got that iterator exception. Can’t remember to have ever used Xojo.Core.Timer.CancelCall.

I don’t doubt that. Joe told me that there was a problem at one point and he thought the fixed it. After that, my reports on the issue have gone ignored. I tried to set up an example app yesterday that might be similar to how I am using it and after 30,000 some attempts I couldn’t get it to happen. I’m still trying to figure out what throws it…

Derk, your suggestions on the FolderItem and BinaryStream are good ones! I am finding places like that in other areas of my code where I’m starting to put extra checks for Nil objects even though they “shouldn’t” ever by Nil, it seems like some user always has a way of making that happen!

You may say Derk…:wink: Lol.

Some users can be manipulating a folderitem or some system-cleaning-software could do this. Even so you should be trying to contain the exceptions as much as you can otherwise “return false”. As @Greg O’Lone suggests you don’t ever want to end in a loop calling itself over-and-over.

I can remember a piece of code somewhere in the docs, handling any exception. Then again if you are logging or parsing the exception it should be a perfect-piece-of-code or you end up in a loop. I’ll try to look for that parsing code.

You mean this:

If error <> Nil Then
  Dim type As String = Introspection.GetType(error).Name
  MsgBox(type + EndOfLine + EndOfLine + Join(error.Stack, EndOfLine))
End If

I just pulled it out of the LR. But one problem, it doesn’t return True so the app will still fail! :slight_smile:

I have based my code on that but your comments are spot on examples of the defensive coding needed.

Jon, I suspect you are correct that this is some kind of regression in the Xojo framework. That said, however, I think you are misusing the App.UnhandledException event. It should be the last stop on the way out of an orderly shutdown of your app. Exceptions that you can recover from should really be caught in the code where they originate. Otherwise, you can get into the situation where your app is misbehaving quite badly and your poor end user can’t get out of it.

Tim,

I general I tend to agree with you, and as I find places where I can recover exceptions in the event/method, I do. However, I have used this to find situations where I’ve made coding mistakes. Just yesterday, a customer sent me some logs generated here of a NOE. I looked at the stack trace and found the offending method. I’m looking at what could possibly be nil in the method. And then I saw it. I had a recordset where I was checking that the recordset was not nil. And I was checking to make sure the string value of one of the fields was not an empty string, but what I missed was checking if that field itself was nil! Now I’ve fixed that code so that won’t happen again.

So I find these invaluable to bug tracking. My message to users is to try the action again. If it still happens quit the program and restart it. If it continues to happen after that, I ask them to contact me.

I use UnhandledException to log the event to my website as well. It’s the global return True at the end that I object to. That says, “Log the exception and ignore it,” which is a dangerous thing to do.