Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Wie Speicherleck beheben (GetWindowsLanguage)? (https://www.delphipraxis.net/204861-wie-speicherleck-beheben-getwindowslanguage.html)

BlueStarHH 8. Jul 2020 10:34

Wie Speicherleck beheben (GetWindowsLanguage)?
 
Hallo,

ich ermittele die "Language ID" (Sprache von Windows) mit diesem Code:

Delphi-Quellcode:
function GetWindowsLanguage(LCTYPE: LCTYPE {type of information}): string;
var
  Buffer : PChar;
  Size : integer;
begin
  Size := GetLocaleInfo (LOCALE_USER_DEFAULT, LCType, nil, 0);
  GetMem(Buffer, Size);
  try
    GetLocaleInfo (LOCALE_USER_DEFAULT, LCTYPE, Buffer, Size);
    Result := string(Buffer);
  finally
    FreeMem(Buffer); <-- Speicherleck hier
  end;
end;

Aufruf mit:
GetWindowsLanguage(LOCALE_ILANGUAGE);
gefunden unter https://www.swissdelphicenter.ch/de/showcode.php?id=320

Nun habe ich FastMM5 eingebunden und der zeigt an, dass es ein Speicherleck gibt:
Code:
---------------------------
Memory Corruption Detected
---------------------------
A memory block footer has been corrupted.
The block size is 5.
The block was allocated by thread 0x1C3C, and the stack trace (return addresses) at the time was:

00425680 [FastMM5.pas][FastMM5][FastMM_DebugGetMem_GetDebugBlock][7292]
004256FB [FastMM5.pas][FastMM5][FastMM_DebugGetMem][7315]
0040755E [System][System][@GetMem]
00BF9A33 [test.pas][test][GetWindowsLanguage][20235]
....
The allocation number is: 51923

Current memory dump of 13 bytes starting at pointer address 8333020:
30 00 34 00 30 00 37 00 00 00 80 80 80
0  . 4  . 0  . 7  . . . . . .

Wie kann ich das beheben?

Dalai 8. Jul 2020 10:59

AW: Wie Speicherleck beheben (GetWindowsLanguage)?
 
Da steht nichts von Speicherleck (Memory leak) sondern was von Speicherkorrumpierung (Memory Corruption).

Das liegt mit Sicherheit daran, dass der Größenparameter bei GetMem in Bytes anzugeben ist, GetLocaleInfo aber die Anzahl Zeichen zurückgibt. Du musst also deinen Buffer mit der Größe von Char multiplizieren:
Delphi-Quellcode:
GetMem(Buffer, Size * SizeOf(Char));
_
Nur nebenbei: MS schreibt zu GetLocaleInfoEx:
Zitat:

Starting with Windows Vista, your applications should not use LOCALE_ILANGUAGE in the LCType parameter to avoid failure or retrieval of unexpected data. Instead, it is recommended for your applications to call GetLocaleInfoEx.
Ist völlig bescheuert, dass die schreiben, man solle genau diese Funktion rufen, aber das wird wohl ein Dokumentationsfehler sein.

Grüße
Dalai

Sinspin 8. Jul 2020 11:02

AW: Wie Speicherleck beheben (GetWindowsLanguage)?
 
Hallo,
ich würde nachsehen was Windows für eine maximale Länge für den String angibt und mit einem Array fester länge arbeiten.

Delphi-Quellcode:
var
  buffer: array[0..MaxBufferLength] of PChar;
begin
  GetLocaleInfo (LOCALE_USER_DEFAULT, LCTYPE, buffer, SizeOf(buffer));
  Result := string(buffer);
end;

Der schöne Günther 8. Jul 2020 11:06

AW: Wie Speicherleck beheben (GetWindowsLanguage)?
 
Wenn, dann aber Array of Char, und nicht PChar, oder?

Jedenfalls ist es das was System.SysUtils auch macht:

Delphi-Quellcode:
function GetLocaleStr(Locale, LocaleType: Integer; const Default: string): string;
{$IFDEF MSWINDOWS}
var
  L: Integer;
  Buffer: array[0..255] of Char;
begin
  L := GetLocaleInfo(Locale, LocaleType, Buffer, Length(Buffer));
  if L > 0 then SetString(Result, Buffer, L - 1) else Result := Default;
end;
{$ENDIF MSWINDOWS}

himitsu 8. Jul 2020 11:07

AW: Wie Speicherleck beheben (GetWindowsLanguage)?
 
Statt sowas wie GetMem verwende ich gern SetLength mit einem TBytes. (falls ich das statische Array nicht auf dem Stack liegen haben möchte, siehe Sinspin, bzw. wenn es eine dynamische Länge hat)
Vorteile:
* der Speicher wird automatisch freigegeben
* und er Debugger hat einen Standard-Viewer für diesen Typen (dynamische Arrays)

BlueStarHH 8. Jul 2020 12:10

AW: Wie Speicherleck beheben (GetWindowsLanguage)?
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1469079)
Wenn, dann aber Array of Char, und nicht PChar, oder?

Jedenfalls ist es das was System.SysUtils auch macht:

Delphi-Quellcode:
function GetLocaleStr(Locale, LocaleType: Integer; const Default: string): string;
{$IFDEF MSWINDOWS}
var
  L: Integer;
  Buffer: array[0..255] of Char;
begin
  L := GetLocaleInfo(Locale, LocaleType, Buffer, Length(Buffer));
  if L > 0 then SetString(Result, Buffer, L - 1) else Result := Default;
end;
{$ENDIF MSWINDOWS}

Danke, so klappt es!

Sinspin 8. Jul 2020 16:43

AW: Wie Speicherleck beheben (GetWindowsLanguage)?
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1469079)
Wenn, dann aber Array of Char, und nicht PChar, oder?

Jawoll, auf jeden Fall kein _P_...! Danke fürs aufpassen :thumb:


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:33 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz