Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delphi memory leak when adding language

Delphi XE, Windows 7 64-bit

When you add language support to an empty application you will receive a memory leak (FastMM4).

How to reproduce:

  • create new VCL forms Application
  • modify the .dpr and add ReportMemoryLeaksOnShutdown := True;
  • Build/Run the application and close the application -> no leaks reported
  • now add a language (Project -> Languages -> Add)
  • Build/Run again and close the application -> Memory leak??

FastMM4 full debug mode report:

--------------------------------2013/7/16 14:54:34--------------------------------
A memory block has been leaked. The size is: 12

This block was allocated by thread 0x17EC, and the stack trace (return addresses) at the time was:
40455E 
40952D 
4094C8 
409834 
409941 
450058 
74548D76 [Unknown function at FirstHookFunc]
7778FA1A [ZwOpenKey]
75924033 [OpenRegKey]
759240AE [OpenRegKey]
777FA71A [Unknown function at RtlUlonglongByteSwap]

The block is currently used for an object of class: Unknown

The allocation number is: 6

Current memory dump of 256 bytes starting at pointer address 7EF9A610:
6E 00 6C 00 2D 00 42 00 45 00 00 00 41 58 0D 7A 00 00 00 00 C1 A6 F9 7E 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 2E 00 00 00 5E 45 40 00 DD 99 40 00 6D 71 4B 00 98 65 40 00 04 66 40 00
77 A6 40 00 98 7C 4B 00 AA 33 8D 76 F2 9E 7A 77 C5 9E 7A 77 00 00 00 00 EC 17 00 00 EC 17 00 00
1F 9A 40 00 53 7F 42 00 2C 65 40 00 EA 68 40 00 E3 7C 4B 00 AA 33 8D 76 F2 9E 7A 77 C5 9E 7A 77
00 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 B6 5C 27 4D 5C 12 4C 00 80 80 80 80
49 A3 D8 B2 80 80 80 80 00 00 00 00 F9 B7 F9 7E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
65 00 00 00 5E 45 40 00 A7 50 40 00 22 56 40 00 DC 50 40 00 5F 72 4B 00 78 96 44 00 8E 72 4B 00
98 65 40 00 04 66 40 00 77 A6 40 00 98 7C 4B 00 EC 17 00 00 EC 17 00 00 7A 45 40 00 C5 50 40 00
n  .  l  .  -  .  B  .  E  .  .  .  A  X  .  z  .  .  .  .  Á  ¦  ù  ~  .  .  .  .  .  .  .  .
.  .  .  .  .  .  .  .  .  .  .  .  ^  E  @  .  Ý  ™  @  .  m  q  K  .  ˜  e  @  .  .  f  @  .
w  ¦  @  .  ˜  |  K  .  ª  3    v  ò  ž  z  w  Å  ž  z  w  .  .  .  .  ì  .  .  .  ì  .  .  .
.  š  @  .  S    B  .  ,  e  @  .  ê  h  @  .  ã  |  K  .  ª  3    v  ò  ž  z  w  Å  ž  z  w
.  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  ¶  \  '  M  \  .  L  .  €  €  €  €
I  £  Ø  ²  €  €  €  €  .  .  .  .  ù  ·  ù  ~  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .
e  .  .  .  ^  E  @  .  §  P  @  .  "  V  @  .  Ü  P  @  .  _  r  K  .  x  –  D  .  Ž  r  K  .
˜  e  @  .  .  f  @  .  w  ¦  @  .  ˜  |  K  .  ì  .  .  .  ì  .  .  .  z  E  @  .  Å  P  @  .

--------------------------------2013/7/16 14:54:34--------------------------------
This application has leaked memory. The small block leaks are (excluding expected leaks registered by pointer):

5 - 12 bytes: Unknown x 1

Note: Memory leak detail is logged to a text file in the same folder as this application. To disable this memory leak check, undefine "EnableMemoryLeakReporting".

Now to the funny part: remove the language and run again -> the leak stays!

I can remove the leak by deleting all project related files (.dproj, .dproj2007, .dsk and so on..) except the .dpr and .res files.

Can someone explain me what is going on?

UPDATE

Using the addresses from the detail log, it seems I found the leak in System.Pas:

var
  PreferredLanguagesOverride: PChar = nil;

...    
procedure SetLocaleOverride(const NewPreferredLanguages: string);
var
  L: Integer;
begin
  if PreferredLanguagesOverride <> nil then
    FreeMem(PreferredLanguagesOverride);
  L := Length(NewPreferredLanguages);
  if L > 0 then
  begin
    Inc(L);
    GetMem(PreferredLanguagesOverride, L * SizeOf(Char));
    MoveChars(NewPreferredLanguages[1], PreferredLanguagesOverride^, L);
  end;
end;

SetLocaleOverride is called and reserves memory for the PreferredLanguagesOverride PChar. I scanned System.Pas for FreeMem(PreferredLanguagesOverride) but this is the only occurrence!

UPDATE2

I found the reason why delphi calls the SetLocaleOverride routine:

when you add language support, a registry key is created with the name as the executable full path and the current system locale as value: HKEY_CURRENT_USER\Software\Embarcadero\Locales

Deleting this key prevents delphi from calling the SetLocaleOverride routine.

Question:

  • can someone verify if this problem exists in later Delphi versions? (or else I make a QC report)

UPDATE 3

there is already a QC report (105136) and it has been fixed from XE3

Question: can someone show me how this has been patched in XE3?

like image 280
whosrdaddy Avatar asked Jul 16 '13 13:07

whosrdaddy


1 Answers

As already stated in my question, this is fixed from XE3.

For those with lower versions, you can patch System.pas.

Add SetLocaleOverride(''); in the procedure _Halt0 just before the line:

FinalizeUnits;

This will get rid of the memory leak.

Good to know: How to recompile System.pas.

If you don't want to recompile System.pas, you can call SetLocaleOverride(''); in a finalization section.

like image 143
whosrdaddy Avatar answered Oct 16 '22 09:10

whosrdaddy