2012-04-26 8 views
5

Delphi 7アプリケーションでこの機能を使用していますが、これはFastMM4 v4.99をプロジェクトに組み込むまでうまく機能しました。 FastMM4が含まれると、次のエラーメッセージが表示されます。「FreeMem操作中にFastMMでエラーが検出されました。ブロックフッターが壊れています。」実行はFreeMem行で停止します。FastMM4は "ブロックフッタが壊れています"

function BinaryFieldToArrayOfWord(aBinaryField : TVarBytesField; 
            out aArrValues : TArrWord) : Boolean; 
var 
    p : Pointer; 
begin 
    if not aBinaryField.IsBlob then 
    begin 
    GetMem(p, aBinaryField.DataSize);  
    try 
     if aBinaryField.GetData(p) then   
     begin 
     // do something 
     end; 
    finally 
     FreeMem(p, aBinaryField.DataSize); 
    end; 
    end; // if 
end; 

最初に私は機能にバグが存在しなければならないと思ったが、それは、Delphi 7ヘルプでこのTField.GetData方法の一例として、実質的に同じである:

{ Retrieve the "raw" data from Field1 } 
with Field1 do 
begin 
    if not IsBlob { this does not work for BLOB fields } 
    begin 
    { Allocate space } 
    GetMem(MyBuffer, DataSize); 
    try 
     if not GetData(MyBuffer) then 
     MessageDlg(DisplayName + ' is NULL', mtInformation, [mbOK], 0) 
     else 
     { Do something with the data }; 
    finally 
     { Free the space } 
     FreeMem(MyBuffer, DataSize); 
    end; 
    end; 
end; 

私はで見つけ上記のエラーメッセージは、データのための十分なスペースがないために頻繁に発生することがあります。だから、私はメモリブロックのサイズを増やし、エラーメッセージは消え、機能は期待通りに機能しました。いくつかの実験の後、私は2つのバイトが必要であることを考え出したとの十分な:

GetMem(p, aBinaryField.DataSize + 2); 

    FreeMem(p, aBinaryField.DataSize + 2); 

それは私の問題を解決しますが、私はその背景を知らないと、私はこのソリューションで完全にリラックスしていないです。このメッセージの理由を知ることはうれしいことです。 FastMM4はそれ自身のフッタのために追加の2バイトを必要としますか?

アップデート:デバッグをして1日を過ごした後、私は現在、Delphi 7 TField.GetDataメソッドにバグがあると考えています。それは割り当てられたメモリブロックを超えて2ゼロバイトを書き込む。 FastMM4の有無にかかわらず試してみましたが、どちらの場合も上書きされます(FastMM4エラーではありません)。私はTVarBytesFieldとしてフィールドを型キャストしてみましたが、違いはありません。 詳細なコメントとともに使用したコードです。その結果は次のとおりです。 私の唯一の残りの質問:後のDelphisでこのバグを修正しましたか?データブレークポイント、コールスタックを追加した後

procedure TfrmMain_PBC_TH.btnDEBUGClick(Sender: TObject); 
    type 
    TArrBytes = array of Byte; 
    var 
    p  : Pointer; 
    qryTest : TADOQuery; 
    begin 
    qryTest := TADOQuery.Create(Application); 
    try 
     // The type of the TQM_BinaryData.BinData column in the MSSQL database is a  varbinary(7900). 
     // Load the #168 binary data record. It contains exactly 7900 bytes, and the value of each byte is 255 
     qryTest.Connection := MainConn; 
     qryTest.SQL.Add('SELECT [BinData] FROM [TQM_BinaryData] WHERE [Id] = 168'); 
     qryTest.Open; 

     // Allocate the memory block for this. 
     GetMem(p, qryTest.FieldByName('BinData').DataSize); 
     // DataSize is 7902 because all TVarBytesFields have 2 byte prefix in Delphi, containing the data length. 
     // So the size of the allocated memory block is 7902 bytes - we are correct so far. 
     try 
     // Values of the first four bytes beyond the end of the memory block (memory thrash at this point) before GetData: 
     // TArrBytes(p)[7902] = 96 
     // TArrBytes(p)[7903] = 197 
     // TArrBytes(p)[7904] = 219 
     // TArrBytes(p)[7905] = 43 

     // Critical point: get the data from the field with the Delphi GetData method 
     qryTest.FieldByName('BinData').GetData(p); 

     // Values after GetData: 
     // TArrBytes(p)[0] = 220 TArrBytes(p)[0] and TArrBytes(p)[1] contains the length of the binary data 
     // TArrBytes(p)[1] = 30  it is correct as 30 * 256 + 220 = 7900 
     // TArrBytes(p)[2] = 255 actual data starts 
     // TArrBytes(p3[2] = 255  
     // ... 
     // TArrBytes(p)[7900] = 255 
     // TArrBytes(p)[7901] = 255 actual data ends 
     // TArrBytes(p)[7902] = 0  changed from 96! 
     // TArrBytes(p)[7903] = 0  changed from 197! 
     // TArrBytes(p)[7904] = 219 no change 
     // TArrBytes(p)[7905] = 43  no change 
     finally 
     // Here FastMM4 throws the block footer corrupt error because GetData modified the 2 bytes after the allocated memory block 
     FreeMem(p); 
     end; 

     qryTest.Close; 
    finally 
     qryTest.Free; 
    end; 
    end; 

