Memory Leak GETIPFROMHOST
Asked Answered
S

3

7

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.

Stieglitz answered 29/1, 2012 at 3:33 Comment(6)
Is it actually a memory leak, or is your process loading in some libraries?Genie
it is a memory leak. I am using Delphi7. the loop just represents that every time the function is called the memory increases.Stieglitz
I don't know delphi but don't you need to release memory pointed by phe at the end of GetIPFromHost?Abnegate
I tried that but the entire program crashes after FreeandNilStieglitz
@Abnegate no you don't. Nothing to do with Delphi. Read the winsock docs.Coltoncoltsfoot
+1 to counter for anynomous downvoteWalcoff
C
3

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.

Coltoncoltsfoot answered 29/1, 2012 at 11:52 Comment(0)
K
4

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.

Kinghood answered 29/1, 2012 at 12:20 Comment(8)
The code in the question calls WSAStartup. I don't know what point you are making.Coltoncoltsfoot
It's not needed. You can call WSAStartup when your thread starts and then call it again when your thread closes. In this case it's the main thread and finalization code is rather pointless and process termination. It's rather wasteful to be initialising and finalising every time you wish to resolve an host name so the approach used in the code in the Q is better than the code you present. Really, there is no leak here.Coltoncoltsfoot
@DavidHeffernan, read the doc regarding WSACleanup. If you think you know better than what's stated in the official MS docs, I suggest you comment there that WSACleanup is not needed after initiating a WSAStartup.Kinghood
Everyone knows that at process termination time, the OS is going to reclaim resources. So you can call it if you want, but it doesn't hurt not to in the code in the question.Coltoncoltsfoot
+1, lol, possible duplicate of my deleted answer (already commented by David for the same). Still, I can't see any possible leakness, so without OP's cooperation we will just guess.Jehol
@TLama, I haven't seen your post, but it was the first thing that popped out to me, specially when you read: ...and allow the implementation to free any resources allocated on behalf of the application or DLL. Maybe David is right, and there is no leak. But I'm just used to program by the book so to speak.Kinghood
@Jehol Remove the Sleep from the code in the Q. Then run the program. Let it run for 10 minutes. Look at the working set in process explorer. Convince yourself there is no leak. Then replace the body of the while loop with AllocMem(10). See how long that runs before you hit out of memory errors.Coltoncoltsfoot
@David, indeed; even my post begins with I haven't noticed any leak (and since the code from your question is not even compilable I would suspect something else in your real code).Jehol
C
3

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.

Coltoncoltsfoot answered 29/1, 2012 at 11:52 Comment(0)
A
2

This code is working on Delphi XE2 and XE3

Add "Winsock" to uses clause

//function to get the IP Address from a Host
function GetIPFromHost(HostName: string): string;
type
  TaPInAddr = array[0..10] of PInAddr;
  PaPInAddr = ^TaPInAddr;
var
  phe: PHostEnt;
  pptr: PaPInAddr;
  i: Integer;
  GInitData: TWSAData;
begin
  WSAStartup($101, GInitData);
  try
    Result := '';
    phe := GetHostByName(PAnsiChar(AnsiString((HostName))));
    if phe = nil then Exit;
    pPtr := PaPInAddr(phe^.h_addr_list);
    i := 0;
    while pPtr^[i] <> nil do
    begin
      Result := string(inet_ntoa(pptr^[i]^));
      Inc(i);
    end;
  finally
    WSACleanup;
  end;
end;e
Antenna answered 5/6, 2013 at 14:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.