Can you Catch an Exception after the main application unit has ended? - delphi

In one of our application im getting an exception that i can not seem to find or trap.
...
Application.CreateForm(TFrmMain, FrmMain);
outputdebugstring(pansichar('Application Run')); //this is printed
Application.Run;
outputdebugstring(pansichar('Application Run After')); //this is printed
end.
<--- The Exception seems to be here
The Event log shows
> ODS: Application Run
> //Various Application Messages
> ODS: Application Run After
> First Change Exception at $xxxxxxxx. ...etc
All i can think of is it is the finalization code of one of the units.
(Delphi 7)

Try installing MadExcept - it should catch the exception and give you a stack-trace.
It helped me when I had a similar issue.

Here's two things you can try:
1) Quick and easy is to to hit 'F7' on the final 'end.'. This will step you into the other finalization blocks.
2) Try overriding the Application.OnException Event.

The SysUtils unit actually sets up the default ErrorProc and ExceptProc procedures in its initialization section, and undoes them in its finalization section, so often in this situation it's worth ensuring that SysUtils is the very first unit in the uses clause in your dpr, so then it will be the last one finalised. Might be enough to get you some meaningful data about what is going wrong.

Finalization exceptions are tricky. Even if you put SysUtls first in your project file, your application object may already be gone, which means your global exception handler is gone too. MadExcept may work for this though.
Another solution is to put a Try / Except block in each of your unit finalization sections, and then handle the exceptions there.
What is your objective? Do you want to suppress the exception or debug it? Debugging it can be done by stepping through them with F7 as Zartog suggested. If you discover which unit has the exception in finalization then you might try placing it in a different order in the uses clause it is called from.
Good luck!

Related

Startup error during main form creation

