Listen to the Memory Manager
Let's say you have a nice, working Delphi application. One fine day, for no reason
whatsoever, you decide to run your fine and bug free application with FastMM in
full debug mode. Just for fun... and suddenly, out of the blue, the app starts
crashing with an AV reading of address 0x80808088. What is going on... ????
When a seemingly working application suddenly starts misbehaving, the first instinct would be to look at the latest code change in searching for clues. In the above case, the only change was turning on FastMM debug mode. Could this be a bug in FastMM?
While all software has bugs and it is perfectly possible that FastMM has bugs, too, it is highly unlikely that this is FastMM's fault.
If turning on the
One of the "problems" with
However, it is often forgotten that in such cases
The following is a very simple test case that will blow up with FastMM in debug mode:
Since the interface reference
If that interface reference is cleared before the component instance is released, the code will work properly.
While code accessing a released object instance may work properly because remnants of the object are still sitting in memory and nothing bad actually happens, such code can just as easily cause memory corruption and subtle bugs, if the memory where a particular object instance was occupying was reused for something else in the meantime.
When a seemingly working application suddenly starts misbehaving, the first instinct would be to look at the latest code change in searching for clues. In the above case, the only change was turning on FastMM debug mode. Could this be a bug in FastMM?
While all software has bugs and it is perfectly possible that FastMM has bugs, too, it is highly unlikely that this is FastMM's fault.
If turning on the
CatchUseOfFreedInterfaces
define in FastMM configuration shows
an attempt to use an interface on a freed object, you have found the culprit. It may
require further debugging and inspecting the code, but at least you will know
what to look for.One of the "problems" with
TComponent
(and subsequently its descendants,
including all visual controls in the VCL and FMX frameworks) is that it implements
interfaces, but has reference counting disabled in the _AddRef
and _Release
methods so that it can be used like a regular class.However, it is often forgotten that in such cases
_AddRef
and _Release
calls, even though they don't do any actual counting, will still be inserted by
the compiler and called for any interface reference to such an object instance. So if
there is an alive interface reference to the object after calling Free
, that
interface reference will contain a dangling pointer and when it goes out of scope,
_Release
will be called on an already nuked object. While you may get away with
such a call without FastMM in debugging mode, if it is turned on it will correctly
identify the problem.The following is a very simple test case that will blow up with FastMM in debug mode:
procedure TestComponent;
var
Comp: TComponent;
Intf: IInterface;
begin
Comp := TComponent.Create(nil);
Intf := Comp;
Comp.Free;
end;
Since the interface reference
Intf
is automatically managed, it will go out of
scope (and invoke the reference counting mechanism) in the epilogue of
the TestComponent
procedure, invoking _Release
on the Comp
object instance,
which had already been released.If that interface reference is cleared before the component instance is released, the code will work properly.
procedure TestComponent;
var
Comp: TComponent;
Intf: IInterface;
begin
Comp := TComponent.Create(nil);
Intf := Comp;
....
Intf := nil;
Comp.Free;
end;
While code accessing a released object instance may work properly because remnants of the object are still sitting in memory and nothing bad actually happens, such code can just as easily cause memory corruption and subtle bugs, if the memory where a particular object instance was occupying was reused for something else in the meantime.
Comments
Post a Comment