は次のとおりです。

@FillChar(???,???,???) 
    TDataSet.DataConvert($7D599770,$12F448,$7D51F7F0,True) 
    VarToBuffer 
    TCustomADODataSet.GetFieldData($7D599770,$7D51F7F0,True) 
    TField.GetData($7D51F7F0,True) 
    TfrmMain_PBC_TH.btnDEBUGClick($7FF7A380) 
    TControl.Click 
    TButton.Click 

答えて

5

FastMMを使用すると、割り当てブロックの最後にいくつかのメモリを割り当て、そこに既知の値を書き込みます。次に、割り当てを解除すると、FastMMはそれらの値が期待どおりであることを確認します。そうでない場合、FastMMはコードがメモリブロックの終わりを超えて書き込み中であることを認識しているので、表示されるエラーが発生します。

try/finallyブロック内の何かがメモリブロックの終わりを超えて書き込みを行っています。そのため、サイズを大きくするとFastMMエラーが取り除かれます。そのコードを見ることなく、正確に何が間違っているのかを知ることはできず、問題を解決するためにデバッグを行う必要があります。

「解決策」に心配するのは間違いありません。試行錯誤は決して合理的な方法ではありません。ブロックの最後を越えてプログラムが書いている理由を知る必要があります。

これを行う1つの方法は、このブロックの終わりをすぐに越えてアドレスのデータブレークポイントを設定することです。そうすれば、デバッガはブロックの終わりを超えて書き込むコードを壊すことになります。

脇に、2番目のパラメータをFreeMemに渡す必要はありません。そうすることで、コードを保守するのが難しくなり、目的はまったくありません。 FreeMemへのポインタだけを渡します。

+0

デバッグ中に、try/finallyとaBinaryField.GetData(p)の行を除いてコメントアウトしたので、最終的なコードは上記のようになりました。 FreeMemから2番目のパラメータを削除しても、この問題は解決されませんでした。しかし、FastMMが割り当てられたメモリブロックの最後にいくつかの既知の値を書き込んだ後、ブロックを別のデータで完全に埋めると(GetDataはこのIMHOを行います)、割り当てられたブロックのみを使用しても既知の値が上書きされます、 ではない?したがって、+ 2バイトはFastMMの既知の値です。 – Almandine

+0

私はFreeMemの第2パラメータが問題を解決するとは言わず、単にそれを渡すのは無意味でした。ブロックの終わりを超えて何かが書いている。 –

+0

"しかし、FastMMが割り当てられたメモリブロックの最後にいくつかの既知の値を書き込んだ後、ブロックを別のデータで完全に埋めると(GetDataはこのIMHOを実行します)、既知の値は上書きされます。割り当てられたブロック、isntそれ?あんまり。何が起こるかは、たとえば、10バイトを要求しますが、FastMMは、例えば、14を割り当てます。このブロックの先頭へのポインタは10バイトであると考えられますが、最後に余分な4バイトに既知の値が書き込まれます。それらを上書きすると、FastMMはバグを発見しました。終わりを超えて何かが書いている。 –

関連する問題