Delphi 7 exception not caught - delphi

I have some really complicated legacy code I've been working on that crashes when collecting big chunks of data. I've been unable to find the exact reason for the crashes and am trying different ways to solve it or at least recover nicely. The last thing I did was enclose the crashing code in a
try
...
except
cleanup();
end;
just to make it behave. But the cleanup never gets done. Under what circumstances does an exception not get caught? This might be due to some memory overflow or something since the app is collecting quite a bit of data.
Oh and the exception I got before adding the try was "Access violation" (what else?) and the CPU window points to very low addresses. Any ideas or pointers would be much appreciated!

"Very low address" probably means that somebody tried to call a virtual method on an object that was not really there (i.e. was 'nil'). For example:
TStringList(nil).Clear;
The first part is very mysterious, though. I have no idea how that can happen.
I think you should try to catch that exception with madExcept. It has never failed me yet. (Disclaimer: I am not using D7.)

A trashed stack or a stack overflow can both cause irreparable harm to the structures on the stack that structured exception handling (SEH) in Windows uses to find the actual exception handlers.
If you have a buffer overflow in a buffer on the stack (e.g. a static array as a local variable but written beyond its end), and overwrite an exception record, then you can overwrite the "next" pointer, which points at the next exception record on the stack. If the pointer gets clobbered, there's nothing the OS can do to find the next exception handler and eventually reach your catch-all one.
Stack overflows are different: they can prevent calling functions at all, since every function call requires at least one dword of stack space for the return address.

you have a number of good answers. the wildest problems i've had to chase come from stack corruption issues like barry mentioned. i've seen stuff happen with the project's "Memory sizes" section on the linker page. i might be superstitious but it seemed like larger wasn't necessarily better. you might consider using the enhanced memory manager FastMM4--it's free & very helpful.
http://sourceforge.net/projects/fastmm/
i've used it with d7 and found some access to stale pointers and other evil things.
you may also wish to create a way to track valid objects and or instrument the code in other ways to have the code checking itself as it works.
when i'm seeing access to addresses like 0x00001000 or less, i think of access to a nil pointer. myStringList:=nil; myStringList.Clear;
when i'm seeing access to other addresses with much larger numbers, i think of stale pointers.
when things are strangely unstable & stack traces are proving to be nonsense and/or wildly varying, i know i have stack issues. one time it's in Controls.pas; next time it's in mmsys.pas, etc.
using the wrong calling convention to a DLL can really mess up your stack as well. this is because of the parameter passing/releasing when calling/returning from the DLL.
MadExcept will be helpful in finding the source of this, even if it shows nonsense...you'll win either way because you'll know where the problem is occurring or you'll know you have a stack issue.
is there any testing framework you can put on it to exercise it? i've found that to be very powerful because it makes it entirely repeatable.
i've fixed some pretty ugly problems this way.

I'll leave the reasons why the except might not work to Barry...
But I strongly suggest a simple strategy to narrow down the area where it happens.
Cut the big chunk in smaller parts surrounded by
try
OutputDebugString('entering part abc');
... // part abc code here
except
OutputDebugString('horror in part abc');
raise;
end;
...
try
OutputDebugString('entering in part xyz');
... // part xyz code here
except
OutputDebugString('horror in part xyz');
raise;
end;
and run your code with DebugView on the side... (works for apps without GUI as well like services).
You'll see which part is executed and if the exceptions are caught there.

I used to get this strange behabiour when calling some COM object that used a safecall calling convention. This object/method may raise an EOleException, not trapped by the usual try/except on the client code.
You should trap an EOleException and the handle it properly.
try
...
except
on E: EOleException do
...
end;
I don't know if it is the problem you are facing. But if it is, i recommend you to take a look at Implement error handling correctly, a very clarifiyng post about exception handling in delphi.
You can also enable your IDE Debug Options to stop on delhi exceptions e monitor the stack trace.

Is this perhaps a DLL or a COM object? If so, it is possible that the FPUExcpetion mask is being set by the host application to something different than Delphi is used to. An overflow, by default in Delphi produces an exception, but the FPUExcpetionmask can be set so that it doesn't, and the value is set to NAN. See the math.pas unit for more information on FPUExceptionmask

