I've got a program that's having some trouble during shutdown, raising exceptions that I can't trace back to their source. It appears to be timing-related and non-deterministic. This is occurring after all shared resources have been released, and since it's shutdown, memory leaks are not an issue, so that makes me wonder if there's any way to just tell the program to terminate immediately and silently after releasing the shared resources, instead of continuing with the shutdown sequence and giving an exception message box.
Does anyone know how to do that?
After looking at the Delphi Run Time Library source code, and at the Microsoft documentation; I can corroborate Mason and Paul-Jan comments.
The hierarchy of shutdown is as follows
Application.Terminate()
performs some unidentified housekeeping of application
calls Halt()
Halt()
calls ExitProc if set
alerts the user in case of runtime error
get rid of PackageLoad call contexts that might be pending
finalize all units
clear all exception handlers
call ExitprocessProc if set
and finally, call ExitProcess() from 'kernel32.dll'
ExitProcess()
unloads all DLLs
uses TerminateProcess() to kill the process
ExitProcess(0) ?
Halt(0) used to be the good old fashioned way of telling the program to end with immediate effect. There's probably a more Delphi-friendly way of doing that now, but I'm 95% sure halt(0) still works. :-)
In case HeartWare's suggestion of using ExitProcess() fails, it might be you are using some DLL's that do not respond well to the DLL_PROCESS_DETACH. In that case, try using a TerminateProcess( getCurrentProcess, 0 );
Once you resort to such measures, one might wonder if the "cleanly" part of the topic title still holds up to scrutiny.
The last time I had to hunt a problem like this was the shutdown was a causing an event (resize? It's been a while.) to fire on the dying window causing an attempt to redraw something that needed stuff that had already been disposed of.
Related
my application uses two self-written components that perform actions during the "loaded" procedure.
The component created first is an single-instance control that should exit the application when another instance is found.
The component created secondly is my database access that establishes the database connection in the "loaded" procedure.
I try to end the application before anything else happens, if a first instance has been found.
Tryout 1:
In my instance control, i call "Application.Terminate" to stop my application. That does not work - my database connection still gets established. Seems that "Application.Terminate" uses a "PostMessage" call to itself, which won't get read until the message gets received (which will happen after all components are loaded...). So obviously, this solution does not work for me.
Tryout 2:
In my instance control, i call "Halt" to stop my application. This immediately stops my application, but seems to create a load of memory leaks - at least that's what delphi's "ReportMemoryLeaksOnShutdown" tells me. Afterwards, i get this annoying "This application has stopped working" windows dialogue. This solution does not work for me.
Question A:
Is there another way to end an Application?
Question B:
Does Delphi's memory leak report work correctly when using "Halt"? Are there really memory leaks after exiting the Application with "Halt"?
If Application.Terminate terminates too late, and you want to terminate post haste, then Halt seems to me to be the appropriate course of action. I don't particularly see why Halt should lead to This application has stopped working exceptions. That suggests that your program's unit finalization code is raising exceptions which are not handled. You could perhaps try to work out (using the debugger, say) why these exceptions are raised and protect against it. Or you could avoid unit finalization with a call to the even more brutal ExitProcess.
There will indeed be memory leaks when you call Halt. However, these can safely be ignored because the operating system reclaims all allocated memory when a process terminates. In other words, the memory is leaked in the sense that is not freed by the application, but the operating system frees it immediately in any case.
However, whether or not a brutal Halt is the correct course of action for you, I cannot say. That's for you to decide. FWIW, a call to Halt from inside a component's Loaded method sounds exceptionally dubious to me.
If all you want to do is ensure that just a single instance of your program runs, then you can make simple modifications to the .dpr file to achieve that. That subject has been covered over and over again here on Stack Overflow. You'll find good coverage and advice in Rob Kennedy's answer here: How can I tell if another instance of my program is already running?
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.
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 created a class that handles serial port asynchronously. I use it to communicate with a modem. I have no idea why, but sometimes, when I close my application, I get the Blue Screen and my computer restarts. I logged my code step by step, but when the BSOD appeared, and my computer restarted, the file into which I was logging data contained only white spaces. Therefore I have no idea, what the reason of the BSOD could be.
I looked through my code carefully and I found several possible reasons of the problem (I was looking for all that could lead to accessing unallocated memory and causing AV exceptions).
When I rethought the idea of asynchronous operations, a few things came to my mind. Please verify whether these are right:
1) WaitCommEvent() takes a pointer to the overlapped structure. Therefore, if I call WaitCommEvent() inside a function and then leave the function, the overlapped structure cannot be a local variable, right? The event mask variable and event handle too, right?
2) ReadFile() and WriteFile() also take references or pointers to variables. Therefore all these variables have to be accessible until the overlapped read or write operations finish, right?
3) I call WaitCommEvent() only once and check for its result in a loop, in the mean time doing other things. Because I have no idea how to terminate asynchronous operations (is it possible?), when I destroy my class that keeps a handle to a serial port, I first close the handle, and then wait for the event in the overlapped structure that was used when calling the WaitCommEvent() function. I do this to be sure that the thread that waits asynchronously for a comm event does not access any fields of my class which is destroyed. Is it a good idea or is it stupid?
try
CloseHandle(FSerialPortHandle);
if Assigned(FWaitCommEvent) then
FWaitCommEvent.WaitFor(INFINITE);
finally
FSerialPortHandle := INVALID_HANDLE_VALUE;
FreeAndNil(FWaitCommEvent);
end;
Before I noticed all these, most of the variables mentioned in point one and two were local variables of the functions that called the three methods above. Could it be the reason of the BSOD or should I look for some other mistakes in my code?
When I corrected the code, the BSOD stopped occuring, but It might be a coincidence. How do you think?
Any ideas will be appreciated. Thanks in advance.
I read the CancelIo() function documentation and it states that this method cancells all I/O operations issued by the calling thread. Is it OK to wait for the FWaitCommEvent after calling CancelIo() if I know that WaitCommEvent() was issued by a different thread than the one that calls CancelIo()?
if Assigned(FWaitCommEvent) and CancelIo(FSerialPortHandle) then
begin
FWaitCommEvent.WaitFor(INFINITE);
FreeAndNil(FWaitCommEvent);
end;
I checked what happens in such case and the thread calling this piece of code didn't get deadlocked even though it did not issue WaitCommEvent(). I tested in on Windows 7 (if it matters). May I leave the code as is or is it dangerous? Maybe I misunderstood the documentation and this is the reason of my question. I apologize for asking so many questions, but I really need to be sure about that.
Thanks.
An application running as a standard user should never be able to cause a bug check (a.k.a. BSOD). (And an application running as an Administrator should have to go well out of its way to do so.) Either you ran into a driver bug or you have bad hardware.
By default, Windows is configured to save a minidump in %SystemRoot%\minidump whenever a bug check occurs. You may be able to determine more information about the crash by loading the minidump file in WinDbg, configuring WinDbg to use the Microsoft public symbol store, and running the !analyze -v command in WinDbg. At the very least, this should identify what driver is probably at fault (though I would guess it's your modem driver).
Yes, you do need to keep the TOverlapped structure available for the duration of the overlapped operation. You're going to call GetOverlappedResult at some point, and GetOverlappedResult says it should receive a pointer to a structure that was used when starting the overlapped operation. The event mask and handle can be stored in local variables if you want; you're going to have a copy of them in the TOverlapped structure anyway.
Yes, the buffers that ReadFile and WriteFile use must remain valid. They do not make their own local copies to use internally. The documentation for ReadFile even says so:
This buffer must remain valid for the duration of the read operation. The caller must not use this buffer until the read operation is completed.
If you weren't obeying that rule, then you were likely reading into unreserved stack space, which could easily cause all sorts of unexpected behavior.
To cancel an overlapped I/O operation, use CancelIo. It's essential that you not free the memory of your TOverlapped record until you're sure the associated operation has terminated. Likewise for the buffer you're reading or writing. CancelIo does not cancel the operation immediately, so your buffers might still be in use even after you call it.
When we created our program, it closed properly under XP, but under Vista, even though the program is closed, the process is often still running until I open task manager and manually kill the process.
Any suggestions on how to make sure this is closed when we close the program? What a pain.
Mark Gundy
www.magchat.com
The debugger will be your friend here. Step through the shutdown until you get stuck. That'll be the best bet.
But... assuming for some reason the debugger is affecting the behaviour, or can't be used for some other reason:
A few earlier replies suggest using FastMM. This has been the default memory manager for delphi since D2006. You can try flipping on the options to report memory leaks... but that'll only work after you've finished shutting down the process, which is what isn't working. :) So I doubt it will help you much in this case. The full version of FastMM, as opposed to the standard one packaged with delphi, might have some other helpful features... But I can't recall any that would help here.
To inspect your app while it's stuck, you could try the sysinternals tools, like Process Explorer & Process Monitor. Process Monitor may show you if it's choking on any ACCESS_DENIED errors, etc, and the stack trace at the time of the error. Process Explorer could be especially useful, by listing all the handles your process is still holding open, and allowing you to view the stack of all its living threads. A familiar function or two, in the stack traces of any hung threads, may send you hunting in the right area.
Are you using multiple threads? If one of them can't terminate for some reason, it'll hang the cleanup process.
The short answer is that you have a bug in your application. So, have you tried debugging it?
If you have the Delphi IDE installed on Vista, run the app from the IDE and break it when it 'hangs'. Chances are that you'll have a thread that hasn't terminated itself, and the VCL is waiting for it to finish.
If you don't have the IDE installed on vista, you can probably use the remote debugger, but I'm not familiar with this.
What do you call to close your program? Try using
Application.Terminate;
To force all forms to close and the process to exit.
It probably means you have some memory leak - some resource is not released.
If your application instantiates COM objects, check that you properly close them.
If you use older version of Delphi, you can try to locate possible memory leaks with FastMM
Edit, examples as requested:
I had two situations where application sometimes would stay resident in memory after exit. Both applications would disappear from taskbar, but they would be still active - visible in task manager. Both applications were created with Delphi 7.
First application has one main window with panel in which ather forms are embedded. Each form is standard TForm. Each form is created first time user requests it. Everything worked without problems in test environment, but users reported that from time to time, application would remain in memory, usually after longer usage - when user displayed almost all of the forms in application. I could not replicate this behavior while testing. That was first time I found out about FastMM. When I first run application with FastMM, it reported that some of forms embedded in main form were not released. This version was tested at user site and it turned out that 2 forms that have lots of data aware components would hang up and prevent application from exiting. When I added code that makes sure that all created forms are released before main form, application never hung up on exit.
Second example is application that uses COM to activate GIS editor (Geomedia) to manipulate some map data. I imported type libraries and created Delphi wrapper object. Some of created objects were not freed when application ends. Application icon disappeared from task bar, but application and GIS editor were still active and visible in task manager. Again, it did not happen every time application run. I included FastMM in application and it reported that some objects were not freed. I made sure that every created object gets freed and after that application did not hang on exit any more.
... and if you need to close single form, then use:
Form.Close;
GUI AND HANDLER DELETED. Reference and some parts of memory is left to provide access to variables, constants, etc.
If you need to hide ( something like Minimize, only GUI is cleared ) form, then:
Form.Hide;
GUI is cleared, leaving internal resources untoauched ( reference, handler, memory )
If form is dynamic ( created at runetime ), then use:
Form.Destroy;
ALL RESOURCES WILL BE CLEARED FROM MEMORY, leaving reference and handlers attached so you could access its location in memory.
If form is dynamic and you will not use it for the same interface, then:
Form.Free;
ALL RESOURCES, REFERENCES, HANDLERS ARE DELETED. I recommend to use this to VCL TComponent class, not for TForm class.
Also, there is Form.FreeAndNill, but my guess that it deleted all memory and loaded handlers, only allowing to use same memory space in the same interface again... (I might be wrong though).
P.S. I hope I am not writing wrong things as the last time I read the theory was a long, long time ago... and it was about Destructor DESTROY in general ...
P.P.S ALSO PLEASE BE CAREFUL if you're writing a Vista-ready app - that it includes UAC Handling with manifests / runtime code and SuperBar compatibility requirement. Also Aero requires some additional megabytes to output file due its Aero feature ... :P