当用户登录服务器,服务器发送与用户名/密码匹配结果相关的响应时,我遇到了这个错误。包含回复数据包的数组导致错误。我不知道该如何修复,这是我第一次看到这样的错误。
代码
主要方法
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]
块页脚损坏是FastMM4 FullDebugMode错误。这意味着在某个地方,代码中的某些内容正在写入超过分配内存的末尾。可能最好的候选者是任何Move
调用。
这有多大的可重复性?如果每次都发生这种情况,有一种简单的方法可以追踪:
- 在分配动态数组的行上放置一个断点(
SetLength
调用) - 当您到达该断点时,运行它(这样SetLength调用就会运行),然后点击CTRL-F7(Evaluate/modify)
- 使用@运算符获取数组中最后一个字节的地址。(例如,如果数组有20个元素长,请计算
@Reply[19]
。)这将为您提供一个十六进制的内存地址。将该值加1可获得超出数组边界的第一个字节的地址 - 转到"断点"窗格,然后单击"添加断点"按钮一侧的下拉箭头。添加数据断点
- 对于地址,请给出您刚刚想到的内存地址。对于"长度",请说1
- 运行该程序,当该位置的内存被覆盖时,它将中断到调试器,您将能够看到是什么在改变它