I believe the issue (if it exists) is with FastMM5. Years ago I delved into FastMM4 and at that time it was the default memory manager for Delphi. When I went looking for this testing project FastMM5 was offered and claimed compatibility and improvements.
I spent some time working out the runtime configuration aspects but settled on a single routine which I now use
Procedure LoadFastMMfromISLib(ADeletePrevLog, AShowViaLog, AShowViaDialog,
AShowViaDebugString,AEnterDebugMode : Boolean = true);
begin
{$IFDEF TestFastMM}
case FastMM_GetInstallationState of
mmisDefaultMemoryManagerInUse:Exit;
{Another third party memory manager has been installed.}
mmisOtherThirdPartyMemoryManagerInstalled:Exit;
{A shared memory manager is being used.}
mmisUsingSharedMemoryManager:Exit;
{This memory manager has been installed.}
mmisInstalled:Begin
if ADeletePrevLog then
FastMM_DeleteEventLogFile;
End;
end;
if AEnterDebugMode then
if FastMM_LoadDebugSupportLibrary then
FastMM_EnterDebugMode;
if AShowViaLog then
FastMM_LogToFileEvents := [
{ Another third party memory manager has already been installed. }
mmetAnotherThirdPartyMemoryManagerAlreadyInstalled,
{ FastMM cannot be installed, because memory has already been allocated through the default memory manager. }
mmetCannotInstallAfterDefaultMemoryManagerHasBeenUsed,
{ When an attempt is made to install or use a shared memory manager, but the memory manager has already been used to
allocate memory. }
mmetCannotSwitchToSharedMemoryManagerWithLivePointers,
{ Details about an individual memory leak. }
mmetUnexpectedMemoryLeakDetail,
{ Summary of memory leaks }
mmetUnexpectedMemoryLeakSummary,
{ When an attempt to free or reallocate a debug block that has already been freed is detected. }
mmetDebugBlockDoubleFree, mmetDebugBlockReallocOfFreedBlock,
{ When a corruption of the memory pool is detected. }
mmetDebugBlockHeaderCorruption, mmetDebugBlockFooterCorruption,
mmetDebugBlockModifiedAfterFree,
{ When a virtual method is called on a freed object. }
mmetVirtualMethodCallOnFreedObject]
Else
FastMM_LogToFileEvents := [];
if AShowViaDialog then
FastMM_MessageBoxEvents :=
[mmetDebugBlockDoubleFree,
mmetDebugBlockReallocOfFreedBlock, mmetDebugBlockHeaderCorruption,
mmetDebugBlockFooterCorruption,
mmetDebugBlockModifiedAfterFree, mmetVirtualMethodCallOnFreedObject,
mmetAnotherThirdPartyMemoryManagerAlreadyInstalled,
mmetCannotInstallAfterDefaultMemoryManagerHasBeenUsed,
mmetCannotSwitchToSharedMemoryManagerWithLivePointers]
Else
FastMM_MessageBoxEvents := [];
if AShowViaDebugString then
FastMM_OutputDebugStringEvents :=
[mmetDebugBlockDoubleFree,
mmetDebugBlockReallocOfFreedBlock, mmetDebugBlockHeaderCorruption, mmetDebugBlockFooterCorruption,
mmetDebugBlockModifiedAfterFree, mmetVirtualMethodCallOnFreedObject, mmetAnotherThirdPartyMemoryManagerAlreadyInstalled,
mmetCannotInstallAfterDefaultMemoryManagerHasBeenUsed, mmetCannotSwitchToSharedMemoryManagerWithLivePointers]
else
FastMM_OutputDebugStringEvents := [];
ReportMemoryLeaksOnShutDown:=true;
{$Endif}
end;
In the test program demonstrating the error there is no reference to anything other than VCL Forms and the FastMM5 code.
Not sure whether Delphi now uses FastMM5 or FastMM4 or its own memory manager by default but I am (normally) very happy using FastMM5 while testing for leaks and memory errors. I use the Delphi default for release.
If I get a “virtual method was called on a freed object” error in future I will try changing the variable name before spending hours searching for a buried free.