I've gotten exceptions in the initialization and finalization blocks of my code which madExcept doesn't even seem to even catch. This might occur if you're referencing external DLL's inside of that try block. I'm not certain of the reason.
Actually (and thanks to #Gung for informing me of the worthlessness of my ancient answer), I read this recently in the ancient O'Reilly Delphi Tome. You should put SysUtils as the first (or second after your non-standard memory manager unit) in your main form's DPR so that it's resident in memory with all it's Exception Catching goodness. Otherwise, if it's loaded from some other unit, it will be unloaded with that unit too and you can kiss built in exception handling goodbye.

Related

How to debug the CPU tab on Delphi?

I'm using Delphi 11. Sometimes an exception happens, and instead of Delphi going to the unit that threw the exception, it goes to this CPU screen, and I don't know what to do with it.
What can I do in such situations ?
This kind of screen typically means there is no code located at the memory address where the CPU tried to execute code from. Which most likely means that a class method was called on an object via an invalid but not nil pointer, or a function was called via a similarly invalid function pointer.
You won't be able to debug the location where the exception was raised from, since it is an invalid memory address to begin with. But you should still have access to the Call Stack trace of function calls that led up to the exception. So, just walk back through the Call Stack until you reenter valid code, and then debug from there to find the invalid pointer.
There might be better answers but I think you might look at EurekaLog or madExcept. Either works great. Never quite understood why this is not built-in to Delphi.

How to identify where an exception is being thrown during finalization in a Delphi application?

I am working onsite with a client, and I am trying to help them with a complicated problem. I am hoping that there is a tool or feature in Delphi that we can use to peer into the inner workings to help us locate the problem.
Here is a high level overview of the problem we are dealing with. This is a commercial application that is currently deployed in Delphi 5. Over the past year the application has been migrated to Delphi XE. The migration is almost complete, but there are some serious errors that are being encountered.
The application itself is very large, with hundreds of units and many third-party and custom components. In one specific situation that we are encountering, the main form is created and then the application is terminated before that main form is displayed. The result is a crash that occurs during this termination, as units are being finalized.
The debugger is breaking in the RaiseException function of kernel32, which is called by NotifyNonDelphiException. We tried to set a non-breaking breakpoint that logs the call stack from within NotifyNonDelphiException, but that does not give us anything useful. The call stack contains only methods that handled the exception, and that is RtlRaiseStatus and KUserExceptionDispatcher.
How do we identify the code that throws the original exception that is being handled by NotifyNonDelphiException?
edit: Here are two images captured following one instance of the exception. The first one is the raised exception, and the second depicts the CPU window after the exception dialog box is closed.
New Edit:
It has been more than a week since I posted this question, and I am impressed with the various answers. Some of the comments to the initial question were most valuable, but some of the answers themselves are very informative.
My visit to that client is over, and I will ask them to consider the answers that have been posted here. While we were not able to track down the actual source of the error, the cause of the error was more than obvious. Many years of tweeking the user interface without a serious refactoring left the application with an unstable log in process. When the log in was canceled by the user, the main form was in a partial state of initialization. When this process was not permitted to run its course, which was what happened when the user aborted log in, very serious finalization issues were present.
The company has purchased AQTime Pro to help identify future problems, but a refactoring of the login process is called for, and will solve the problem in the long run.
At one point I considered removing this question, but I have opted to keep it posted, since I believe that others will find the many excellent suggestions that were posted informative.
For the time being, I am accepting #Deltics answer, since I hate leaving a question without an answer. However, I ask viewers of this question to also consider all of the other answers and comments, and they are equally valuable.
Exceptions should never be allowed to "escape" from finalization (or initialization) sections for precisely this reason.
With very few exceptions [sic], any code in a finalization section should be enclosed in a try..except. What you do when you get an exception is up to you, but at the very least a call to OutputDebugString() will give you information when debugging and give you a point on which to set a breakpoint that will only cause a break when an actual exception has occurred.
finalization
try
// Perform finalization processing here
except
on e: Exception do
OutputDebugString('%s: $s in unit %s', [e.ClassName, e.Message, 'MyUnitName']);
end;
end.
NOTE: The OutputDebugString() call in this code is to my own "string friendly", wrapper around the function in the Windows unit, extended to accept args.
Since you presumably don't have such exception handling in your finalization sections, this will involve putting them in place before you can proceed. However, this exercise will improve the quality of your code overall, and make diagnosing any similar problems in the future that much easier (who's to say that once you have identified and fixed your current exception, that some other finalization exception will not raise it's ugly head?).
Also, the process of applying this exception handling will give you an opportunity to review each finalization section and determine whether it cannot be handled differently, with a view to eliminating as many finalization sections as possible.
This should not be considered an "unnecessary overhead" or a "waste of time" but an essential piece of housekeeping to bring your code quality up to an acceptable standard.
An Alternative Approach
An alternative approach is to manage your own list of finalization procedures, as we had to do before finalization sections were introduced. i.e. in the initialization section of a unit that current has finalization, remove the current finalization code into a parameterless procedure and register that procedure with a "finalization manager".
Then, in your application, invoke the "finalization manager" at an appropriate time during application shutdown, to perform your finalization before any actual unit finalization takes place. This ensures that your finalization procedures are performed with the runtime exception handler still in place.
This also presents the opportunity for providing a more sophisticated "finalization manager", with mechanisms to ensure that finalization procedures are performed in a specific, determined order (if required). This capability depends on how you implement your own finalization manager, naturally.
Go to View/Debug Windows/Modules, find cxLibraryD15.bpl and extract its base adderess. Now, substract $00E51B9E - base = offset.
Run your application and immediately pause it. Go to View/Debug Windows/Modules, find cxLibraryD15.bpl and extract its base adderess (it could be the same). Now, add an offset from step 1 to it: base + offset = absolute address.
Open breakpoints window or CPU view and set breakpoint at address from step 2. Now you'll stop right before exception occurs, thus you can see call stack and analyze the situation in the debugger.
Try to set breakpoint to KiUserExceptionDispatcher, RaiseException and Exception.GetExceptionStackInfoProc.

AV after successful close of applications

I am getting this AV message about 3 to 5 seconds after the applications close as expected:
Exception EAccessViolation in module rtl160.bpl at 00073225. Access violation at address 500A3225 in module 'rtl160.bpl'. Read of address 00000004.
These (20) applications are very similar in that they are IBX business applications. About half of them did not cause the AV to occur.
These applications were ported from Delphi-xe and they worked flawlessly for a long time. No changes were made to the projects in the port. Both 32 and 64 bit builds gave the same results.
Is this a bug in some library's finalization section freeing a resource or something?
I am using Delphi-XE2 Update 3.
Would appreciate the help.
Try using madExcept / EurekaLog etc. - they give you detailed stack trace on AV. This is not always a panacea, but can point you to the problem.
Access Violations are by their nature already very troublesome beasts since they deal with invalid pointers in memory. One that occurs a while after an application shuts down is even worse because that's when your app is in "cleanup" mode. You're could be dealing with something that went wrong much earlier in the application, but is only exposing itself at shutdown.
General Tips:
Try to always undo things in the reverse order you did them. E.g.
Create A, Create B ... Destroy B, Destroy A
Connect to Database, Open Dataset ... Close Dataset, Disconnect from Database
Even making sure you've done all the above before shutting down can help tremendously.
Any threads that are still running while your application is running can cause problems.
Preferably ensure all your child threads are properly terminated before final shutdown.
Refer back to Closing datasets above. Depending on what you're doing, some database components will create their own threads.
If you're using COM, try ensure ComObj is high up in the initialization sequence (I.e. place it as high as possible in your DPR).
Delphi finalizes units in the reverse order that they were initialized.
And you don't want ComObj to finalize before other things that are dependent on ComObj have also done so.
If you're using interface references, make sure you resolve circular reference issues.
Some of these problems can be tricky to find, but you can do the following:
Setup a source-code "sandbox" environment (you're going to chuck all your changes as soon as you've found the problem).
Figure out the simplest set of steps required to guarantee the error. (Start app and immediately shutdown would be ideal.)
Then you're going to comment-out delete wipe out chunks of code between tests and basically follow a divide and conquer approach to:
rip out code
test
if the problem persists, repeat. Else roll-back and rip out a different chunk of code.
eventually your code base will be small enough to pinpoint likely problems which can be tackled with targeted testing.
I've had this kind of access violation problem on occasion with old Delphi or C++Builder projects. Today I had it with C++Builder. At the time of the crash, by looking in the Debug -> Call Stack window, I can see that it's happening inside a call to fflush, called by __exit_streams and _exit.
I'm not sure what is causing it, since it's so deep in the Borland library code, but it seems to come and go at random when the code changes. And it seems to be more common with multi-form applications.
This time the error went away when I just added a new button on the main form. A button which is just there, has no event handlers and does not do anything. I think that any random change to the code, classes, variables etc rearranges the memory layout when you relink the application, and that either triggers or untriggers the error.
For now, I just leave the new button on the form, set it to "not visible" so that there's no visible change. As it seems to work, it's good enough solution for me at this time.

How do I debug an Access violation in the field?

An application in the field is getting this message intermittently:
I am not able to reproduce this on my machine. I have also traced what I believe is the relevant code and can't find any access to uninitialized objects.
I've never had to deal with this kind of problem.
I did a build with madExcept and unfortunately the program does not crash once it is bundled.
Any opinions on madExcept vs EurekaLog for finding this kind of thing? I've never used FastMM. Would it be useful in his situation? (Delphi 2010) Any suggested flags to set in FastMM? Any other recommendations?
Note the very low address you are attempting to read. This sort of error almost certainly means you attempted to dereference a nil pointer even if you can't find one.
Given your description of the behavior I would suspect you've got a memory stomp going on--something is blasting a zero on top of the pointer to an object. When you change things you move things around and the stomp moves to someplace harmless.
Turn on both range checking and overflow checking.
Note the offending object must be at least 3C0 bytes in size--this should help narrow it down, most objects will be smaller than this.
What I have done in the past with such errors that only show in the field is put logging checkpoints in--a bunch of lines that display something in an out of the way place--a simple sequence of numbers is fine. Find out what number is showing when it crashes and you know which of you checkpoints was the last to execute. If that doesn't narrow it down enough you can repeat the process now that you've narrowed it down.
With a full map file you can identify the exact point in the code where this occurs. I hope you have a full map file for this image! Subtract $00401000 from the address at which the exception is raised ($007ADE8B in your case) and that corresponds to the values in the map file.
Having done that you know which object is nil and from there it is usually not too hard to work out what is going on.
One of the most common ways for this to occur is when a constructor raises an exception. When this occurs the destructor runs. If you access, in a destructor, a field that has not been initialised, and do anything other than call Free on it, then you will get an exception like this.
Looks like a memory overwrite where changing memory layout (your machine vs field machine or adding madExcept) makes the overwrite change something harmless.
FastMM is great at of making this kind of problems happen more consistently (and finding their source). Download the full version of FastMM, add it as the first unit of your project, and turn on FullDebugMode on its settings.
It might cause the problem to be reproduceable in your machine right away. If not, don't forget to deploy FastMM_FullDebugMode.dll with your application for testing. Keep madExcept on and let it embed the .map file for call stacks.

How can I find out which exceptions a Delphi function might throw?

Is there a good way to find out which exceptions a procedure/function can raise in Delphi (including it's called procedures/functions)?
In Java you always have to declare which exceptions that can be thrown, but this is not the case in Delphi, which could lead to unhandled exceptions.
Are there any code analysis tools that detects unhandled exceptions?
(Edit: It is now obvious that the question referred only to design-time checking.)
New answer:
I cannot state whether there are any tools to check this for you. Pascal Analyzer, for one, does not.
I can tell you, however, that in most Delphi applications, even if there was a tool to check this for you, you would get no results.
Why? Because the main message loop in TApplication.Run() wraps all HandleMessage() calls in an exception handling block, which catches all exception types. Thus you will have implicit/default exception handling around 99.999% of code in most applications. And in most applications, this exception handling will be around 100% of your own code - the 0.001% of code which is not wrapped in exception handling will be the automatically generated code.
If there was a tool available to check this for you, you would need to rewrite Application.run() such that it does not include exception handling.
(Previous answer:
The Application.OnException event handler can be assigned to catch all exceptions that aren't handled by other exception handlers. Whilst this is run-time, and thus perhaps not exactly what you are after (it sounds like you want to identify them at design time), it does allow you to trap any exception not handled elsewhere. In conjunction with tools such as the JCLDebug stuff in the Jedi Code Library, you could log a stack trace to find out where & why an exception occurred, which would allow for further investigation and adding specific exception handling or prevention around the guilty code...)
My guess is that you're trying to make Delphi behave like Java, which is not a good approach. I'd advise not to worry too much about unhandled exceptions. In the worst case, they'll bubble up to the generic VCL exception handler and cause a Windows message dialog. In a normal application, they won't halt the application.
Well-written code would document the different exceptions that can be raised so you can handle them in a meaningful way. Catch-all handlers aren't recommended since there is really no way to know what to do if you don't know why an exception was raised. I can also highly recommend madExcept.
Except for a scan on the "raise" keyword, there's no language construct in Delphi that tells the casual reader which exceptions can be expected from a method.
At runtime, one could add a catch-all exception handler in every method, but that's not advisable, as it will slow down the speed of execution. (And it's cumbersome to do too).
Adding an exception-handling block to a method will add a few assembly instructions to it (even when the exception isn't triggered), which forms measureable slow-down when the method is called very often.
There do exist a few libraries that can help you in analyzing runtime exceptions, like madExcept, JclDebug, and EurekaLog. These tools can log all kinds of details about the exception, it's highly advisable to use one of those!
The short answers is there is no tool that does what you say, and even a scan for the raise keyword wouldn't get you there. EAccessViolation or EOutOfMemory are just two of a number of exceptions that could get raised just about anywhere.
One fundamental thing about Delphi is the exceptions are hierarchical: All defined language exceptions descend from Exception, although it is worth noting that it is actually possible to raise any TObject descendant.
If you want to catch every exception that is raised in a particular procedure, just wrap it in a try / except block, but as was mentioned this is not recommended.
// Other code . . .
try
SomeProcedure()
except // BAD IDEA!
ShowMessage('I caught them all!');
end;
That will catch everything, even instances of a raised TObject. Although I would argue that this is rarely the best course of action. Usually you want to use a try / finally block and then allow your global exception handler (or one final try / except block) to actually handle the exceptions.
I will second (or is it third) MadExcept. I have been using it successfully in several commercial applications without any problems. The nice thing about MadExcept is that it will generate a report for you with a full stack trace that will generally point you in the right direction as to what went wrong, and can even include a screenshot, as well has have this automatically emailed to you from the clients computer with a simple mouse click.
However, you don't want to use this for ALL exceptions, just to catch the ones you miss. For instance, if you open a database and the login fails, it would be better for you to catch and handle this one yourself rather than give the user the MadExcept default error in your application occured message.
Any exception not explicitly or generally handled at a specific level will trickle upwards in the call stack. The Delphi RTL (Run Time Library) will generate a set of different exception classes - (mathematical errors, access errors, class specific errors etc). You can chose to handle them specifically or generally in the different try except blocks.
You don't really need to declare any new exception classes unless you need to propagate a specific functional context with the exception.
As previous commenters wrote, you can also add a mother of all exception handlers like MadExcept or EurekaLog to catch the uncaught.
edit: This is a blanket insurance against unhandled exceptions
try
ThisFunctionMayFail;
except
// but it sure won't crash the application
on e:exception
do begin
// something sensible to handle the error
// or perhaps log and/or display the the generic e.description message
end
end;
Take a look at http://www.madshi.net/madExceptDescription.htm
For runtime try Eurekalog. I do not know whether a tool exists for design time. You will have more dificoulties even when you have third party code without source. There is no need in Delphi to catch exceptions, so you do not have to declare them like in Java.
What I wanted to say is that Delphi does not require that an exception is handled. It will just terminate the program. EurekaLog provides means to log handled and unhandled exceptions and provide a wealth of information on the sate of the program when the exception occured, including the line of code it occured at and the call stack at the time.
As Jim McKeeth points out, you can't get a definitive answer, but it seems to me that one could partially answer the question by some static analysis: given a particular function/procedure, construct a call graph. Check each of the functions in that call graph for a raise statement. That would tell you, for instance, that TIdTcpClient.ReadString can raise an EIdNotConnected (among others).
A clever analyser might also note that some code uses the / operator and include EDivByZero as a possibility, or that some procedure accesses an array and include ERangeError.
That answer's a bit tighter than simply grepping for "raise".
Finalization sections of units can raise exceptions too. These will slip by I think... and are also somewhat problematic.
I think Delphi IDE has a build-in "stack trace" or "stack tree" something like.
This question reminds me of Skybuck's TRussianRoulette game... google it, it's code and answer may help.

Resources