Watch, Follow, &
Connect with Us
Public Report
Report From: Delphi-BCB/Internet/Controls/TClientSocket    [ Add a report in this area ]  
Report #:  93816   Status: Need Feedback
TClientSocket leak when connection fails
Project:  Delphi Build #:  7600
Version:    14.2 Submitted By:   Guy Glirbas
Report Type:  Minor failure / Design problem Date Reported:  5/12/2011 9:40:25 AM
Severity:    Infrequently encountered problem Last Updated: 5/12/2011 8:58:00 PM
Platform:    All platforms Internal Tracking #:  
Resolution: Need More Info (Resolution Comments) Resolved in Build: : None
Duplicate of:  None
Voting and Rating
Overall Rating: No Ratings Yet
0.00 out of 5
Total Votes: None
Description
if FClientSocket.Open fails below (such as the socket server was not running on the target and needed to be restarted), the next attempt to connect will create a new TClientSocket object overriting the pointer to the prior attempt. This reports a memory leak on shutdown.

From SConnect.pas:


procedure TSocketTransport.SetConnected(Value: Boolean);
begin
  if GetConnected = Value then Exit;
  if Value then
  begin
    if (FAddress = '') and (FHost = '') then
      raise ESocketConnectionError.CreateRes(@SNoAddress);
    FClientSocket := TClientSocket.Create(nil);
    FClientSocket.ClientType := ctBlocking;
    FSocket := FClientSocket.Socket;
    FClientSocket.Port := FPort;
    if FAddress <> '' then
      FClientSocket.Address := FAddress else
      FClientSocket.Host := FHost;
    FClientSocket.Open;
  end else
  begin
    if FSocket <> nil then FSocket.Close;
    FSocket := nil;
    FreeAndNil(FClientSocket);
    if FEvent <> 0 then WSACloseEvent(FEvent);
    FEvent := 0;
  end;
end;
Steps to Reproduce:
1) Create a test app with a TSocketConnection and configure it to connect  to a server.
2) Put a button on the test app that attempts to set MySocketconnection.Connected to true.
3) Stop the socket server on the target server.
4) Run the test application and press the button twice.
5) Close the application

Memory Leak report will show a TClientSocket, a TClientWinSocket, a TCriticalSection leak.
Workarounds
None
Attachment
None
Comments

Guy Glirbas at 5/12/2011 12:32:12 PM -
TDataBlocks are also leaking on a failed connection. The TDataBlock created in this function leaks if there is an exeception when opening the socket connection.

function TDataBlockInterpreter.CallCreateObject(Name: string): OleVariant;
var
  Flags: TVarFlags;
  Data: IDataBlock;
begin
  Data := TDataBlock.Create as IDataBlock;
  WriteVariant(Name, Data);
  Data.Signature := CallSig or asCreateObject;
  Data := FSendDataBlock.Send(Data, True);
  Result := ReadVariant(Flags, Data);
end;

The following code removes the leaks which confirms that this is the instance that is leaking, not that I recommend this solution:

function TDataBlockInterpreter.CallCreateObject(Name: string): OleVariant;
var
  Flags: TVarFlags;
  Data: IDataBlock;
begin
  Data := TDataBlock.Create as IDataBlock;
  try
    WriteVariant(Name, Data);
    Data.Signature := CallSig or asCreateObject;
    Data := FSendDataBlock.Send(Data, True);
    Result := ReadVariant(Flags, Data);
  finally
    while (TdataBlock(Data).RefCount > 1) do
      Data._Release;
    Data := nil; // In case there is an exception;
  end;
end;

Tomohiro Takahashi at 5/12/2011 8:57:57 PM -
What version of Delphi do you use, for example Delphi 2010?
And, could you please attach sample project to verify this issue?

Server Response from: ETNACODE01