Fatal application error not caught by MadExcept - delphi

I have an application which runs multiple threads. I use MadExcept to catch errors and debug it.
The problem is that sometimes after 2-3 hours of running, Windows shows a close program dialog. Why isn't that error handled by MadExcept ?

Threads are a special case. If you have an exception in a thread, it will not get handled by the global handler, and will usually kill your application. The solution is easy though, with madExcept. Just catch the exception, and tell MadExcept about it. It will log in the usual way, and you won't kill your thread.
uses
{$IFDEF MadExcept}
madExcept,
{$ENDIF}
procedure TMyThread.Execute;
begin
try
SetName;
// do your stuff
except
on errInfo : Exception do
begin
{$IFDEF MadExcept}
HandleException(etNormal, errInfo);
{$ENDIF}
end;
end;
end;
What I also do is have the thread set a "RunningOK" property to true when it starts, and the exception sets it to False. This way my control code can see that something went wrong, and handle that appropriately (either restart it, or report the error, etc)

Related

Capture exception in Delphi Application.OnException before try except block

I want to log every exception raised in the delphi application.
For that, I overrided the Application.OnException event with one of my own in the project source code.
program Project;
uses
Vcl.Forms,
Unit1 in 'Unit1.pas' {Form1},
Logger in 'Logger.pas',
JCLDebugHandler in 'JCLDebugHandler.pas';
{$R *.res}
begin
Application.Initialize;
Application.OnException := TApplicationException.AppException;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
This works perfectly, but I´m failing at catching with this solution the exceptions catched in a try-except block.
When the exception is catched in the except block, it just not triggers the Application.OnException event.
Is there any way to first catch it in the Application.OnException event rather than the except block?
The Application.OnException handler is only called for unhandled exceptions.
An unhandled exception is one where no try..except block has caught the exception or where it has been caught and then re-raised.
Using some trivial examples to demonstrate, let's assume that this is virtually the only code in the application and that there are no other exception handlers...
try
a := 42 / 0;
except
on EDivisionByZero do
begin
Log.i('Silly division by zero error has been logged');
raise;
end;
end;
In this case, the exception is caught but the application has no strategy for handling the exception so simply logs that it has occurred and then re-raises the exception. Execution will continue in any outer except block. If there are none, or if any that may exist also re-raise the exception, then eventually the exception will reach the Application.OnException handler.
But an exception handler might not need to re-raise an exception:
try
a := 42 / 0;
except
on EDivisionByZero do
a := 0;
end;
In this case, the exception handler handles the division by zero and does not re-raise it since the code is happy to proceed with a result of zero in that case (unlikely, but this is just an example).
Since the exception is not re-raised, execution proceeds (after the try..except block) as if the exception had never happened in the first place. Your Application.OnException will never know about it.
In summary: Application.OnException is your last chance to deal with an unhandled exception. It is not the first opportunity to respond to any exception.
Intercepting exceptions at the moment that they occur, before any application code has had an opportunity to react or deal with them is possible, but is pretty advanced stuff and no simple mechanism is provided "out of the box".
Fortunately there are 3rd party libraries you can use that may provide the capabilities you are seeking to introduce into your application.
A popular one for Delphi which you might wish to check out is madExcept.
I finally used JCL for capturing and logging all my exceptions. I created a new .pas file with the following code:
/// <summary>
/// Inicializa JCL para capturar la informacion necesaria de la excepcion.
/// </summary>
initialization
JclAddExceptNotifier(SetExceptionError);
JclStackTrackingOptions := JclStackTrackingOptions + [stExceptFrame];
JclStartExceptionTracking;
/// <summary>
/// Finaliza la notificacion de JCL luego de capturar la informacion necesaria de la excepcion.
/// </summary>
finalization
JclRemoveExceptNotifier(SetExceptionError);
end.
With this code, I can capture the exception and treat it in my function SetExceptionError. I was avoiding using some 3rd party framework for this simple logging.

MadExcept for delphi is not printing stacktrace after application crash

