0

当用户登录服务器并且服务器发送与用户名/密码匹配结果相关的响应时,我遇到了这个错误。具有回复数据包的数组导致错误。我不知道如何解决这个问题,这是我第一次看到这样的错误。

代码

主要方法

procedure TAgUDP.ProcessLoginPacket
          ( const APacket : TBytes; const ABinding : TIdSocketHandle );
var
  Username : String;
  Password : String;
  Index    : WORD;
  ID       : TGUID;
  Reply    : TBytes;
  Peer     : TAgUDPSPeer;

begin

  // Extracting Username
  SetLength ( Username, APacket [LI_LNUN] );
  Index := 5 + HEADER_END + ( APacket [LI_LNIP] * 2 );
  Move  ( APacket [Index], Username [1], APacket [LI_LNUN] * 2 );

  // Checking whether the peer is already connected
  if not Assigned ( fClientsList.FindPeer ( Username )) then
  begin

    // Extracting Password
    SetLength ( Password, APacket [LI_LNPW] );
    Index := Index + ( APacket [LI_LNUN] * 2 );
    Move  ( APacket [Index], Password [1], APacket [LI_LNPW] * 2 );

    // Creating Peer Object
    CreateGUID ( ID );
    Peer :=
    TAgUDPSPeer.Create ( ABinding.PeerIP, ABinding.PeerPort, ID, Self );

    // Checking whether the database has a record of the user
    if fOnLogin ( Peer, Username, Password, Reply ) then
    begin

      // Assigning username and adding to connected clients list
      Peer.fName := Username;
      fClientsList.Add ( Peer );

      // Extracting local ip+port pair
      SetLength ( Peer.fLIP,  APacket [LI_LNIP] );
      Move  ( APacket [LI_PORT], Peer.fLPort,   2 );
      Move  ( APacket [LI_IPST], Peer.fLIP [1], APacket [LI_LNIP] * 2 );

      // -----------------------------------------------------------------------
      // Building login reply packet

      Index := StrSize ( Peer.fIP ) + HEADER_END + 3;
      SetLength ( Reply, Index + Length ( Reply ));
      Move ( Reply [0], Reply [Index], Length ( Reply ) - Index );

      Reply [0] := Byte ( AgOp_LoginReply );
      Move ( fID,      Reply [HEADER_SID], 16 );
      Move ( Peer.fID, Reply [HEADER_RID], 16 );

      Reply [LR_LNIP] := Length ( Peer.fIP );
      Move ( Peer.fPort,   Reply [LR_PORT], 2 );
      Move ( Peer.fIP [1], Reply [LR_IPST], Length ( Reply ) - 3 );

      SendBuffer ( ABinding.PeerIP, ABinding.PeerPort, Reply );

    end
    else
    begin

      // Building login reply packet - for login rejection

      Peer.Free;
      SetLength ( Reply, 35 );
      Reply [0] := Byte ( AgOp_LoginReply );
      SendBuffer ( ABinding.PeerIP, ABinding.PeerPort, Reply );;

    end;

  end;
  // Deliberate freeing of the array to make the debugger stop after this, after exception otherwise it stops after end
  SetLength ( Reply, 0 );

end;

fOnLogin 方法

function  TNetworkModule.OnLogin
          ( const APeer: TAgUDPSPeer; const AUsername, APassword: String;
            var ABuffer: TBytes ): Boolean;
var
  DS      : TSQLDataset;
  Profile : TUser;
