Delphi 2009: How do I prevent network application from leaking critical section?
-
26-09-2019 - |
Question
As part of Vista certification, Microsoft wants to make sure that an application exits without holding on to a lock (critical section):
TEST CASE 31. Verify application does not break into a debugger with the specified AppVerifier checks (Req:3.2)
As it turns out, network applications built using Delphi 2009 does break into the debugger, which displays unhelpful message as follows:
(1214.1f10): Break instruction exception - code 80000003 (first chance)
eax=00000001 ebx=07b64ff8 ecx=a6450000 edx=0007e578 esi=0017f7e0 edi=80000003
eip=77280004 esp=0017f780 ebp=0017f7ac iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Windows\SysWOW64\ntdll.dll -
ntdll!DbgBreakPoint:
77280004 cc int 3
After hitting Go button several times, you come across the actual error:
=======================================
VERIFIER STOP 00000212: pid 0x18A4: Freeing virtual memory containing an active critical section.
076CC5DC : Critical section address.
01D0191C : Critical section initialization stack trace.
075D0000 : Memory block address.
00140000 : Memory block size.
=======================================
This verifier stop is continuable.
After debugging it use `go' to continue.
=======================================
Given that my code does not leak TCriticalSection
, how do I prevent Delphi from doing so.
Solution
Indy10 intentionally leaks critical sections upon exit.
IdStack.pas:
finalization
// Dont Free. If shutdown is from another Init section, it can cause GPF when stack
// tries to access it. App will kill it off anyways, so just let it leak
{$IFDEF IDFREEONFINAL}
FreeAndNil(GStackCriticalSection);
{$ENDIF}
IdThread.pas:
finalization
// This call hangs if not all threads have been properly destroyed.
// But without this, bad threads can often have worse results. Catch 22.
// TIdThread.WaitAllThreadsTerminated;
{$IFDEF IDFREEONFINAL}
//only enable this if you know your code exits thread-clean
FreeAndNil(GThreadCount);
{$ENDIF}
- Copy those two files from
%delphi_home%\source\Indy\Indy10\System
and%delphi_home%\source\Indy\Indy10\Core
into your project, or include them in search path. - Rebuild with
IDFREEONFINAL
or remove the IFDEF directives.
OTHER TIPS
How do you know your code is not leaking anything unless you have run with ReportMemoryLeaksOnShutdown := True
or FastMM4 in FullDebugMode
to catch ALL memoryleaks (your code and Delphi libraries)?
Running your app in FullDebugMode would also give you the StackTrace of the unfreed memory allocations.
You will probably find that, indeed, you are leaking the IdStack Critical Section.
You may want to give a look at this CodeRage 2 session: Fighting Memory Leaks for Dummies. It mainly shows how to use FastMM to prevent/detect memory leaks in Delphi. Was for D2007 but still relevant for D2009.