Detailed question :
We are trying to capture the stacktrace (bugreport.txt) using MadExcept in a delphi application where a thread is crashing the application with a fatal error. But MadExcept doesn't print any stacktrace after the application crashes. Any ideas why?
OUR CODE :
procedure TMainForm.WSServerExecute(AContext: TIdContext);
begin
try
HTMLExecute(AContext);
except
on E: Exception do
begin
if not(E is EIdException) then
begin
LogData.AddError('HTMLExecute error: ' + E.Message);
madExcept.HandleException;
end;
raise;
end;
end;
end;
This procedure is called when the client makes a websocket connection back to the server. This is a thread produced by the Indy TCPServer component. The HTMLExecute function is what reads and writes packets between the client and server. I've wrapped that in a try..except block to catch any exceptions. The LogData line is what records the error to the Error Log and the madExcept line is supposed to create the bugreport.txt file. The Raise line passes the exception back to Indy so that it knows a fatal error occurred and will abort the thread.
The reason why madExcept is not handling the exception is because you already caught it with on E:Exception do handling it yourself. Just give madExcept.HandleExcept the exception to handle it:
madExcept.HandleException(etNormal, E);
You could try using RegisterHiddenExceptionHandler(stDontDync). See documentation for more details. In your handler then simply do this:
procedure YourHiddenExceptionHandler(const exceptIntf: IMEException; var handled: boolean);
begin
handled := false;
end;
The above is a trick to force madexcept to work also with handled exceptions, of course it is risky to use it in production...

Occasional EAccessViolation in VCL/comctl32.dll/USER32.dll/GDI32.dll after receiving WM_PAINT

I need some suggestions for debugging a crash in a Delphi XE2 application. I've never seen the crash myself - indeed it occurs very rarely and is not reproducible on demand.
We do though have a set of 10 crash reports from MadExcept. These show that the main thread was processing a WM_PAINT message at the time in the list view on the main form. The call stack in each case shows no references to my own code, just VCL code and functions in comctl32.dll, ntdll.dll and USER32.dll.
The list view in question is TColorListView, which derives from TCustomListView, and handles the OnCustomDrawItem and OnDeletion events. But as I said, none of my TColorListView code is on the call stack when the crash occurs.
The actual location of the crash in each case varies, but the sequence of calls (earlier to later) leading up to it is always:
KiUserCallbackDispatcher
RtlAnsiStringToUnicodeString
StdWndProc
TWinControl.MainWndProc
TCustomListView.WndProc
TWinControl.WndProc
TControl.WndProc
TCustomListView.WMPaint
TWinControl.WMPaint
TWinControl.WMPaint
TWinControl.DefaultHandler
CallWindowProcA
TControl.WndProc
After that it goes into one of StdWndProc/SendMessageW/TControl.Perform, and from there the path is different each time. Eventually it ends up in one of comctl32.dll, USER32.dll, GDI32.dll or just TControl.WndProc and raises an EAccessViolation. Sadly I have no information about what the user was trying to do at the time because the user didn't fill in that part of the bug report.
Can you suggest any 'psychic debugging' techniques that I can use to try to pin down the cause of this crash (and thus fix it)?
Update to answer the questions in the comments below:
procedure TColorListView.HandleCustomDrawItem(aSender: TCustomListView; aItem: TListItem;
aState: TCustomDrawState; var aDefaultDraw: Boolean);
begin
Canvas.Font.Color := ItemColors[aItem.Index];
end;
In (just) one of the crash reports, it appears to go off into TListItem.GetIndex and crashes several stack frames further on. That's probably a red herring though.
What's the 'Perform'ed message? Sorry, I don't know. MadExcept doesn't give me method argument values; just the method names.
31 May
Although I'd prefer to find the fault just from the information I have, I'd also welcome suggestions for any new diagnostics I could add to the program so that if this crash occurs again after the next release I will have more to go on. I'm at a loss though because at the point of the crash none of the code I can modify is even on the call stack.
13 June
I've added to the MadExcept report a line that tells me what state the application was in when the exception occurred - Starting/Active/Idle/ModalDlg/Terminated. (Thanks to Chris Thornton for his comment suggesting this.) I think there is reasonable chance that the exception is happening during shutdown. Unfortunately it won't be until 2014 before we release the new version and have the possibility of getting back bug reports with the new diagnostics.
This is just a guess but maybe you are facing same problem that I have(look similar).
My problem was in destroying WinAPI windows in different thread than they was created.
Windows will not destroy window in this case and return error, but some Delphi components just ignore that error, so you end up with hanging window that have WndProc pointed to junk memory(it will be freed by Delphi on component destruction, but window will stay behind).
And when this window will try to process any message it will go to WndProc(which is undefined) and result in random callstack with AV.
So make sure you are creating and deleting windows in same thread (pay special attention to TTimer, they also create windows)
Interesting read here. Maybe something similar is happening?
Wouldn't hurt to check for canvas <> nil
Access violation while the program was idle - not trace information to track down the bug
First of all, to deBUG access violation errors you have to find variables (memory pointers) that are referencing areas not owned memory by your process.
Mostly non-initialized variables causes the problem.
So my suggestion would be to change the piece the following way
procedure TColorListView.HandleCustomDrawItem(aSender: TCustomListView; aItem: TListItem;
aState: TCustomDrawState; var aDefaultDraw: boolean);
begin
if Canvas = nil then
.... ; // a breakpoint here
if ItemColors = nil then
.... ; // a breakpoint here
if aItem = nil then
.... ; // a breakpoint here
Canvas.Font.Color := ItemColors[aItem.Index];
end;
I hope that this will show you which variable is not passed as expected.
My guess is for aItem.

