delphi – FastMM4说“块页脚已被破坏”
我在Delphi 7应用程序中有这个功能,在我将FastMM4 v4.99包含在项目中之前一直运行良好.一旦包含,FastMM4引发了以下错误消息:“FastMM在FreeMem操作期间检测到错误.块页脚已损坏.”执行在FreeMem行中停止.
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个字节用于自己的页脚? 更新:经过一天的调试后,我现在相信Delphi 7 TField.GetData方法中存在一个错误.它在分配的内存块之外写入2个零字节.我尝试使用和不使用FastMM4,并在两种情况下都覆盖(因此它不是FastMM4错误).我也尝试将该字段类型化为TVarBytesField,没有区别. 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,True) TField.GetData($7D51F7F0,True) TfrmMain_PBC_TH.btnDEBUGClick($7FF7A380) TControl.Click TButton.Click 解决方法
FastMM在您分配的块的末尾分配一些内存,并在那里写入已知值.然后,当您取消分配时,FastMM会检查这些值是否符合预期.如果没有,那么会出现您看到的错误,因为FastMM知道您的代码正在写入超出内存块的末尾.
因此,try / finally块中的某些内容正在写入超出内存块的末尾.这就是为什么增加它的大小会消除FastMM错误.在没有看到代码的情况下,我们无法确定究竟是什么问题,您需要进行一些调试来解决问题. 你很关心你的“解决方案”.试验和错误绝不是一种合理的编程方式.您必须找出程序在块结束后编写的原因. 一种方法是在该块结束之后立即为地址设置数据断点.这将迫使调试器中断超出块结尾的代码. 顺便说一句,您不需要将第二个参数传递给FreeMem.这样做会使您的代码难以维护并且完全没有用处.只传递指向FreeMem的指针. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |