Delphi中的TSocketTransport类中内存泄漏BUG
TSocketTransport.SetConnected
  
  if GetConnected = Value then Exit;
  if Value then  
  begin
      if (FAddress = '') and (FHost = '') then raise ESocketConnectionError.CreateRes(@SNoAddress);
      FClientSocket := TClientSocket.Create(nil);  
      FClientSocket := TClientSocket.Create(nil);  //此处创建的ClientSocket
      FClientSocket.ClientType := ctBlocking;
      FSocket := FClientSocket.Socket;
      FClientSocket.Port := FPort;
      if FAddress <> '' then
        FClientSocket.Address := FAddress else
        FClientSocket.Host := FHost;
      FClientSocket.Open;                            //如果在此处抛出弃常的话不会被释放(TSocketTransport的Destroy过程中也没有释放的代码)
      FClientSocket.Free;
  end else
  begin
    if FSocket <> nil then FSocket.Close;
    FSocket := nil;
    FreeAndNil(FClientSocket);                       //只有此处才有释放的代码,但连接失败后根本就不会运行至此处
    if FEvent <> 0 then WSACloseEvent(FEvent);
    FEvent := 0;
  end;

解决方案 »

  1.   

    不是delphi的bug,而是LZ代码写的有问题,delphi提供了异常处理机制可以完全避免你说的问题。
      

  2.   

    晕。这代码可不是我写的呀,这是Delphi代码库里的代码你去看看SConnect单元吧。
      

  3.   


    if GetConnected = Value then Exit;
      if Value then  
      begin
          if (FAddress = '') and (FHost = '') then raise ESocketConnectionError.CreateRes(@SNoAddress);
          FClientSocket := TClientSocket.Create(nil);  
          FClientSocket := TClientSocket.Create(nil);  //此处创建的ClientSocket
          FClientSocket.ClientType := ctBlocking;
          FSocket := FClientSocket.Socket;
          FClientSocket.Port := FPort;
          if FAddress <> '' then
            FClientSocket.Address := FAddress else
            FClientSocket.Host := FHost;
          FClientSocket.Open;                            //如果在此处抛出弃常的话不会被释放(TSocketTransport的Destroy过程中也没有释放的代码)
          //FClientSocket.Free;此行不是库代码,本人不小心拷错
      end else
      begin
        if FSocket <> nil then FSocket.Close;
        FSocket := nil;
        FreeAndNil(FClientSocket);                       //只有此处才有释放的代码,但连接失败后根本就不会运行至此处
        if FEvent <> 0 then WSACloseEvent(FEvent);
        FEvent := 0;
      end;
      

  4.   

    能发现Delphi Bug的人 佩服
      

  5.   

    修正后的代码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);
        try
          FClientSocket.ClientType := ctBlocking;
          FSocket := FClientSocket.Socket;
          FClientSocket.Port := FPort;
          if FAddress <> '' then
            FClientSocket.Address := FAddress else
            FClientSocket.Host := FHost;
          FClientSocket.Open;
        except
          FClientSocket.Free;
          raise;
        end;
      end else
      begin
        if FSocket <> nil then FSocket.Close;
        FSocket := nil;
        FreeAndNil(FClientSocket);
        if FEvent <> 0 then WSACloseEvent(FEvent);
        FEvent := 0;
      end;
    end;
      

  6.   

    不是吧,这个异常是要你自己在外面加的,你这样加上去,别人以后想怎么判断啊晕这不是BUG。。
      

  7.   

    你试试从类外部去释放一个类内部的私有对象看看,况且我也有将异常抛出,没看到raise;语句吗?
      

  8.   

    To 楼主:
    FClientSocket同一个类成员,如果Open之后发生异常,那么将在下一次Connected的状态改变的时候执行后else的代码.
    包括Destroydestructor TSocketTransport.Destroy;
    begin
      FInterceptor := nil;
      SetConnected(False);
      inherited Destroy;
    end;
      

  9.   

    最简单的测试办法就是在
    FClientSocket := TClientSocket.Create(nil);

    FreeAndNil(FClientSocket);
    设置断点,然后把
    FClientSocket.Open;
    替换成一个:
    Raise Exception.Create('Test Exception');
    试运行一下看.
      

  10.   

    需要注意的是SetConnected是一个Protected方法,而不是public.从而要求调用者必须要遵守相应的资源管理规则.
      

  11.   


    Destroy中的调用SetConnected(false)没有意义
    if GetConnected = Value then Exit; //从这里这就退出了
    因为根本没有连接成功
      

  12.   

    而且每连接失败一次,就会多创建一次,非常的牛,
    这Bug是FastMM检测出来内存泄漏,
    我顺势而找到的。
      

  13.   

    unsigned 谢谢捧场,几乎我每发一贴你都会参与,
    但你几乎都是在质疑我的问题,
    却没有帮我解决过实质上的问题。
      

  14.   

    其实要发现一个BUG并不是那么容易的事情,
    你们所说的方法我几乎都试过了,我也不至于无聊到未确认就来嚷嚷。
    正是这些方法证明了它确实是一个BUG。
    如果你们有什么问题可以自己去测试。
    也许只有自己得到的结果才是最容易让自己相信的。
    不知道为什么,SConnect单元的代码写的很粗造,
    仅这个单元就有不下10个的Bug。
      

  15.   

    不同的版本,都有对其中的问题做修正.部分BUG,可以在QC上找到.
      

  16.   

    要明白的是在这段代码当中不管理FActive这个属性的值,所以对于上一层管理FActive的值时,就需要根据FActive的改变调用SetConnected.否则就会错乱.