Recent

Author Topic: [SOLVED] Try...Except for external exception?  (Read 2049 times)

Eugene Loza

  • Hero Member
  • *****
  • Posts: 674
    • My games in Pascal
[SOLVED] Try...Except for external exception?
« on: May 21, 2023, 09:56:32 am »
Is there any way to try...except situations like this? I want to show some meaningful logs when an error happens, but instead my app just crashes. Especially uncomfortable to debug rare bugs in an Android app this way.

Code: Pascal  [Select][+][-]
  1. program TestTryExcept;
  2.  
  3. var
  4.   O: TObject;
  5. begin
  6.   try
  7.     WriteLn(O.ClassName);
  8.   except
  9.     WriteLn('error');
  10.   end;
  11. end.
  12.  
« Last Edit: May 21, 2023, 01:52:56 pm by Eugene Loza »
My FOSS games in FreePascal&CastleGameEngine: https://decoherence.itch.io/ (Sources: https://gitlab.com/EugeneLoza)

alpine

  • Hero Member
  • *****
  • Posts: 1064
Re: Try...Except for external exception?
« Reply #1 on: May 21, 2023, 10:09:41 am »
The O isn't instantiated.
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

TRon

  • Hero Member
  • *****
  • Posts: 2515
Re: Try...Except for external exception?
« Reply #2 on: May 21, 2023, 10:10:19 am »
Must be specific to android ? e.g. no console ?

Code: [Select]
$ fpc -B TestTryExcept.pas
Free Pascal Compiler version 3.2.2 [2021/05/16] for x86_64
Copyright (c) 1993-2021 by Florian Klaempfl and others
Target OS: Linux for x86-64
Compiling TestTryExcept.pas
TestTryExcept.pas(11,13) Warning: Variable "O" does not seem to be initialized
Linking TestTryExcept
15 lines compiled, 0.1 sec
1 warning(s) issued
$ ./TestTryExcept
error

Eugene Loza

  • Hero Member
  • *****
  • Posts: 674
    • My games in Pascal
Re: Try...Except for external exception?
« Reply #3 on: May 21, 2023, 10:25:42 am »
Quote
Must be specific to android ? e.g. no console ?

Nah, there is a console on Android, but you need to keep it connected to desktop all the time to see what actually happens.