Disable exception handling and let windows catch it?

I want to disable the exception catching by Delphi and let Windows catch it - making it produce a window like "AppName crashed. Debug , Send", add this to Application events, create a memory dump and so on.
By default, Delphi catches all the exception in TApplication.Run procedure... How can I avoid that without modifying Forms.pas?
You could add an OnException handler that re-raised the exception:
class procedure TMainForm.OnException(Sender: TObject; E: Exception);
begin
raise Exception(AcquireExceptionObject);
end;
initialization
Application.OnException := TMainForm.OnException;
I'm not sure why you would want to do this at all though. It's more normal to use a tool like madExcept or EurekaLog to show an error dialog that yields much more helpful information than the system dialog.
You can set JITEnable to '1' or higher (default is '0'). With '1', non native exceptions, with higher than '1', all exceptions will be handled by JIT or WER (depending on the system).
This may not be what you want though. With this solution any qualifying exception will be passed to the OS, it doesn't matter if they're handled in code or not. Clarification (run outside the debugger):
procedure TForm1.Button1Click(Sender: TObject);
begin
raise EAccessViolation.Create('access denied');
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
try
PInteger(0)^ := 0;
except
end;
end;
initialization
JITEnable := 1;
The first example is a native exception, it will be handled by the application exception handling mechanism when JITEnable is 1. But the second example will trigger JIT/WER.
Add your own handler. Application.OnException is probably what you want. Better than leaving it up to windows as well, as you get different behaviours depending on the environment. For instance if windows error reporting is on, it will ask the user if they want to send an error report to MS.
Like Mr Heffernan I recommend you look at something like EurekaLog.
AS. I agree with voices above that this wish is rather strange.
I also agree that practically hooking in TApplication.OnException would probably be enough ("if it looks like a duck...")
However if you truly want to make RTL oblivious to exceptions, there are ways too.
Exception handlers are plugin to low-level RTL, just like heap management, etc.
You can look at KOL (Key Objects Library).
In Delphi 5 times i managed to make 2KB-size DLL.
That required absense of many usualyl taken "for granted" features. Exception were among them.
To enable Exceptions in KOL's system RTL replacement, you had to make some $DEFINE's, and then the code to add exceptions support to IDE was unlocked.
I believe you can still get that modularized RTL version and grep for that $IfDef and see which code is replaced with which.
I believe there is fair chance you can undo that and make Windows avoid calling Delphi RTL over Exceptions.
I don't remember details, but i believe Delphi RTL Exception handler is just registered in Windows core as a callback. And you probably can de-register it (register nil callback).
I believe you can find it in stock RTL, but KOL's modularised RTL would just make it easier to search.

Raise exception in another thread

