我是一个将 Delphi 2007 用于大型应用程序的团队的成员,我们怀疑堆损坏,因为有时会出现没有其他解释的奇怪错误。我相信编译器的 Rangechecking 选项仅适用于数组。我想要一个工具,当在应用程序未分配的内存地址上写入时,它会给出异常或日志。
问候
编辑:错误类型:
错误:模块“BoatLogisticsAMCAttracsServer.exe”中地址 00404E78 的访问冲突。读取地址 FFFFFFDD
EDIT2:感谢所有建议。不幸的是,我认为解决方案比这更深。由于我们拥有源代码,因此我们为 Delphi 使用了 Bold 的补丁版本。可能在 Bold 框架中引入了一些错误。是的,我们有一个日志,其中包含由 JCL 处理的调用堆栈以及跟踪消息。所以带有异常的调用栈可以像这样锁定:
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)
内部异常部分是重新引发异常时的调用堆栈。
EDIT3:现在的理论是虚拟内存表(VMT)以某种方式损坏。当这种情况发生时,没有任何迹象。只有在调用方法时才会引发异常(始终在地址 FFFFFFDD,-35 十进制),但为时已晚。您不知道错误的真正原因。任何关于如何捕获这样的错误的提示都非常感谢!!!我们尝试过使用 SafeMM,但问题是即使使用 3 GB 标志,内存消耗也太高。所以现在我试着给 SO 社区一个赏金:)
EDIT4:一个提示是,根据日志,在此之前经常(甚至总是)另一个异常。例如,它可以是数据库中的乐观锁定。我们试图强制引发异常,但在测试环境中它工作正常。
EDIT5:故事还在继续……我现在对过去 30 天的日志进行了搜索。结果:
- “读取地址 FFFFFFDB” 0
- “读取地址 FFFFFFDC” 24
- “读取地址 FFFFFFDD” 270
- “读取地址 FFFFFFDE” 22
- “读取地址 FFFFFFDF” 7
- “读取地址 FFFFFFE0” 20
- “读取地址 FFFFFFE1” 0
所以目前的理论是一个枚举(有很多粗体)覆盖一个指针。我在上面得到了 5 个不同地址的点击。这可能意味着枚举包含 5 个值,其中第二个是最常用的。如果出现异常,则应为数据库进行回滚,并且应销毁 Boldobjects。也许不是所有东西都被破坏了,枚举仍然可以写入地址位置。如果这是真的,也许可以通过正则表达式搜索代码以查找具有 5 个值的枚举?
EDIT6:总而言之,还没有解决问题的方法。我意识到我可能会用调用堆栈误导你。是的,其中有一个计时器,但还有其他没有计时器的调用堆栈。对此感到抱歉。但有两个共同因素。
- 读取地址 FFFFFFxx 的异常。
- 调用堆栈的顶部是 System.TObject.InheritsFrom (sys\system.pas:9237)
这让我相信VilleK最能描述这个问题。我也确信问题出在 Bold 框架的某个地方。但最大的问题是,如何解决这样的问题?仅仅有一个像VilleK这样的断言是不够的,因为损坏已经发生并且调用堆栈在那一刻已经消失了。因此,描述我对可能导致错误的原因的看法:
- 某个地方的指针被分配了一个错误的值 1,但它也可以是 0、2、3 等。
- 一个对象被分配给该指针。
- 对象基类中有方法调用。这会导致方法 TObject.InheritsForm 被调用,并且地址 FFFFFFDD 上出现异常。
这 3 个事件可以在代码中一起使用,但也可以在以后使用。我认为这对于最后一个方法调用是正确的。
EDIT7:我们与 Bold Jan Norden 的作者密切合作,他最近在 Bold 框架中的 OCL 评估器中发现了一个错误。修复此问题后,这些异常减少了很多,但它们仍然偶尔会出现。但这是一个很大的安慰,这几乎解决了。