views:

1369

answers:

8

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!

+8  A: 

"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.)

gabr
I second the use of madExcept, which I have used successfully in Delphi 7.
Bruce McGee
Third on the use of madExcept. Its very easy to use, just install into the IDE and enable for your project.
skamradt
I concure, with both doctors ...
CheGueVerra
+6  A: 

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.

Barry Kelly
This seems close to the truth, I'm investigating further. Thanks!
Niklas Winde
+1  A: 

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.

Gustavo
+1  A: 

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.

François
+2  A: 

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.

X-Ray
A: 

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

Steve
A: 

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.

Do you know if the except block was even entered? Could you put an OutputDebugString() in there to check?

Peter Turner
A: 

I've got the very same problem as the autor. I can't excute the except-block. Debugger stops the application.

Deactivating the debugger doesn't help. The Exceptions get caught by the OS. Can it be ? Is there a bug in Delphi 7 exception handling ?

Here an example (text is in German sorry): http://img207.imageshack.us/img207/2135/except.png

temporaryGuy