Delphi XE5/32, on Windows10/64, generating Win32 VCL executable.
I am getting intermittent Access Violation errors that are associated with form creation. This error has also been seen, rarely, by some end-users (I'm currently in small-scale trials, with a test group of about 20 users).
This has been going on for months and until recently my attempts to find the problem were frustrated by the fact that it was so hard to reproduce. However, I have now finally been able to establish an environment that reproduces the error quite reliably. Bizzarely, I have discovered it is triggered by certain emails being displayed in my GMail account, in Chrome browser. The emails that cause the problem are completely consistent - see the video in https://www.devexpress.com/Support/Center/Question/Details/T395896. (I initially posted this query to the DevExpress support forum because I suspected one of their components was the cause, however now I doubt this).
I have now disabled my splash screen temporarily, and changed my previous auto-create datamodules to be created in the main form's OnCreate. The DPR is now, very simply:
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.Title := 'Topshare V3';
Application.CreateForm(TMainForm, MainForm);
Application.Run;
end.
That is, nothing happens prior to the CreateForm for the program's main form.
When the error is happening, the program either hangs silently during Application.CreateForm(TMainForm, MainForm), and before the main form's OnCreate is invoked; or it terminates before OnCreate, and invokes the form's OnDestroy. So the problem is occurring during the parsing of the DFM.
If I step the program in debug mode within the IDE when the error is active, there are several AVs raised during Application.CreateForm(TMainForm, MainForm). These are only apparent from the IDE so are, presumably, within try..except blocks. If I click Break on the first of these, the Call Stack is usually something like:
System.SysGetMem(???)
:00405423 SysGetMem + $43
System.Classes.TReader.ReadComponent(nil)
System.Classes.TReader.ReadDataInner(???)
System.Classes.TReader.ReadData($7BCCD90)
System.Classes.TComponent.ReadState(???)
Vcl.Controls.TControl.ReadState($9C6F098)
Vcl.Controls.TWinControl.ReadState($9C6F098)
:00aa0bcd TcxCustomGrid.ReadState + $29
System.Classes.TReader.ReadDataInner(???)
System.Classes.TReader.ReadData($7BF4230)
System.Classes.TComponent.ReadState(???)
Vcl.Controls.TControl.ReadState($9C6F098)
Vcl.Controls.TWinControl.ReadState($9C6F098)
System.Classes.TReader.ReadComponent(nil)
System.Classes.TReader.ReadDataInner(???)
System.Classes.TReader.ReadData($7BF3F50)
System.Classes.TComponent.ReadState(???)
Vcl.Controls.TControl.ReadState($9C6F098)
Vcl.Controls.TWinControl.ReadState($9C6F098)
System.Classes.TReader.ReadComponent(nil)
System.Classes.TReader.ReadDataInner(???)
System.Classes.TReader.ReadData($9B9C7A0)
System.Classes.TComponent.ReadState(???)
Vcl.Controls.TControl.ReadState($9C6F098)
Vcl.Controls.TWinControl.ReadState($9C6F098)
Vcl.Forms.TCustomForm.ReadState($9C6F098)
System.Classes.TReader.ReadRootComponent($9B9C7A0)
System.Classes.TStream.ReadComponent($9B9C7A0)
System.Classes.InternalReadComponentRes(???,???,$9B9C7A0)
System.Classes.InitComponent(TMainForm)
System.Classes.InitInheritedComponent($9B9C7A0,TForm)
Vcl.Forms.TCustomForm.Create(???)
Vcl.Forms.TApplication.CreateForm(???,(no value))
TopshareV3.TopshareV3
The apparent involvement of SysGetMem lead me to this Question: Delphi XE5 Acces Violation on app start
Accordingly I have enabled both Range Checking and Overflow Checking, but this does not help.
There must be something wrong with the DFM.
One aspect is that the main form inherits from an ancestor form type. The ancestor form has no components, just some methods. The ancestor form's source code does not include the default global variable declaration. So, the main form's form declaration is:
TMainForm = class(TABase)
and the DFM contains:
inherited MainForm: TMainForm
The form contains several nested frames, and also uses several ActionManagers, ActionToolbars, an ActionMainMenubar, a PopupActionbar, and a dxSkinController.
Can anyone shed any further light on what to look for, or how to proceed further??
EDIT: The call stack shown above is After the first AV. But I have already done the tracing you suggest. I put a breakpoint in System.Classes at line #10169, in TReader.ReadComponent. I then add watches on "Parent.name" and "CompName". Then, starting again in the IDE, I see the various main form components being created.
Previously, when the datamodules were being created first, I would see a number of components created, but the AV would always happen after hitting the breakpoint with watches showing the first View of the first cxGrid (DevExpress). If I added an extra grid to the form (and on the first panel to be created), without any properties being set, then the new grid would appear to trigger the AV. In other words, it seemed like the cxGrid was the problem - hence my contact with DevExpress support.
But postponing the creation of the datamodules, and eliminating my splash screen, has changed things (although the AV is still occurring). Now, it progresses well beyond the first grid; and, although a cxGrid still seems to be involved, I'm not sure that's relevant now (I have a lot of grids on the main form).
EDIT: Running in the IDE, there are 3 AVs (if I click Continue after each) - then the program hangs before my code in OnCreate executes: the first is $C0000005 with message 'access violation at 0x0040541d: read of address 0x002d001c'; and, twice, $C0000005 with message 'access violation at 0x00a8107a: read of address 0x00000068'.
EDIT: My initial breakpoint at Classes # 10169 now executes a few dozen times as the form components from the DFM are processed. On the now-critical component (still a cxGrid view), execution steps from Classes #10169 (in Treader.ReadComponent), to CreateComponent #10114, to Result.create #10129. From here there is a loop (or recursion) that includes an assembler block beginning at System #16752, and empty Tobject.Create at #15511. A breakpoint at System #15511 executes 29 times. Then, the 30th time through, the AV occurs at System #16757, CALL DWORD PTR [EAX] + VMTOFFSET TObject.NewInstance
EDIT: When stepping through execution when there's no error condition, things seem essentially the same as when there is: that is, the same sequence of calls. The same sequence described in the para above seems to be followed - except for no AV on the 30th pass or subsequently.
I have narrowed the problem down to DevExpress's dxSpreadSheetCore unit. If I include that in any Uses clause, the error is displayed; if I omit it, no error. I have submitted the problem to DevExpress, although I was not able to simplify my application enough to also give them a useful demonstration of the error.
My assumption, based on comments here, is that something in the initialization section of dxSpreadSheetCore (or in its dependant units) is causing heap corruption.

MadExcept + try/finally block?

I have some delphi code, kind of like this:
try
//some code
//occasionally throws an exception here, for example an EIndexOutOfRangeException
//more code...should get skipped if exception is thrown
finally
// there may or may not be any important cleanup code here
end;
The exception in this case is not something that needs handling beyond breaking out of the try block. So, before mad-except was added to the project for error troubleshooting, this code was "working". But now I'm getting bug reports because MadExcept is reporting the uncaught exception.
Related question, MadExcept triggers on try finally indicates the behavior of MadExcept breaking in such circumstance is "expected" because the exception isn't "handled".
I would like some clarification about what my options are as far ways to prevent a mad-except dialog from popping up when this code runs, regardless of whether there's an internal exception being thrown and ignored.
So I'm correct in thinking there's no switch to disable MadExcept from breaking on unhanded exceptions in a try/finally block? And I'm going to need to explictly "catch" the exception even if I wish to ignore it?
Should I be doing something like this (ignore any exception):
try
//some code
//sometimes throws EIndexOutOfRangeException here
//more code...should get skipped if exception is thrown
except do begin end;
end;
or perhaps (ignore a very specific exception):
try
//some code
//sometimes throws EIndexOutOfRangeException here
//more code...should get skipped if exception is thrown
except on E : EIndexOutOfRangeException do begin end;
end;
or maybe it needs to be:
try
try
//some code
//sometimes throws EIndexOutOfRangeException here
//more code...should get skipped if exception is thrown
except on E : EIndexOutOfRangeException do begin end;
finally
// some cleanup code
end;
If all three of those are valid solutions, should I prefer one over the other for any reason?
So I'm correct in thinking there's no switch to disable MadExcept from breaking on unhanded exceptions in a try/finally block?
Yes. try/finally is not exception handling; it's guaranteed cleanup, whether or not an exception occurs. As such, try/finally blocks are completely irrelevant to exception handling tools such as MadExcept.
And I'm going to need to explicitly "catch" the exception even if I wish to ignore it?
Yes. That's how exceptions work. They work their way down the stack until they find a handler that catches them. If no such handler exists, the OS interprets it as a crash and terminates the program. Delphi's TApplication object installs a handler very close to the bottom of the call stack so that your program won't crash, and MadExcept hooks this so that if an exception reaches this point, a report will be generated.
If you want to ignore an exception, yes, you do need to catch it, because what you are doing is formally "handling the exception by catching it at this point in the stack unwinding and ignoring it." That part about "catching it at this point in the stack unwinding" is important, since it means that the stack unwinding halts at that point and the program resumes normal execution. If you just ignored it, (ie. did nothing about it in your code, including not installing an exception handler,) it would continue to unwind the stack all the way to the default handler, whether or not you had MadExcept installed.
So yeah, in this case, example #2 is the correct course of action. Example #3 would be valid too, if you have cleanup code that needs to be performed at this point. But example #1 should never be done under any circumstances because it means you might end up ignoring an exception that you were not anticipating, and then you end up with corruption in your program and you never become aware of it.
It seems to me that you have a fundamental mis-understanding about what finally means.
A finally block does not influence the propagation of an exception. It just ensures that the finally block will execute, even if an exception has been raised, or the normal execution flow has been modified by exit, break etc.
Take the try/finally out and madExcept will still report that the program raised an exception that was not handled.
There are ways to tell madExcept to ignore certain exceptions. For instance some exceptions should be silent. The canonical example of such is EAbort. You would use RegisterExceptionHandler to customise how unhandled exceptions are treated. Although, as I will explain, I doubt this to be the solution for your problem.
What you need to do next is forget about madExcept. You need to work out what to do about this exception. Do you want to handle it here, or do you need to let the exception propagate? Only you can really know that. But madExcept is not the driver here. What must drive your decision is the correct execution of your program. Should the exception be handled or not, to make your program behave correctly? You must get that right first, and then worry about madExcept.
If you need to handle it here, then handle it selectively. Don't catch all exceptions. That's an absolute no-no. But if you handle it here, ask yourself if that is sensible. The code failed to perform some action. Is there some subsequent code that relies on that action succeeding? By handling the error, and ignoring it as you propose, you are forcing all subsequent code to be ambivalent about the success or failure of this action. That seems highly dubious to me.
Now, the exception is EIndexOutOfRangeException. That means you wrote something like A[i] where the value of i is invalid. I cannot think of a scenario where that would be acceptable. So it looks to me that your program contains an error and is simply using an invalid index. You should fix that error properly by not accessing out of bounds. Don't suppress the exception, stop it being raised.
Another way to look at this. How can you tell the difference between your current situation, and that which would arise from writing A[-i] instead of A[i]? Suppressing the exception means that you cannot detect such egregious errors as this.
The bottom line, so far as I can tell, is that madExcept is reporting an error in your code. You should regard madExcept as your friend and listen to what it says. It is telling you that you have a defect in your code that should be fixed.

What may and don't I may do in FormCreate()?

I think this must be a FAQ, but googling hasn't really helped.
What may I do - and may do not - in FormCreate()?
I am wondering if all of the form's child controls are fully created and available for access, etc.
The reason I ask is that I stumbled over an old project where my FormCreate() simply consists of
Sleep(1000);
PostMessage(Handle, UM_PROGRAM_START, 0, 0);
It seems that I want to "wait a bit" and then do some initialization "when things have settled down" ...
Surely I had a reason for it at the time(?), but, in the absence of an enlightening comment I am unable to recall why I felt that to be necessary.
Can anyone state, or reference a link which states, any restrictions on what one may do in FormCreate()?
[Update] I think thta DavidHefferman found the solution when he wrote "the application starts pumping messages. That happens when you call Application.Run in your .dpr file".
I guess that I wasn't concerned about a single form. For instance, my main form wants to do somethign with my config/options form at start up, so obviously would have to wait until it is created.
Here's a typical .DPR from one of my projects ...
Application.Initialize;
Application.CreateForm(TGlobal, Global);
Application.MainFormOnTaskbar := True;
Application.CreateForm(TMainForm, MainForm);
Application.CreateForm(TLoginForm, LoginForm);
Application.CreateForm(TConfigurationForm, ConfigurationForm);
//[snip] a bunch of other forms ...
Application.Run();
So, it makes sense for my app's mainForm.CreateForm() to send a UM_APPLICATION_START to itself which it won't process until all forms are created & initialized (or, I could just call the fn() which the message triggers from my .DPR after Application.Run() is called; but I prefer the message as it is more obvious - I rarely look at my .DPR files).
There's no definitive documentation giving the list of all the things you can do and connot do in a form's OnCreate.
As for whether or not the .dfm file has been processed and all the form's owned components created, yes they have.
I wouldn't place much store in the code you have found. Calling Sleep during start up, to make the main thread wait, is absolutely not good practice. If the code wanted to wait for another thread it could block for that thread, or wait to get a message from that thread. This just looks like code that got put in by someone who didn't understand what he/she was doing. And the code never got removed.
The other line of code is reasonable:
PostMessage(Handle, UM_PROGRAM_START, 0, 0);
Because this message is posted, it won't get processed until the application starts pumping messages. That happens when you call Application.Run in your .dpr file. Which means that everything related to the creation of you main form happens before that message is pulled off the queue.
I wouldn't put to much initialization code in FormCreate, instead I would place it into a separate function, like
fm := TForm.Create;
fm.Init;
The problem is, an exception thrown in the FormCreate() procedure is not re-thrown (there is only a MessageBox). That means, your code keeps running, although the form is not initialized correctly.
You may do whatever you want in the FormCreate. But there is no message handler to play with, that's all. In general I would create dependent objects in the FormCreate and free them in the FormDestroy. I would also try to avoid time consuming initialization routines.

Exception handling without interruption

Some part of my source code are nested inside try statements in order to handle some run time errors, at the same time each and every line must be tried to execute even if the previous line is not executed because of run time error .
currently my code looks like this
try
try
//statement1
except
end;
try
//statement2
except
end;
try
//statement3
except
end;
finally
//something
end;
I am very sure going in the wrong way ,even if the final out put is working well, I have to do this for dozens of lines.
Is there any better way to implement this
If you want each statement to execute then you have to write it the way you have done. Note that in that case may not need the try/finally because you are swallowing all the exceptions.
However, the code does look a bit odd to me. I wonder if you really need each and every statement to execute. Normally you would write:
try
statement1;
statement2;
statement3;
except
//handle exceptions
end;
Then, if there is an exception in statement1, the other two lines will not execute.
However, it would be even more common not to handle exceptions at all and let them float up to some higher level handler. If you are making routine logic decisions using exceptions then that would be considered bad practice.
I think it would be helpful for you to publish some of your code that handles the exceptions and some details of what exceptions you are expecting to occur. Then we could give you some more specific advice.

Need a way to periodically log the call stack/stack trace for EVERY method/procedure/function called

I'm working on a very large application where periodically I'd like to log the ENTIRE call stack up until the current execution point (not on an exception). The idea here is that I want a map of the exact code path that led me to the point that I am. I have been working with madExcept, tooled around with jclDebug and while I can get some of the call stack, I can't seem to get EVERY method/procedure/function call that is made in the application to show up in the log.
I've got stack frames turned on, debug info, etc enabled on the project. I even tried turning on stack frames on individual methods that weren't getting included in the call stack to no avail.
Is what I'm trying to do even possible? I'm really trying to avoid having to add logging code all over our millions of lines of code in order to log the code path.
I use JCLDebug from the JCL to do just this.
The following will get the call stack for the current location and return it as a string.
function GetCurrentStack: string;
var
stackList: TJclStackInfoList; //JclDebug.pas
sl: TStringList;
begin
stackList := JclCreateStackList(False, 0, Caller(0, False));
sl := TStringList.Create;
stackList.AddToStrings(sl, True, True, True, True);
Result := sl.Text;
sl.Free;
stacklist.Free;
end;
To make this work as expected, you must enable one of supported ways for Debug Information for JCL such as:
Turbo Debugger Information
JDBG Files (Generated from the MAP Files)
JBDG Files Inserted into the EXE.
I recently switched between JDBG files inserted into the EXE to just shipping the external JDBG files as it was easier to maintain.
There are also routines that are useful for tracing such as:
function ProcByLevel(Level : Integer) : String;
This allows you to determine the current method/procedure name looking back in the call stack "N" number of levels.
You can use madExcept - it includes a method named GetThreadStackTrace. MadExcept is free for non-commercial use and definitely worth the price otherwise.
From the responses and comments to other answers it sounds like you need a CALL LOG, not a CALL STACK. The information you want simply isn't present in a call stack.
In which case I suggest you investigate a tool such as SmartInspect or AQ Time. Of the two I think SmartInspect is most likely to be relevant. AQ Time is more of an interactive profiling tool, where-as SmartInspect has facilities specifically for remote inspection.
When you return from a method it is removed from the stack. So presumably your Partial call stack is every method that has not yet returned?
e.g.
DoSomething
begin
MiniSubMethod
DomeSomethingMore
begin
InnerDoSomething
begin
ShowCallStack
end
end
end
I would think in this situation the call stack would be
InnerDoSomething
DoSomethingMore
DoSomething
MiniSubMethod is no longer on the stack as it returned before DoSomethingMore was called.
I think FastMM4 includes a Stack Trace so you could try that.
You would definitely need some kind of logging/stack trace instead of just the call stack.
If it is a complete trace you want, I believe a tool like SmartInspect could take you a long way.
It would require you to add logging to your code but for what you need, that would be unavoidable.
Some of its highlights
Monitor in Real-Time
High-performance live logging via TCP or named-pipes to the Console
Watch and Monitor Resources
Track variable values, session data and other application resources.
Rich Logging & Tracing
Track messages, exceptions, objects, files, database results & more.

Resources