begin

  DS := TSQLDataSet.Create ( nil );
  DS.SQLConnection := DBConnection;
  DS.CommandText   :=
  'SELECT user_id,rating,clan '+
  'FROM users '+
  'WHERE username='''+ AUsername +''' AND password='''+ APassword +'''';
  DS.Open;
  Result  := not DS.Eof;

  if Result then
  begin

    fLog.Log( ['Event'],
              ['A login request has been accepted. Username: '+ AUsername] );

    // Storing user information
    Profile := TUser.Create ( APeer, DS.Fields [0].AsInteger,
                              DS.Fields [1].AsInteger, DS.Fields [2].AsString );

    // Adding user to lobby
    fHall.AddUser ( Profile );

    // Making a packet to have additional information of the user to be transmitted to
    // it in the login reply packet 
    SetLength ( ABuffer, 4 + StrSize ( Profile.Clan ));
    Move ( Profile.Rating, ABuffer [0], 4 );
    Move ( Profile.Clan,   ABuffer [4], Length ( ABuffer ) - 4 );

  end
  else
    fLog.Log( ['Event'],
              ['A login request has been denied. Username: '+ AUsername] );

  DS.Close;
  DS.Free;

end;

FastMM 日志

FastMM has detected an error during a FreeMem operation. The block footer has been corrupted. 

The block size is: 68

This block was allocated by thread 0x9C, and the stack trace (return addresses) at the time was:
419E3E [FastMM4.pas][FastMM4][DebugReallocMem$qqrpvi][8935]
40692F [System.pas][System][@ReallocMem$qqrrpvi][4325]
40C165 [System.pas][System][DynArraySetLength$qqrrpvpvipi][31888]
40C296 [System.pas][System][@DynArraySetLength$qqrv][31967]
A4B26B [AgUDPServer.pas][AgUDPServer][TAgUDP.ProcessLoginPacket$qqrx25System.%DynamicArray$tuc%xp30Idsockethandle.TIdSocketHandle][872]
A4BF94 [AgUDPServer.pas][AgUDPServer][TAgUDP.DoUDPRead$qqrp32Idudpserver.TIdUDPListenerThreadx25System.%DynamicArray$tuc%p30Idsockethandle.TIdSocketHandle][1247]
A486A0 [IdUDPServer.pas][IdUDPServer][TIdUDPListenerThread.UDPRead$qqrv][415]
A485E4 [IdUDPServer.pas][IdUDPServer][TIdUDPListenerThread.Run$qqrv][392]
A466D8 [IdThread.pas][IdThread][TIdThread.Execute$qqrv][363]
484E7D [System.Classes.pas][System.Classes][Classes.ThreadProc$qqrp22System.Classes.TThread][14569]
409F9E [System.pas][System][ThreadWrapper$qqspv][21627]

The block was previously used for an object of class: TDBXDynalinkConnection

The block is currently used for an object of class: Unknown

The allocation number is: 182223

The block was previously freed by thread 0x9C, and the stack trace (return addresses) at the time was:
40690E [System.pas][System][@FreeMem$qqrpv][4251]
4082FD [System.pas][System][TObject.FreeInstance$qqrv][14978]
408A8D [System.pas][System][@ClassDestroy$qqrxp14System.TObject][16273]
AF0F57 [Data.DBXCommon.pas][Data.DBXCommon][Dbxcommon.TDBXConnection.$bdtr$qqrv][8476]
4083FB [System.pas][System][TObject.Free$qqrv][15046]
B6E0A3 [Data.SqlExpr.pas][Data.SqlExpr][Sqlexpr.TSQLConnection.DoDisconnect$qqrv][2563]
A77FE5 [Data.DB.pas][Data.DB][Db.TCustomConnection.SetConnected$qqro][3405]
A77F6F [Data.DB.pas][Data.DB][Db.TCustomConnection.Close$qqrv][3386]
B6D010 [Data.SqlExpr.pas][Data.SqlExpr][Sqlexpr.TSQLConnection.$bdtr$qqrv][2217]
4083FB [System.pas][System][TObject.Free$qqrv][15046]
B7181C [Data.SqlExpr.pas][Data.SqlExpr][Sqlexpr.TCustomSQLDataSet.InternalFreeCommand$qqrv][4046]

The current thread ID is 0x9C, and the stack trace (return addresses) leading to this error is:
40690E [System.pas][System][@FreeMem$qqrpv][4251]
40C3EA [System.pas][System][@DynArrayClear$qqrrpvpv][32152]
40C085 [System.pas][System][DynArrayClear$qqrrpvpv][31815]
40C0C1 [System.pas][System][DynArraySetLength$qqrrpvpvipi][31839]
40C296 [System.pas][System][@DynArraySetLength$qqrv][31967]
A4B3FC [AgUDPServer.pas][AgUDPServer][TAgUDP.ProcessLoginPacket$qqrx25System.%DynamicArray$tuc%xp30Idsockethandle.TIdSocketHandle][904]
A4BF94 [AgUDPServer.pas][AgUDPServer][TAgUDP.DoUDPRead$qqrp32Idudpserver.TIdUDPListenerThreadx25System.%DynamicArray$tuc%p30Idsockethandle.TIdSocketHandle][1247]
A486A0 [IdUDPServer.pas][IdUDPServer][TIdUDPListenerThread.UDPRead$qqrv][415]
A485E4 [IdUDPServer.pas][IdUDPServer][TIdUDPListenerThread.Run$qqrv][392]
A466D8 [IdThread.pas][IdThread][TIdThread.Execute$qqrv][363]
484E7D [System.Classes.pas][System.Classes][Classes.ThreadProc$qqrp22System.Classes.TThread][14569]
4

1 回答 1

6

块页脚损坏是 FastMM4 FullDebugMode 错误。这意味着在某处,您的代码中的某些内容正在写入超过分配内存的末尾。可能最好的候选人是任何Move电话。

这有多可复制?如果它每次都发生,有一种简单的方法可以追踪它:

  • SetLength在分配动态数组的行(调用)处放置一个断点
  • 当您到达该断点时,运行它(因此 SetLength 调用运行),然后按 CTRL-F7(评估/修改)
  • 使用 @ 运算符获取数组中最后一个字节的地址。(例如,如果数组有 20 个元素长,请评估@Reply[19]。)这将为您提供十六进制的内存地址。将此值加 1 以获得超出数组边界的第一个字节的地址。
  • 转到 Breakpoints 窗格,然后单击 Add Breakpoint 按钮侧面的下拉箭头。添加数据断点。
  • 对于地址,请给出您刚刚提出的内存地址。对于长度,例如 1。
  • 运行程序,当该位置的内存被覆盖时,它将中断调试器,您将能够看到发生了什么变化。
于 2013-11-25T13:32:02.940 回答