I am working in a DLL which sometimes raises unhandled exceptions. I am using madExcept to detect and debug the buggy code, but when I finally deploy my DLL I want include my own global exception handler inside the DLL to log the exceptions.
So the question is how I can set a global exception handler in my Delphi DLL?
The concept of "a global exception handler" doesn't really exist in DLLs the way it exists in the VCL. To understand why, remember that exceptions propagate by unwinding the stack until they can find a handler. The VCL can install a global exception handler because in a VCL app, everything that happens (excluding startup and shutdown) will have TApplication.Run somewhere in the call stack, and that's where it puts the exception handler. Since your DLL doesn't have a single central point like that, you can't do it that way.
What you can do is set up a "central exception handler routine" in your DLL somewhere. It should take an Exception object as a parameter. Then do something like this for all your exported routines:
procedure MyExportedRoutine(param: integer);
begin
try
//do normal stuff
except
on E: Exception do
CentralExeptionHandler(E);
end;
end;
That's really the best you can do, unless you're using COM. If you're writing a COM DLL, mark your interface methods with the safecall calling convention and the compiler will silently generate code for you that takes care of exception propagation.
What exactly do you mean by "global exception handler"?
Windows Structured Exception Handling (SEH), in 32-bit, finds a handler by walking the exception handler chain of the thread in which the exception occurred. The exception handler chain is a linked list of records, the head of which is found in FS:[0]; the records are normally allocated on the stack, pushed at every try and popped when the protected block is exited. There's a callback routine referred to by each exception record; Windows calls this routine with details of the exception during its search phase to determine whether or not this "level" of the chain is going to "handle" the exception. Windows then unwinds the call stack to that point by going through the exception chain again, calling each callback with a different value letting it know that unwinding is going on, until it reaches the handler that elected to handle the exception. If no handler is found, the process is terminated, hard, without notification. Normally this doesn't happen; the OS installs a last-chance handler of its own at the bottom of the stack (last element in the chain), and this normally pops up the familiar Windows "this program has encountered a problem" dialog. But if things have gotten very corrupt, or the exception handler chain has been messed around with to remove it, then the process goes down hard.
So from this brief overview of Windows exception handling, it should be clear that there is no single "global" handler, only a list of handlers, one list per thread (FS register is part of the thread context); and the "last chance" handler is the one that is installed earliest in the stack. The easiest way of catching exception that occur inside your DLL is to immediately install an exception handler at every entry point. See Mason's answer for details of how to do that (it's with try/except); but be aware that if your DLL calls back into somewhere else (e.g. via a callback routine), then you may be catching exceptions that weren't "meant" for you and not caused by your code. (It's poor style to expect exceptions to propagate like that through third-party code at the DLL level, but it can happen.)
Related
I've set Application.OnException to a custom exception handler so that I can log crashes and give an option to exit. However, I'm now finding that this runs even on exceptions that I've already handled, for instance, exceptions that come up when validating number inputs. Is there a way to have the custom exception handler only run on unhandled exceptions?
Edit: it turns out that I get the expected behavior when I run outside the debugger. Maybe it's just a debugger thing. I do not find the Delphi debugger's interaction with exceptions to be intuitive, to say the least.
If behavior changes inside and outside the debugger, then it's not really your program that's telling you about exceptions. I've written about this phenomenon on my Web site:
Why do I continue getting error messages even after I have written an exception handler?
An excerpt:
In its default settings, the Delphi IDE notifies you whenever an exception occurs in your program ... . What’s important to realize is that at that point, none of your program’s exception-handling code has run yet. It’s all Delphi itself; its special status as a debugger allows it to get first notification of any exception in your program, even before your program knows about it.
After you dismiss Delphi’s message box, execution will be paused at the best line of your source code Delphi could find to represent the source of the exception. Press the “Run” button to have your program resume. Control will pass to the next finally or except
block. Before you resume your program, you may use the various debugging tools at your disposal. You can inspect the values of any variables in scope, and you can even modify their values.
So, how do you notify Delphi that you've already handled an exception? You don't — because your program hasn't handled it yet. And why can't the debugger detect whether your program is going to handle an exception? Because in order to do that, it needs to execute your program further. Detecting the lack of an exception handler is like solving the halting problem. The only way to determine whether an exception is going to be handled is to let the program run and then see whether the exception gets handled. But by that point, it's too late to do any debugging, so the debugger has no choice but to pause your program when it first detects an exception and then let you figure out what to do from there.
My article goes on to describe some ways you can avoid having the debugger catch certain exceptions, summarized here:
Use advanced breakpoints to temporarily disable breaking on exceptions for certain regions of the code.
Configure the debugger to ignore certain classes of exceptions (and their descendants).
Tell the debugger not to notify you about any exceptions.
Disable integrated debugging altogether.
There's another options that I didn't include in my article:
Change your program such that the exception doesn't get raised in the first place.
You say you're validating numeric input. That sounds to me like you're doing something like calling StrToInt and then catching the EConvertError exception when the input isn't a valid integer. That's an expensive way of validating input. Instead of that, use TryStrToInt, which will tell you whether the conversion succeeded, or StrToIntDef, which will silently return a default value instead of raising an exception. Another option is plain old Val, which tries to convert a string, and if it fails, it tells you which position in the string caused the failure. Val is particularly useful if you want to consume as many characters as possible for the conversion and then resume parsing at the next non-numeric character.
Quoting from the documentation (Delphi 7) on TApplication.OnException
"Use OnException to change the default behavior that occurs when an exception is not
handled by application code."
So: Only unhandled exception will be available in the OnException event handler. What you are experiencing is probably the Delphi IDE breaking on the exception. This is (at least in Delphi 7) configurable.
In Delphi 7 you can configure it by clicking on the Tools->Debugger Options menu. Then select the "Language Exceptions" an un-ckech the "Stop on Delphi exceptions" checkbox. It might however be different in other delphi versions.
An alternative might be to not use Application.OnException. But to simply catch all exceptions in your "main" function. That way you can catch all exceptions you have not cached before, log the exception, and then crash.
Application.OnException should only fire for unhandled exceptions. Re-raising an exception in a try-except block will cause the exception to be handled by Application.OnException. For input validation that raises an exception, you could display a message to the user and then re-raise the exception only if you want it recorded into the error log.
I've set Application.OnException to a custom exception handler so that I can log crashes and give an option to exit. However, I'm now finding that this runs even on exceptions that I've already handled, for instance, exceptions that come up when validating number inputs. Is there a way to have the custom exception handler only run on unhandled exceptions?
Edit: it turns out that I get the expected behavior when I run outside the debugger. Maybe it's just a debugger thing. I do not find the Delphi debugger's interaction with exceptions to be intuitive, to say the least.
If behavior changes inside and outside the debugger, then it's not really your program that's telling you about exceptions. I've written about this phenomenon on my Web site:
Why do I continue getting error messages even after I have written an exception handler?
An excerpt:
In its default settings, the Delphi IDE notifies you whenever an exception occurs in your program ... . What’s important to realize is that at that point, none of your program’s exception-handling code has run yet. It’s all Delphi itself; its special status as a debugger allows it to get first notification of any exception in your program, even before your program knows about it.
After you dismiss Delphi’s message box, execution will be paused at the best line of your source code Delphi could find to represent the source of the exception. Press the “Run” button to have your program resume. Control will pass to the next finally or except
block. Before you resume your program, you may use the various debugging tools at your disposal. You can inspect the values of any variables in scope, and you can even modify their values.
So, how do you notify Delphi that you've already handled an exception? You don't — because your program hasn't handled it yet. And why can't the debugger detect whether your program is going to handle an exception? Because in order to do that, it needs to execute your program further. Detecting the lack of an exception handler is like solving the halting problem. The only way to determine whether an exception is going to be handled is to let the program run and then see whether the exception gets handled. But by that point, it's too late to do any debugging, so the debugger has no choice but to pause your program when it first detects an exception and then let you figure out what to do from there.
My article goes on to describe some ways you can avoid having the debugger catch certain exceptions, summarized here:
Use advanced breakpoints to temporarily disable breaking on exceptions for certain regions of the code.
Configure the debugger to ignore certain classes of exceptions (and their descendants).
Tell the debugger not to notify you about any exceptions.
Disable integrated debugging altogether.
There's another options that I didn't include in my article:
Change your program such that the exception doesn't get raised in the first place.
You say you're validating numeric input. That sounds to me like you're doing something like calling StrToInt and then catching the EConvertError exception when the input isn't a valid integer. That's an expensive way of validating input. Instead of that, use TryStrToInt, which will tell you whether the conversion succeeded, or StrToIntDef, which will silently return a default value instead of raising an exception. Another option is plain old Val, which tries to convert a string, and if it fails, it tells you which position in the string caused the failure. Val is particularly useful if you want to consume as many characters as possible for the conversion and then resume parsing at the next non-numeric character.
Quoting from the documentation (Delphi 7) on TApplication.OnException
"Use OnException to change the default behavior that occurs when an exception is not
handled by application code."
So: Only unhandled exception will be available in the OnException event handler. What you are experiencing is probably the Delphi IDE breaking on the exception. This is (at least in Delphi 7) configurable.
In Delphi 7 you can configure it by clicking on the Tools->Debugger Options menu. Then select the "Language Exceptions" an un-ckech the "Stop on Delphi exceptions" checkbox. It might however be different in other delphi versions.
An alternative might be to not use Application.OnException. But to simply catch all exceptions in your "main" function. That way you can catch all exceptions you have not cached before, log the exception, and then crash.
Application.OnException should only fire for unhandled exceptions. Re-raising an exception in a try-except block will cause the exception to be handled by Application.OnException. For input validation that raises an exception, you could display a message to the user and then re-raise the exception only if you want it recorded into the error log.
This happens half of the time when closing my application in which I have placed a TLMDHiTimer on my form in design time, Enabled set to true.
In my OnFormClose event, I call MyLMDHiTimer.Enabled := false. When this is called, I sometimes (about half of the time) get this exception.
I debugged and stepped into the call and found that it is line 246 in LMDTimer.pas that gives this error.
FThread.Terminate;
I am using the latest version of LMDTools. I did a complete reinstall of LMD tools before the weekend and have removed and re-added the component to the form properly as well.
From what I've found, this has something to do with TExternalThread, but there's no documentation on it from Embarcadero and I haven't found anything referencing it within the LMDTools source code.
Using fully updated RAD Studio 2010, Delphi 2010.
What really upsets me here is that there's no documentation whatsoever. Google yeilds one result that actually talks about it, in which someone says that the error is caused by trying to terminate a TExternalThread.
But looking at the source-code for this LMDHiTimer, not once does it aim to do anything but create a regular TThread.
The one google result I could find, Thread: Cannot terminate an externally created thread? on Embarcadero mentions using GetCurrentThread() and GetCurrentThreadId() to get the data necessary to hook on to an existing thread, but the TLMDHiTimer does no such thing. It just creates its own TThread descendant with its own Create() constructor (overridden of course, and calls inherited at the start of the constructor)
So... What the heck is this TExternalThread? Has anyone else run into this kind of exception? And perhaps figured out a solution or workaround?
I've asked almost the exact same question to LMDTools' own support, but it can't hurt to ask in multiple places.
Thank you in advance for any assistance.
TExternalThread wraps a thread that the Delphi RTL didn't create. It might represent a thread belonging to the OS thread pool, or maybe a thread created by another DLL in your program. Since the thread is executing code that doesn't belong to the associated TExternalThread class, the Terminate method has no way to notify the thread that you want it to stop.
A Delphi TThread object would set its Terminated property to True, and the Execute method that got overridden would be expected to check that property periodically, but since this thread is non-Delphi code, there is no Execute method, and any Terminated property only came into existence after the thread code was already written someplace else (not by overriding Execute).
The newsgroup thread suggests what's probably happening in your case:
... you have corrupted memory that causes the TThread.FExternalThread member to become a non-zero value.
It might be due to a bug in the component library, or it could be due to a bug in your own code. You can use the debugger's data breakpoints to try to find out. Set a breakpoint in the timer's thread's constructor. When your program pauses there, use the "Add Breakpoint" command on the Run menu to add a data breakpoint using the address of the new object's FExternalThread field. Thereafter, if that field's value changes, the debugger will pause and show you what changed it. (The data breakpoint will get reset each time you run the program because the IDE assumes the object won't get allocated at the same address each time.)
Is there any chance the code might be trying to Terminate an already Destroyed TThread? This could easily happen if you have FreeOnTerminate set.
I noticed your post while diagnosing a similar (opposite?) error, "Cannot call Start on a running or suspended thread" in the constructor of a component placed on the main form. When I removed the Start(), that error was replaced by more telling errors, e.g. "invalid pointer operation" and "access violation", in the corresponding destructor. The component was trying to manipulate its TThread object after the TThread was Freed, thus leaving things up to Murphy's law. When I fixed that, I was able to replace the Start() call without the "Cannot call Start" error returning.
By analogy, could your problem be that the address of your FExternalThread had been recycled and clobbered before the destructor/Terminate call? In our case, we had a buggy implementation of the Singleton Instance Pattern; but again, FreeOnTerminate also seems like a likely suspect.
[FYI: I'm using I'm using C++ under RAD Studio XE]
I've set Application.OnException to a custom exception handler so that I can log crashes and give an option to exit. However, I'm now finding that this runs even on exceptions that I've already handled, for instance, exceptions that come up when validating number inputs. Is there a way to have the custom exception handler only run on unhandled exceptions?
Edit: it turns out that I get the expected behavior when I run outside the debugger. Maybe it's just a debugger thing. I do not find the Delphi debugger's interaction with exceptions to be intuitive, to say the least.
If behavior changes inside and outside the debugger, then it's not really your program that's telling you about exceptions. I've written about this phenomenon on my Web site:
Why do I continue getting error messages even after I have written an exception handler?
An excerpt:
In its default settings, the Delphi IDE notifies you whenever an exception occurs in your program ... . What’s important to realize is that at that point, none of your program’s exception-handling code has run yet. It’s all Delphi itself; its special status as a debugger allows it to get first notification of any exception in your program, even before your program knows about it.
After you dismiss Delphi’s message box, execution will be paused at the best line of your source code Delphi could find to represent the source of the exception. Press the “Run” button to have your program resume. Control will pass to the next finally or except
block. Before you resume your program, you may use the various debugging tools at your disposal. You can inspect the values of any variables in scope, and you can even modify their values.
So, how do you notify Delphi that you've already handled an exception? You don't — because your program hasn't handled it yet. And why can't the debugger detect whether your program is going to handle an exception? Because in order to do that, it needs to execute your program further. Detecting the lack of an exception handler is like solving the halting problem. The only way to determine whether an exception is going to be handled is to let the program run and then see whether the exception gets handled. But by that point, it's too late to do any debugging, so the debugger has no choice but to pause your program when it first detects an exception and then let you figure out what to do from there.
My article goes on to describe some ways you can avoid having the debugger catch certain exceptions, summarized here:
Use advanced breakpoints to temporarily disable breaking on exceptions for certain regions of the code.
Configure the debugger to ignore certain classes of exceptions (and their descendants).
Tell the debugger not to notify you about any exceptions.
Disable integrated debugging altogether.
There's another options that I didn't include in my article:
Change your program such that the exception doesn't get raised in the first place.
You say you're validating numeric input. That sounds to me like you're doing something like calling StrToInt and then catching the EConvertError exception when the input isn't a valid integer. That's an expensive way of validating input. Instead of that, use TryStrToInt, which will tell you whether the conversion succeeded, or StrToIntDef, which will silently return a default value instead of raising an exception. Another option is plain old Val, which tries to convert a string, and if it fails, it tells you which position in the string caused the failure. Val is particularly useful if you want to consume as many characters as possible for the conversion and then resume parsing at the next non-numeric character.
Quoting from the documentation (Delphi 7) on TApplication.OnException
"Use OnException to change the default behavior that occurs when an exception is not
handled by application code."
So: Only unhandled exception will be available in the OnException event handler. What you are experiencing is probably the Delphi IDE breaking on the exception. This is (at least in Delphi 7) configurable.
In Delphi 7 you can configure it by clicking on the Tools->Debugger Options menu. Then select the "Language Exceptions" an un-ckech the "Stop on Delphi exceptions" checkbox. It might however be different in other delphi versions.
An alternative might be to not use Application.OnException. But to simply catch all exceptions in your "main" function. That way you can catch all exceptions you have not cached before, log the exception, and then crash.
Application.OnException should only fire for unhandled exceptions. Re-raising an exception in a try-except block will cause the exception to be handled by Application.OnException. For input validation that raises an exception, you could display a message to the user and then re-raise the exception only if you want it recorded into the error log.
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.