I have a complex application that works as expected when compiled normally, but closing a form generates an access violation when compiled using FastMM 4.97 (the latest). The AV occurs when the message dispatching attempts to handle a message meant for a button on the form that has already been destroyed. I also have Eurekalog 6.1.0.1 (the latest) enabled for the project. It doesn't trap any run-time exception when this same code is executed with FastMM's FullDebug mode disabled.
Is it possible that in some situations FastMM can alter the behaviour of the EXE such that it causes, or falsely reports access violations?
Here is the FastMM error report:
--------------------------------2011/3/21 13:30:17--------------------------------
FastMM has detected an attempt to call a virtual method on a freed object. An access violation will now be raised in order to abort the current operation.
Freed object class: TftGenericButton80
Virtual method: Offset +80
Virtual method address: 4A1FF0
The allocation number was: 5628628
The object was allocated by thread 0xE80, and the stack trace (return addresses) at the time was:
403110 [System][@GetMem]
404F03 [System][TObject.NewInstance]
42E85D [FastMM4][CreateComponent]
42EAD9 [FastMM4][TReader.ReadComponent]
42FEE1 [Classes][TReader.ReadValue]
42ED86 [FastMM4][TReader.ReadDataInner]
42ECC5 [FastMM4][TReader.ReadData]
433802 [Classes][TComponent.ReadState]
4A21CE [Controls][TControl.ReadState]
4A5742 [Controls][TWinControl.ReadState]
48BCA0 [Forms][TCustomForm.ReadState]
The object was subsequently freed by thread 0xE80, and the stack trace (return addresses) at the time was:
40313B [System][@FreeMem]
404F21 [System][TObject.FreeInstance]
405339 [System][@ClassDestroy]
8AFBEF [..\..\AdvShapeButton.pas][AdvShapeButton][TAdvCustomShapeButton.Destroy][1422]
4A5601 [Controls][TWinControl.Destroy]
48A9DD [Forms][TScrollingWinControl.Destroy]
48B9D8 [Forms][TCustomForm.Destroy]
48B9F2 [Forms][TCustomForm.Destroy]
404F67 [System][TObject.Free]
A9C42C [..\..\fmWaitingList.pas][fmWaitingList][TfrmWaitingList.OnTanWaitingListItem][130]
A9D41B [fmWaitingListItem.pas][fmWaitingListItem][TfrmWaitingListItem.DoOnTanItem][142]
The current thread ID is 0xE80, and the stack trace (return addresses) leading to this error is:
8B2630 [..\..\AdvShapeButton.pas][AdvShapeButton][TAdvCustomShapeButton.Click][3042]
4A4817 [Controls][TControl.WMLButtonUp]
4A4227 [Controls][TControl.WndProc]
7E42B401 [CallNextHookEx]
7E42B401 [CallNextHookEx]
7E42B372 [MoveWindow]
7E42B317 [MoveWindow]
7E42B326 [MoveWindow]
7E42B326 [MoveWindow]
7E4278D0 [GetWindowTextLengthW]
7E4278E0 [GetWindowTextLengthW]
Current memory dump of 256 bytes starting at pointer address 7FEB5F00:
90 8C AD 00 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80
80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80
80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80
80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80
80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80
80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80
80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80
80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80
Œ . € € € € € € € € € € € € € € € € € € € € € € € € € € € €
€ € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € €
€ € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € €
€ € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € €
€ € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € €
€ € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € €
€ € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € €
€ € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € €
It's not reporting an AV; it's creating a fake AV exception in order to bring your process to a screeching halt, because the road it's on--accessing a deleted object--frequently leads to data corruption, which is even worse.
The problem isn't an access violation; the problem is something is trying to call the Click
method on a button that's already been freed. Just from looking at this stack trace, it looks like you or someone else has a hook installed that's holding a reference to the button and not updating itself appropriately once the form is destroyed. That's where I'd start looking.
A little tricky without being able to see your code. But from the stack traces it looks to me as if you might be destroying a TAdvCustomShapeButton
instance in the middle of processing messages destined for that object.
A good place to start checking should be the method currently hooked to the TfrmWaitingList.OnTanWaitingListItem
event.
You said this occurrs when closing a form.
I'm assuming your form is destroyed (not simply hidden) when closed, so it would in turn destroy all objects owned by the form.
How is the form being closed? You may want to consider Form.Release instead.
I have found FastMM to be exceedingly reliable in this regard.
If you run in release mode you'll have no problems with calling methods on freed objects 99.9% of the time. The 0.1% of the time will invariably occur only on your most valuable customers machine!
So, I'd bet money that this is a problem. It's actually quite easy to track down because FastMM gives you all the call stacks that show exactly how it occurred. You just need to follow through the details carefully.
Now, you may well ask, how can I call a method on an object that has been freed? Well, when you free an object, you return the memory to the memory manager. But the memory manager typically holds on to that memory and waits for an opportune moment to re-use it. Crucially it doesn't immediately return it to the system because doing so is expensive (it takes a significant amount of time).
This is what makes the memory manager fast, but it also leads to errors such as calling methods on free objects being masked. If the memory had been returned to the system then such an action would result in a real access violation. This is what I mean by saying the most of the time, with the memory manager in release mode, such a bug will not surface.
This is one of the best features of FastMM in my view and heeding this warning will save you pain in the future. Trying to track down such a problem in the field is exceedingly difficult. Fixing it with the information FastMM has provided is usually simple.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With