Блокировка повреждения нижнего колонтитула после освобождения динамического массива
Я сталкиваюсь с этой ошибкой, когда пользователь входит на сервер, а сервер отправляет ответ, связанный с результатом совпадения имени пользователя и пароля. Массив с ответным пакетом вызывает ошибку. Я не знаю, как я могу это исправить, я впервые вижу такую ошибку.
Код
Основной метод
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 Log
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]
1 ответ
Решение
Повреждение нижнего колонтитула является ошибкой FastMM4 FullDebugMode. Это означает, что где-то что-то в вашем коде записывается после конца выделенной памяти. Наверное, лучший кандидат на это любой Move
звонки.
Насколько это воспроизводимо? Если это происходит каждый раз, есть простой способ отследить это:
- Поместите точку останова в строку, где вы размещаете динамический массив (
SetLength
вызов) - Когда вы достигнете этой точки останова, запустите ее (чтобы выполнялся вызов SetLength), а затем нажмите CTRL-F7 (оценить / изменить)
- Используйте оператор @, чтобы получить адрес последнего байта в массиве. (Если массив состоит из 20 элементов, например,
@Reply[19]
.) Это даст вам адрес памяти в шестнадцатеричном формате. Добавьте 1 к этому значению, чтобы получить адрес первого байта за пределами массива. - Перейдите на панель точек останова и щелкните стрелку раскрывающегося списка сбоку кнопки "Добавить точку останова". Добавьте точку останова данных.
- В качестве адреса укажите адрес памяти, который вы только что создали. Для длины, скажем, 1.
- Запустите программу, и когда память в этом месте будет перезаписана, она перестанет работать с отладчиком, и вы сможете увидеть, что ее меняет.