Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Memory Leak GETIPFROMHOST

I have this code right here to retrive the IP-address from a hostname:

program Project1;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  winsock;

function GetIPFromHost(const HostName: string): string;
type
  TaPInAddr = array[0..10] of PInAddr;
  PaPInAddr = ^TaPInAddr;
var
  phe: PHostEnt;
  pptr: PaPInAddr;
  i: Integer;
begin
  Result := '';
  phe := GetHostByName(PChar(HostName));
  if phe = nil then Exit;
  pPtr := PaPInAddr(phe^.h_addr_list);
  i := 0;
  while pPtr^[i] <> nil do
  begin
    Result := inet_ntoa(pptr^[i]^);
    Inc(i);
  end;
end;

var
wsaData: TWSAData;

begin

if (WSAStartup($0202, wsaData) <> 0) then begin
      Exit;
end;

while true do begin
sleep (1000);
GetIPFromHost ('localhost');
end;

it works fine and gives me the IP address. Unfortunately, I need this function a couple of times to compare a DNS with an IP-address.

For some reason I get a big Memory Leak and the memory of my program increases very fast. Why is that and how can I free the memory?

Thanks in advance.

like image 981
Ben Avatar asked Jan 29 '12 03:01

Ben


2 Answers

Here is how GetIPAddress is implemented in JclSysInfo:

function GetIPAddress(const HostName: string): string;
var
  R: Integer;
  WSAData: TWSAData;
  HostEnt: PHostEnt;
  Host: string;
  SockAddr: TSockAddrIn;
begin
  Result := '';
  R := WSAStartup(MakeWord(1, 1), WSAData);
  if R = 0 then
  try
    Host := HostName;
    if Host = '' then
    begin
      SetLength(Host, MAX_PATH);
      GetHostName(PChar(Host), MAX_PATH);
    end;
    HostEnt := GetHostByName(PChar(Host));
    if HostEnt <> nil then
    begin
      SockAddr.sin_addr.S_addr := Longint(PLongint(HostEnt^.h_addr_list^)^);
      Result := inet_ntoa(SockAddr.sin_addr);
    end;
  finally
    WSACleanup;
  end;
end;

Note that you are missing WSACleanup.


An application or DLL is required to perform a successful WSAStartup call before it can use Windows Sockets services. When it has completed the use of Windows Sockets, the application or DLL must call WSACleanup to deregister itself from a Windows Sockets implementation and allow the implementation to free any resources allocated on behalf of the application or DLL.

like image 95
kobik Avatar answered Oct 11 '22 13:10

kobik


This code does not leak. Either your leak detection is faulty, or the code you are actually running is more complex than this and the leak is in the code that you have not shown.

The only memory allocated by the Delphi RTL, in the code in the question, is for the dynamic strings. Delphi dynamic string handling does not leak. The calls to WinSock, gethostbyname and inet_ntoa allocate memory internal to WinSock.

In the case of gethostbyname:

The memory for the hostent structure returned by the gethostbyname function is allocated internally by the Winsock DLL from thread local storage. Only a single hostent structure is allocated and used, no matter how many times the gethostbyaddr or gethostbyname functions are called on the thread. The returned hostent structure must be copied to an application buffer if additional calls are to be made to the gethostbyname or gethostbyaddr functions on the same thread. Otherwise, the return value will be overwritten by subsequent gethostbyname or gethostbyaddr calls on the same thread. The internal memory allocated for the returned hostent structure is released by the Winsock DLL when the thread exits.

And likewise for inet_ntoa:

The string returned by inet_ntoa resides in memory that is allocated by Windows Sockets. The application should not make any assumptions about the way in which the memory is allocated. The string returned is guaranteed to be valid only until the next Windows Sockets function call is made within the same thread.

Whilst it is true that the code in the question does not call WSACleanup that's fine since it is rather pointless to reclaim resources at process termination time.

like image 36
David Heffernan Avatar answered Oct 11 '22 13:10

David Heffernan