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.
Related
What tips can you share to help locate and fix access violations when writing applications in Delphi?
I believe access violations are usually caused by trying to access something in memory that has not yet been created such as an Object etc?
I find it hard to identify what triggers the access violations and then where to make the required changes to try and stop/fix them.
A example is a personal project I am working on now. I am storing in TTreeView Node.Data property some data for each node. Nodes can be multiple selected and exported (the export iterates through each selected node and saves specific data to a text file - the information saved to the text file is what is stored in the nodes.data). Files can also be imported into the Treeview (saving the contents of the text files into the node.data).
The issue in that example is if I import files into the Treeview and then export them, it works perfect. However if I add a node at runtime and export them I get:
"Access Violation at address 00405772 in module 'Project1.exe'. Read of address 00000388."
My thoughts on that must be the way I am assigning the data to created nodes, maybe differently to the way I assign it when they are imported, but it all looks ok to me. The access violation only shows up when exporting, and this never happens with imported files.
I am NOT looking for a fix to the above example, but mainly advice/tips how to find and fix such type of errors. I don't often get access violations, but when I do they are really hard to track down and fix.
So advice and tips would be very useful.
It means your code is accessing some part of the memory it isn't allowed to. That usually means you have a pointer or object reference pointing to the wrong memory. Maybe because it is not initialized or is already released.
Use a debugger, like Delphi. It will tell you on what line of code the AV occurred. From there figure out your problem by looking at the callstack and local variables etc. Sometimes it also helps if you compile with Debug DCUs.
If you don't have a debugger because it only happens on a client side, you might want to use MadExcept or JclDebug to log the exception with callstack and have it send to you. It gives you less details but might point you in the right direction.
There are some tools that might be able to find these kind of problems earlier by checking more aggressively. The FastMM memory manager has such options.
EDIT
"Access Violation at address 00405772
in module 'Project1.exe'. Read of
address 00000388."
So your problem results in a AV at addresss 00405772 in module 'Project1.exe'. The Delphi debugger will bring you to the right line of code (or use Find Error).
It is trying to read memory at address 00000388. That is pretty close to 00000000 (nil), so that would probably mean accessing some pointer/reference to an array or dynamic array that is nil. If it was an array of bytes, it would be item 388. Or it could be a field of a rather large object or record with lots of fields. The object or record pointer/reference would be nil.
I find that the really hard-to-find access violations don't always occur while I'm running in a debugger. Worse yet, they happen to customers and not to me. The accepted answer mentions this, but I really think it should be given more detail: MadExcept provides a stack traceback which gives me valuable context information and helps me see where the code fails, or has unhandled exceptions (it's not just for access violations). It even provides a way for customers to email you the bug reports right from inside your program. That leads to more access violations found and fixed, reported by your beta testers, or your users.
Secondly, I have noticed that compiler hints and warnings are in fact detecting for you, some of the common problems. Clean up hints and warnings and you might find many access violations and other subtle problems. Forgetting to declare your destructors properly, for example, can lead to a compiler warning, but to serious problems at runtime.
Thirdly, I've found tools like Pascal Analyzer from Peganza, and the audits-and-metrics feature in some editions of Delphi, can help you find areas of your code that have problems. As a single concrete example, Pascal Analyzer has found places where I forgot to do something important, that lead to a crash or access violation.
Fourth, you can hardly beat the technique of having another developer critique your code. You might feel a bit sheepish afterwards, but you're going to learn something, hopefully, and get better at doing what you're doing. Chances are, there is more way than one to use a tree view, and more way than one to do the work you're doing, and a better architecture, and a clean way of doing things is going to result in more reliable code that doesn't break each time you touch it. THere is not a finite list of rules to produce clean code, it is rather, a lifetime effort, and a matter of degrees. You'd be surprised how innocent looking code can be a hotbed of potential crashes, access violations, race conditions, freezes and deadlocks.
I would like to mention one more tool, that I use when other tools fail to detect AV. It's SafeMM (newer version). Once it pointed me to the small 5 line procedure. And I had to look more than 10 minutes at it, in order to see the AV that happened there. Probably that day my programming skills wasn't at their maximum, but you know, bad thing tend to happen exactly at such days.
Just want to mention other debugging or "code guard" techniques that were not mentioned in previous answers:
"Local" tools:
* Use FastMM in DebugMode - have it write zeros each time it dealocates memory. This will make your program PAINFULLY slow but you have a HUGE chance to find errors like trying to access a freed object.
* Use FreeAndNil(Obj) instead of Obj.Free. Some, people were complaining about it as creating problems but without actually providing a clear example where this might happen. Additionally, Emarcadero recently added the recommendation to use FreeAndNil in their manual (finally!).
* ALWAYS compile the application in Release and Debug mode. Make sure the Project Options are correctly set for debug mode. The DEFAULT settings for Debug mode are NOT correct/complete - at last not in Delphi XE7 and Tokyo. Maybe one day they will set the correct options for Debug mode. So, enable things like:
"Stack frames"
"Map file generation (detailed)"
"Range checking",
"Symbol reference info"
"Debug information"
"Overflow checking"
"Assertions"
"Debug DCUs"
Deactivate the "Compiler optimizations"!
3rd Party Tools:
Use MadShi or EurekaLog (I would recommend MadShi over EurekaLog)
Use Microsoft's ApplicationVerfier
I am working on a Delphi application using the TService functionalities.
It is a large project that was started by someone else.
The application uses several separate threads for processing, communicating with clients, database access, etc. The application’s main job is to poll regularly (every 2-300ms) certain devices and, a couple times a day, execute specific actions.
Now somewhere there is an unhandled exception for which I cannot seem to find the cause:
According to the debugger, the faulting method is System.Classes.StdWndProc.
This also seems to be confirmed by analyzing the crash dump file with WinDbg.
After numerous tests and debugging, I noticed that the crash happened on my dev computer every day at almost the same time.
I looked at the windows log and found this event:
This, coupled with the fact that the stack trace from Delphi indicates that a message with ID=26 (WM_WININICHANGE) was processed, made me believe that there might be something wrong with my usage of FormatDateTime() or DateTimeToStr() when regional settings are reloaded.
I checked every call and made sure to be using the thread-safe overload with a local instance of TFormatSettings.
However today the service crashed again.
A few points that I think are worth mentioning:
The application is also installed on a Windows 2008 server and has
been running OK for over a month.
On 2012r2 I tried forcing DEP off, but it didn’t change anything.
The service’s OnExecute() method is not implemented. I create a base thread in TService. ServiceStart() which then in turn creates the main data module and all the other threads.
The service is not marked as interactive and is executed with the Local System account.
All data modules are created with AOwner=nil.
With a special parameter, the application can be started a normal windowed application with a main form (which is created only in this case). The exception does not seem to happen when running in GUI mode.
Almost all threads have a message pump and use PostThreadMessage() to exchange information. There are no window handle allocations anywhere.
I have checked the whole project and there are no timers or message dialogs or other graphical components anywhere.
I have activated range as well as overflow checking and found no issues.
I am a loss for what to do here. I have checked and re-checked the code several times without finding anything that could explain the error.
Looking online I found several reports that seem to be pertinent to my situation, but none that actually explains what is going on:
https://answers.microsoft.com/en-us/windows/forum/windows_10-other_settings/windows-10-group-policy-application-hang/72016ea4-ba89-4770-b1de-6ddf14b0a51f
https://www.experts-exchange.com/questions/20720591/Prevent-regional-settings-from-changing-inside-a-TService-class.html
https://forums.embarcadero.com/thread.jspa?messageID=832265
Before taking everything apart I would like to know if anyone experienced anything similar or has any tips.
Thanks
Edit: looking at the call stack and the first method executed I am thinking of the TApplication instance that is used in TService.
LPARAM is always 648680.
LPARAM is a pointer to a string (you can cast it to PChar).
You could try to catch WM_SETTINGS_CHANGE and log anytime it's processing.
I think you could use TApplicationEvents component. The component has OnSettingsChange event. The event provides a setting area name (section name) and a flag that points to changed parameter.
Have a look at doc-wiki.
There is a full list of possible parameters.
I did not test it, but maybe you can use Abort procedure in OnSettingsChange event handler to stop the message distribution. Of course it's not a solution, but it may work.
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.
I would like to know if it is possible to nest a dataset within a dataset and then nest this data set with in another dataset. Therfore 3 levels of nesting. Currently I only manage to nest one dataset with in the other. When attemting to nest the third level the database manages to run successfully the first time I compile my program and I am able to enter data. When I then attempt to run the program the second time I an execption raised by EDBClient with message "mismatch in datapacket".
So I would like to know is it possible to nest 3 levels of datasets within each other?
Kind regards
Riaan
Short story:
Try it with Delphi XE... for my nowadays main project this resolved the bug.
Long story:
I faced the same problem you have with 3 or more levels of nested datasets when there's any error on the database side with Delphi 2010.
The previous last version I heavily used was Delphi 2007 without problems, so there's a chance the bad behavior was introduced in Delphi 2009 or Delphi 2010.
I traced this problem down to midas.dll on the client side, and it happens no matter if you're linking midas statically using MidasLib. Midas "thinks" the packet it receives from the server is malformed, and raises the exception. This exception breaks the "normal" error reconcile process, so there's no way to try to recover from an error: OnReconcileError never fired and the process is aborted due to the lack of try/except blocks inside this part of the VCL.
I'm sure it was a bug, but not if it happens on the server or on the client side, When I was working to produce a project to put a support ticket, while trying to reduce it to the minimum possible, it happens Delphi XE was released and I'm under SA, so I get it the last minute.
Download, Install, configure... then, I compiled my to support project and everything worked fine. I compiled my main project: the one where I was facing real problems with the users because of this and the fact I use to raise exceptions in database triggers and stored procedures due to last second validations or state/condition changes. Everything worked fine. The user is receiving meaningful error messages and the application recovered his ability to perform data-transformations and retries on the fly, or to ask the user what to do in some circumstances.
Sorry, I found no workaround during my efforts to diagnose and report this problem to Embarcadero, maybe someone else can help you better without suggesting to upgrade.
Simple answer is yes, you can have three levels of datasets nested within each other. I have examples of ClientDataSets where the nesting goes down 6 levels. In fact, I do not think there is a limit to the depth of nesting, other than that imposed by memory constraints.
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