Rol*_*son 5 delphi heap memory-corruption vmt bold-delphi
我是一个使用Delphi 2007用于更大应用程序的团队的成员,我们怀疑堆损坏,因为有时会有奇怪的错误,没有其他解释.我相信编译器的Rangechecking选项仅适用于数组.我想要一个工具,当存储器地址没有被应用程序分配时,它会发出异常或日志.
问候
编辑:错误类型:
错误:模块"BoatLogisticsAMCAttracsServer.exe"中地址00404E78处的访问冲突.读取地址FFFFFFDD
EDIT2:感谢所有建议.不幸的是,我认为解决方案比这更深.我们使用补丁版本的Bold for Delphi,因为我们拥有源代码.可能在Bold框架中引入了一些错误.是的,我们有一个带有由JCL处理的callstack的日志以及跟踪消息.所以带异常的callstack可以像这样锁定:
20091210 16:02:29 (2356) [EXCEPTION] Raised EBold: Failed to derive ServerSession.mayDropSession: Boolean
OCL expression: not active and not idle and timeout and (ApplicationKernel.allinstances->first.CurrentSession <> self)
Error: Access violation at address 00404E78 in module 'BoatLogisticsAMCAttracsServer.exe'. Read of address FFFFFFDD. At Location BoldSystem.TBoldMember.CalculateDerivedMemberWithExpression (BoldSystem.pas:4016)
Inner Exception Raised EBold: Failed to derive ServerSession.mayDropSession: Boolean
OCL expression: not active and not idle and timeout and (ApplicationKernel.allinstances->first.CurrentSession <> self)
Error: Access violation at address 00404E78 in module 'BoatLogisticsAMCAttracsServer.exe'. Read of address FFFFFFDD. At Location BoldSystem.TBoldMember.CalculateDerivedMemberWithExpression (BoldSystem.pas:4016)
Inner Exception Call Stack:
[00] System.TObject.InheritsFrom (sys\system.pas:9237)
Call Stack:
[00] BoldSystem.TBoldMember.CalculateDerivedMemberWithExpression (BoldSystem.pas:4016)
[01] BoldSystem.TBoldMember.DeriveMember (BoldSystem.pas:3846)
[02] BoldSystem.TBoldMemberDeriver.DoDeriveAndSubscribe (BoldSystem.pas:7491)
[03] BoldDeriver.TBoldAbstractDeriver.DeriveAndSubscribe (BoldDeriver.pas:180)
[04] BoldDeriver.TBoldAbstractDeriver.SetDeriverState (BoldDeriver.pas:262)
[05] BoldDeriver.TBoldAbstractDeriver.Derive (BoldDeriver.pas:117)
[06] BoldDeriver.TBoldAbstractDeriver.EnsureCurrent (BoldDeriver.pas:196)
[07] BoldSystem.TBoldMember.EnsureContentsCurrent (BoldSystem.pas:4245)
[08] BoldSystem.TBoldAttribute.EnsureNotNull (BoldSystem.pas:4813)
[09] BoldAttributes.TBABoolean.GetAsBoolean (BoldAttributes.pas:3069)
[10] BusinessClasses.TLogonSession._GetMayDropSession (code\BusinessClasses.pas:31854)
[11] DMAttracsTimers.TAttracsTimerDataModule.RemoveDanglingLogonSessions (code\DMAttracsTimers.pas:237)
[12] DMAttracsTimers.TAttracsTimerDataModule.UpdateServerTimeOnTimerTrig (code\DMAttracsTimers.pas:482)
[13] DMAttracsTimers.TAttracsTimerDataModule.TimerKernelWork (code\DMAttracsTimers.pas:551)
[14] DMAttracsTimers.TAttracsTimerDataModule.AttracsTimerTimer (code\DMAttracsTimers.pas:600)
[15] ExtCtrls.TTimer.Timer (ExtCtrls.pas:2281)
[16] Classes.StdWndProc (common\Classes.pas:11583)
Run Code Online (Sandbox Code Playgroud)
内部异常部分是异常重新启动时的callstack.
EDIT3:现在的理论是虚拟内存表(VMT)在某种程度上被打破了.当发生这种情况时,没有迹象表明它.只有当一个方法被调用时才会引发异常(总是在地址FFFFFFDD,-35十进制),但是为时已晚.您不知道错误的真正原因.任何关于如何捕捉这样的bug的提示都非常感谢!!! 我们尝试过使用SafeMM,但问题是即使使用3 GB标志,内存消耗也太高.所以现在我尝试给SO社区一个赏金:)
编辑4:一个提示是,根据日志,在此之前经常(或甚至总是)有另一个例外.它可以是例如数据库中的乐观锁定.我们试图通过武力提出例外,但在测试环境中它只是工作正常.
编辑5:故事继续......我现在搜索了过去30天的日志.结果:
因此,目前的理论是枚举(Bold中有很多)覆盖指针.我有5个点击,上面有不同的地址.这可能意味着enum保存5个值,其中第二个值最常用.如果存在异常,则应对数据库进行回滚,并且应销毁Boldobjects.也许有可能不是所有东西都被破坏而且枚举仍然可以写入地址位置.如果这是真的,也许可以通过regexpr搜索具有5个值的枚举的代码?
编辑6:总而言之,目前还没有解决问题的方法.我意识到我可能会用callstack误导你一点.是的,有一个计时器,但有其他没有计时器的callstack.对不起.但有两个共同因素.
这让我相信VilleK能够最好地描述这个问题.我也确信问题出现在Bold框架中.但是大问题是,这样的问题怎么解决?像VilleK这样的断言是不够的,因为损坏已经发生并且那时候的信号堆消失了.因此,要描述我可能导致错误的原因:
这三个事件可以在代码中一起使用,但也可以在以后使用它们.我认为对于最后一次方法调用都是如此.
编辑7:我们与Bold Jan Norden的作者密切合作,他最近在Bold框架中发现了OCL评估者的一个错误.当这个被修复时,这些异常减少了很多,但它们偶尔也会出现.但这几乎解决了,这是一个很大的缓解.
你写的是你希望那里有例外
存储器地址上有一个未由应用程序分配的写入
如果您的意思是要在应用程序的分配地址范围内检查无效的内存写入,那么您只能做很多事情.您应该使用FastMM4,并在应用程序的调试模式下使用它的最详细和偏执设置.这将捕获大量无效写入,访问已释放的内存等,但它无法捕获所有内容.考虑一个指向另一个可写内存位置的悬空指针(如大字符串或浮点值数组的中间位置) - 写入它会成功,它会丢弃其他数据,但内存管理器无法捕获这样的内容访问.
我没有解决方案,但有一些关于该特定错误消息的线索.
System.TObject.InheritsFrom从Self-pointer(类)中减去常量vmtParent,以获取指向父类地址的指针.
在Delphi 2007中定义了vmtParent:
vmtParent = -36;
所以错误$ FFFFFFDD(-35)在这种情况下听起来类指针是1.
这是一个重现它的测试用例:
procedure TForm1.FormCreate(Sender: TObject);
var
I : integer;
O : tobject;
begin
I := 1;
O := @I;
O.InheritsFrom(TObject);
end;
Run Code Online (Sandbox Code Playgroud)
我已经在Delphi 2010中尝试过并获得"读取地址FFFFFFD1",因为vmtParent在Delphi版本之间是不同的.
问题是,这种情况发生在Bold框架内部,因此您可能无法在应用程序代码中防范它.
您可以在DMAttracsTimers代码中使用的对象上尝试此操作(我假设您的应用程序代码):
Assert(Integer(Obj.ClassType)<>1,'Corrupt vmt');
Run Code Online (Sandbox Code Playgroud)