Блокировка повреждения нижнего колонтитула после освобождения динамического массива

Я сталкиваюсь с этой ошибкой, когда пользователь входит на сервер, а сервер отправляет ответ, связанный с результатом совпадения имени пользователя и пароля. Массив с ответным пакетом вызывает ошибку. Я не знаю, как я могу это исправить, я впервые вижу такую ​​ошибку.

Код

Основной метод

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.
  • Запустите программу, и когда память в этом месте будет перезаписана, она перестанет работать с отладчиком, и вы сможете увидеть, что ее меняет.
Другие вопросы по тегам