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
デバッグ中に、try/finallyとaBinaryField.GetData(p)の行を除いてコメントアウトしたので、最終的なコードは上記のようになりました。 FreeMemから2番目のパラメータを削除しても、この問題は解決されませんでした。しかし、FastMMが割り当てられたメモリブロックの最後にいくつかの既知の値を書き込んだ後、ブロックを別のデータで完全に埋めると(GetDataはこのIMHOを行います)、割り当てられたブロックのみを使用しても既知の値が上書きされます、 ではない?したがって、+ 2バイトはFastMMの既知の値です。 – Almandine
私はFreeMemの第2パラメータが問題を解決するとは言わず、単にそれを渡すのは無意味でした。ブロックの終わりを超えて何かが書いている。 –
"しかし、FastMMが割り当てられたメモリブロックの最後にいくつかの既知の値を書き込んだ後、ブロックを別のデータで完全に埋めると(GetDataはこのIMHOを実行します)、既知の値は上書きされます。割り当てられたブロック、isntそれ?あんまり。何が起こるかは、たとえば、10バイトを要求しますが、FastMMは、例えば、14を割り当てます。このブロックの先頭へのポインタは10バイトであると考えられますが、最後に余分な4バイトに既知の値が書き込まれます。それらを上書きすると、FastMMはバグを発見しました。終わりを超えて何かが書いている。 –