How do I raise an exception in another thread in Delphi?
I have thread 1 and thread 2 and I want to raise an exception in thread 1 and to catch it in thread 2.
EDIT
I can see now that my initial explanation is confusing. What I want to do is to INITIATE an exception raising in thread 2 from thread 1. So exception is raised and caught in thread 2, but this process is controlled from thread 1.
Let's say that I have a main thread which creates a worker thread. I need a mechanism to stop the worker thread from the main thread gracefully, but because of some reasons, which are irrelevant here I cannot use TThread.Terminate/Terminated pattern. So I thought that if I could initiate (inject?) an exceptin raising in the worker thread from the main thread, then that could be used as a stopping signal.
You can inspire from Rob's answer here Delphi thread exception mechanism or from this Embarcadero article.
Here's a sample piece of code that raises an exception into an other thread. It uses SuspendThread to stop the thread, GetThreadContext to read the thread's registers, alters EIP (the instruction pointer), uses SetThreadContext and then ResumeThread to restart the thread. It works!
UKilThread unit
Nicely packaged for reuse unit that provides the AbortThread() routine:
unit UKillThread;
interface
uses Classes, Windows, SysUtils;
procedure AbortThread(const Th: TThread);
implementation
// Exception to be raized on thread abort.
type EThreadAbort = class(EAbort);
// Procedure to raize the exception. Needs to be a simple, parameterless procedure
// to simplify pointing the thread to this routine.
procedure RaizeThreadAbort;
begin
raise EThreadAbort.Create('Thread was aborted using AbortThread()');
end;
procedure AbortThread(const Th: TThread);
const AlignAt = SizeOf(DWORD); // Undocumented; Apparently the memory used for _CONTEXT needs to be aligned on DWORD boundary
var Block:array[0..SizeOf(_CONTEXT)+512] of Byte; // The _CONTEXT structure is probably larger then what Delphi thinks it should be. Unless I provide enough padding space, GetThreadContext fails
ThContext: PContext;
begin
SuspendThread(Th.Handle);
ZeroMemory(#Block, SizeOf(Block));
ThContext := PContext(((Integer(#Block) + AlignAt - 1) div AlignAt) * AlignAt);
ThContext.ContextFlags := CONTEXT_FULL;
if not GetThreadContext(Th.Handle, ThContext^) then
RaiseLastOSError;
ThContext.Eip := Cardinal(#RaizeThreadAbort); // Change EIP so we can redirect the thread to our error-raizing routine
SetThreadContext(Th.Handle, ThContext^);
ResumeThread(Th.Handle);
end;
end.
Demo project
Here's how to use AbortThread:
program Project23;
{$APPTYPE CONSOLE}
uses
SysUtils,
Classes,
Windows,
UKillThread;
var Th: TThread;
type
TTestThread = class(TThread)
public
procedure Execute;override;
end;
{ TTestTrehad }
procedure TTestThread.Execute;
var N: Integer;
begin
try
N := 1;
while not Terminated do
begin
WriteLn(N);
Inc(N);
Sleep(1000);
end;
except on E:Exception do
WriteLn(E.ClassName + ' / ' + E.Message);
end;
end;
begin
Th := TTestThread.Create(False);
WriteLn('Press ENTER to raize exception in Thread');
ReadLn;
AbortThread(Th);
WriteLn('Press ENTER to exit');
ReadLn;
end.
Disclaimer
Please make sure you understand what this code does before you actually use it. This is by no means a replacement for proper Terminate - Terminated logic (that is, cooperative thread shut-down), but it's a better alternative to TerminateThread(). This has been modeled after the .NET Thread.Abort() method. I have no idea how the actual .NET method was implemented but none the less read up on that because the potential problems of using this code are similar:
The method doesn't actually terminate the thread, it raises an EAbort -derived exception in the context of the thread. The thread's code might catch the exception. That's very unlikely because EAbort exceptions are not supposed to be handled.
The method might stop the thread at any time. It might stop the thread while it's handling a finally section or while setting up a new exception frame. Even if your thread uses proper try-finally blocks, it might cause memory or resource leaks if the exception is raised after a resource has been allocated but before the resource has been assigned to a variable.
The code might cause deadlocks if the thread is interrupted immediately after EnterCriticalSection and just before the try-finally that normally follows. The MSDN page for EnterCriticalSection mentions: "If a thread terminates while it has ownership of a critical section, the state of the critical section is undefined.". This came as a surprise to me, I'd intuitively expect the critical section to be "released" when the owning thread terminates, but apparently that's not so.
The way to signal your thread to cancel is to arrange for your thread to check the status of a boolean flag and respond to that. The flag is set by the controlling thread and then the worker thread does what is needed to abort. You must check the status of the flag regularly.
Such a solution would be a re-implementation of the built-in Terminated method, but you state that you can't use Terminated. I think this leaves you in a bind. Threads can't safely and reliably be terminated by force so you need a co-operative method.
I strongly advise you to re-work your architecture so that use of Terminated is viable.
That is impossible, and Delphi does not matter. Exception information reside in stack, and stack belongs to thread (each thread has its own stack). Consequently you must raise and handle exception in the same thread.
#Max: if you execute a code in a different thread (using Synchronize or Queue methods) then the exception raised by the code can only be caught in the same (different) thread.
It is possible that a thread A raises & catches the exception, passes the exception object to a thread B and the thread B re-raises the exception, but it is absolutely impossible for a thread B to catch the exception raised by thread A because each thread has its own stack.
Extending and perhaps simplifying #David's answer: I add public error message and errorState properties to my thread class. If an exception occurs in the thread, I handle or eat it (depending on what's appropriate) and set the error properties with the exception info etc.
The Main thread checks the thread class error properties in the thread.onTerminate event (which runs in main thread) and notifies frontEnd/User if necessary, showing exception exception info returned from the thread.
HTH
Make all your threads "message" processing threads, and have the failure to "process" a message just generate an exception-like message to be passed onto any other threads/main thread that need to know. I use this architecture in my distributed multi-threaded application framework here.

Resources