And I'm very surprised you got "error" in console because I don't. Maybe my FPC installation is broken (I'm using not-the-latest trunk)? "except" part is completely ignored for me, even in Debug mode where it actually shows it as an internal exception, not external one.

Quote
The O isn't instantiated.

Yes, in this specific situation is obvious. However, in a computer game with 30k lines of code things are not as quite obvious, unfortunately :D Hunting this-or-that dangling pointer can get really hard, especially if a bug occurs once in 2-3 days and you can only guess what could have gone wrong. And at least a hint on where the error occurred might be invaluable for debugging.

Update:

Moreover, this way one can even cheat around rare bugs. If this situation happens once in a blue moon, it might not be even worth spending weeks on tracking down the issue, user will just see an error message and a monster will misbehave for a frame:

Code: Pascal  [Select][+][-]
  1. try
  2.   Monster.Ai.Update;
  3. except
  4.   ShowError('Monster AI crashed');
  5.   Monster.Ai.Free;
  6.   Monster.Ai := TMonsterAi.Create(Monster);
  7. end;
« Last Edit: May 21, 2023, 10:39:16 am by Eugene Loza »
My FOSS games in FreePascal&CastleGameEngine: https://decoherence.itch.io/ (Sources: https://gitlab.com/EugeneLoza)

TRon

  • Hero Member
  • *****
  • Posts: 2515
Re: Try...Except for external exception?
« Reply #4 on: May 21, 2023, 10:48:18 am »
Nah, there is a console on Android, but you need to keep it connected to desktop all the time to see what actually happens.
I am not familiar with Android myself but the message you showed looks similar to what I got on linux when I try to use write/writeln friends in a GUI application. In that case the I/O is not routed to anything (by default).

I can solve that by including a unit that does route the I/O to something sensible (such as a memo).

Quote
And I'm very surprised you got "error" in console because I don't. Maybe my FPC installation is broken (I'm using not-the-latest trunk)?
I am using 3.2.2. But it works that way for me on older versions as well.

Quote
"except" part is completely ignored for me, even in Debug mode where it actually shows it as an internal exception, not external one.
Perhaps/maybe the exception handling for Android is not fully implemented ? As said, I am not familiar with the target.

Eugene Loza

  • Hero Member
  • *****
  • Posts: 674
    • My games in Pascal
Re: Try...Except for external exception?
« Reply #5 on: May 21, 2023, 10:52:54 am »
Quote
Perhaps/maybe the exception handling for Android is not fully implemented ?

Hypothetically it can be, because not-so-long-ago I was getting "null pointer" crashes - while Desktop showed me proper stacktrace on the screen, Android just silently killed the app. But the issue above (accessing a nil pointer or a dangling pointer) is reproducible for me even on Desktop. The except part was just ignored completely. Maybe indeed I should try it with stable version (but I have an important bug fixed in Trunk but not yet in (some recent stable version (3.2.0?), I didn't try the latest one), so rather for testing purposes).
My FOSS games in FreePascal&CastleGameEngine: https://decoherence.itch.io/ (Sources: https://gitlab.com/EugeneLoza)

alpine

  • Hero Member
  • *****
  • Posts: 1064
Re: Try...Except for external exception?
« Reply #6 on: May 21, 2023, 10:57:14 am »
And at least a hint on where the error occurred might be invaluable for debugging.

See
https://wiki.lazarus.freepascal.org/Logging_exceptions#System_ExceptProc
https://wiki.lazarus.freepascal.org/Logging_exceptions#Dump_exception_call_stack

And it is good to have line debug info included (-gl).

EDIT: Not sure about Android.
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

Warfley

  • Hero Member
  • *****
  • Posts: 1499
Re: Try...Except for external exception?
« Reply #7 on: May 21, 2023, 11:07:23 am »
You need to put sysutils in the uses clause to correctly setup exceptions

Eugene Loza

  • Hero Member
  • *****
  • Posts: 674
    • My games in Pascal
Re: Try...Except for external exception?
« Reply #8 on: May 21, 2023, 01:26:26 pm »
You need to put sysutils in the uses clause to correctly setup exceptions
Wait... is that... it??? It's working now!!!!
Huge thank you!!!
That also explains why _some_ exceptions got caught while others slipped through.

On the other hand, I'd never ever expect that...
My FOSS games in FreePascal&CastleGameEngine: https://decoherence.itch.io/ (Sources: https://gitlab.com/EugeneLoza)

TRon

  • Hero Member
  • *****
  • Posts: 2515
Re: Try...Except for external exception?
« Reply #9 on: May 21, 2023, 01:49:09 pm »
That also explains why _some_ exceptions got caught while others slipped through.
True. For your example-code there is/was no need to use sysutils but if you want to catch rtl related exceptions or raise your own then you would have to include sysutils.

Apparently unit sysutils does a bit more (initialization) for setting up exceptions on Android target than for my used Linux target.

/That/ is something /I/ did not figure  :)  (good catch Warfley)
« Last Edit: May 21, 2023, 01:55:14 pm by TRon »

Warfley

  • Hero Member
  • *****
  • Posts: 1499
Re: Try...Except for external exception?
« Reply #10 on: May 21, 2023, 01:57:38 pm »
Both the unit sysutils and classes do a lot of initialization, and should not be omitted. From sysutils:
Code: Pascal  [Select][+][-]
  1. Initialization
  2.   InitExceptions;       { Initialize exceptions. OS independent }
  3.   InitInternational;    { Initialize internationalization settings }
  4.   SysConfigDir:='/etc'; { Initialize system config dir }
  5.   OnBeep:=@SysBeep;
  6. {$ifdef android}
  7.   InitAndroid;
  8. {$endif android}
  9.  
  10. Finalization
  11.   FreeDriveStr;
  12.   FreeTerminateProcs;
  13.   DoneExceptions;
  14. end.
  15.  
  16.  
InitExceptions registers a handler for external events (like divide by 0, segfault, etc) and raises an exception from it. So while in Language exceptions (i.e. those you raise yourself) still work, to convert external (signal) events to exceptions you need sysutils (or register your own handler)

Also sysutils initializes i18 so if you want to write multi lingual programs you also need sysutils

Also important is classes, which does the following:
Code: Pascal  [Select][+][-]
  1. procedure CommonInit;
  2. begin
  3. {$ifdef FPC_HAS_FEATURE_THREADING}
  4.   SynchronizeTimeoutEvent:=RtlEventCreate;
  5.   InterlockedIncrement(ThreadQueueLockCounter);
  6.   InitCriticalSection(ThreadQueueLock);
  7.   MainThreadID:=GetCurrentThreadID;
  8. {$else}
  9.   MainThreadID:=0{GetCurrentThreadID};
  10. {$endif}
  11.   ExternalThreads := TThreadList.Create;
  12. {$ifdef FPC_HAS_FEATURE_THREADING}
  13.   InitCriticalsection(ResolveSection);
  14.   TThread.FProcessorCount := CPUCount;
  15. {$else}
  16.   TThread.FProcessorCount := 1{CPUCount};
  17. {$endif}
  18.   InitHandlerList:=Nil;
  19.   FindGlobalComponentList:=nil;
  20.   IntConstList := TThreadList.Create;
  21.   ClassList := TThreadList.Create;
  22.   ClassAliasList := nil;
  23.   { on unix this maps to a simple rw synchornizer }
  24.   GlobalNameSpace := TMultiReadExclusiveWriteSynchronizer.Create;
  25.   RegisterInitComponentHandler(TComponent,@DefaultInitHandler);
  26. end;
  27.  
So it initializes threading, the some features of the class system, and the component system.

But this is usually not a problem in any real program, because some unit always includes sysutils or classes. It's just important to know for such minimal examples
« Last Edit: May 21, 2023, 02:03:08 pm by Warfley »

Eugene Loza

  • Hero Member
  • *****
  • Posts: 674
    • My games in Pascal
Re: [SOLVED] Try...Except for external exception?
« Reply #11 on: May 21, 2023, 02:13:41 pm »
Interesting! Thank you!

However, as the matter of fact in 'real' program I used both SysUtils and Classes in many units. And I had a lot of "missed" exceptions when the game would crash instead of showing an error message. And my first guess is that indeed those "uncaught" exceptions came from units that didn't have SysUtils in uses section.

Well, let me try just adding SysUtils and Classes in all units and see if it helps :D I don't think there will be any harm done anyway :)

Hmmm... Now remembering one of the bug: double-checked and one of such crashes came from a unit which had both SysUtils and Classes in uses section... So, still not so straightforward for Android.
My FOSS games in FreePascal&CastleGameEngine: https://decoherence.itch.io/ (Sources: https://gitlab.com/EugeneLoza)

Warfley

  • Hero Member
  • *****
  • Posts: 1499
Re: [SOLVED] Try...Except for external exception?
« Reply #12 on: May 21, 2023, 02:25:42 pm »
I don't know that much about android, but as a Unix system, how it should work is that these external exceptions trigger a signal. Sysutils then just registers signal handlers that catch these signals and turns them into exceptions.

The signals cought are: SIGINT,SIGFPE,SIGSEGV,SIGILL,SIGBUS,SIGQUIT

So my guess is that either android may use additional signals, that are not covered by sysutils (in which case I would consider this a reportable bug), or android uses another mechanism to crash that does not go through signals.

In any way, a concrete example would be nice on the kind of error that cannot be cought, to check what android does in that situation. If it's just another signal type, this should be easily fixable.

PS: you don't need sysutils in every unit, having it once in your project is fully enough

PascalDragon

  • Hero Member
  • *****
  • Posts: 5481
  • Compiler Developer
Re: [SOLVED] Try...Except for external exception?
« Reply #13 on: May 22, 2023, 10:27:15 pm »
However, as the matter of fact in 'real' program I used both SysUtils and Classes in many units. And I had a lot of "missed" exceptions when the game would crash instead of showing an error message. And my first guess is that indeed those "uncaught" exceptions came from units that didn't have SysUtils in uses section.

Without an explicit example it's hard to tell what went wrong.

Hmmm... Now remembering one of the bug: double-checked and one of such crashes came from a unit which had both SysUtils and Classes in uses section... So, still not so straightforward for Android.

The important part for the initialization of the System and Classes units is that they're at least used once in the program. You don't need to use them in every unit if you don't required their other functionality.

Eugene Loza

  • Hero Member
  • *****
  • Posts: 674
    • My games in Pascal
Re: [SOLVED] Try...Except for external exception?
« Reply #14 on: May 22, 2023, 11:14:10 pm »
I'm afraid "explicit example" is too large to be meaningful. I hoped that I've managed to reproduce it on a minimal testcase in the first message of the topic  :-\... But unfortunately it isn't that simple.

I've ran into such issues multiple times and eventually (sometimes after months of testing) figured out what was going wrong, but if you're interested in an example:

Every Actor has a CurrentAction which is Updated every frame. As actions can sometimes get very complex and there are a lot of possible issues with their execution, so it's wrapped inside try...except:

https://gitlab.com/EugeneLoza/vinculike/-/blob/grandmaster/code/actors/gameactor.pas#L166

For example one of such bugs happened before introducing this check:

https://gitlab.com/EugeneLoza/vinculike/-/blob/grandmaster/code/actors/actions/gameactionmarktarget.pas#L113

If the Player Character was near the border of the map and a monster tried to "throw the mark" outside of the map - it would call Mark.MoveCenterTo(SX, SY); afterwards which in turn should have shown an error message that the object is outside of the map:

https://gitlab.com/EugeneLoza/vinculike/-/blob/grandmaster/code/actors/gamepositionedobject.pas#L227

However, originally there was a typo in there: instead of (%.1n, %.1n) on map %dx%d it was (%d, %d) on map %dx%d which obviously was wrong for Single coordinates passed to Args and eventually was rising an exception in Format in:

https://gitlab.com/EugeneLoza/vinculike/-/blob/grandmaster/code/views/gameviewgame.pas#L1447

Which was supposed to be caught by the wrapping try...except, but on Android the app would just close without any explanations, and I was never lucky enough to reproduce the bug on Desktop.
My FOSS games in FreePascal&CastleGameEngine: https://decoherence.itch.io/ (Sources: https://gitlab.com/EugeneLoza)

 

TinyPortal © 2005-2018