在Delphi中,检测VMT或堆损坏的正确工具是什么?

在Delphi中,检测VMT或堆损坏的正确工具是什么?,delphi,heap,memory-corruption,vmt,bold-delphi,Delphi,Heap,Memory Corruption,Vmt,Bold Delphi,我是一个团队的成员,该团队将Delphi2007用于更大的应用程序,我们怀疑堆损坏,因为有时会出现奇怪的bug,没有其他解释。 我相信编译器的Rangechecking选项只适用于数组。我想要一个工具,当应用程序没有分配内存地址时,它会给出一个异常或日志 问候 编辑:错误类型为: 错误:模块“boatlogicsamcattracsserver.exe”中地址00404E78处存在访问冲突。读取地址ffffdd EDIT2:谢谢你的建议。不幸的是,我认为解决办法比这更深。我们使用了一个补丁版本的

我是一个团队的成员,该团队将Delphi2007用于更大的应用程序,我们怀疑堆损坏,因为有时会出现奇怪的bug,没有其他解释。 我相信编译器的Rangechecking选项只适用于数组。我想要一个工具,当应用程序没有分配内存地址时,它会给出一个异常或日志

问候

编辑:错误类型为:

错误:模块“boatlogicsamcattracsserver.exe”中地址00404E78处存在访问冲突。读取地址ffffdd

EDIT2:谢谢你的建议。不幸的是,我认为解决办法比这更深。我们使用了一个补丁版本的Bold for Delphi,因为我们拥有这个源代码。粗体框架中可能引入了一些错误。是的,我们有一个日志,其中包含由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)
20091210 16:02:29(2356)[异常]引发的EBold:未能派生ServerSession.mayDropSession:布尔值
OCL表达式:非活动、非空闲和超时(ApplicationKernel.allinstances->first.CurrentSession self)
错误:模块“boatlogicsamcattracsserver.exe”中地址00404E78处存在访问冲突。读取地址ffffdd。位于位置BoldSystem.TBoldMember.CalculatedDriveMemberWithExpression(BoldSystem.pas:4016)
引发内部异常EBold:未能派生ServerSession.mayDropSession:布尔值
OCL表达式:非活动、非空闲和超时(ApplicationKernel.allinstances->first.CurrentSession self)
错误:模块“boatlogicsamcattracsserver.exe”中地址00404E78处存在访问冲突。读取地址ffffdd。位于位置BoldSystem.TBoldMember.CalculatedDriveMemberWithExpression(BoldSystem.pas:4016)
内部异常调用堆栈:
[00]System.TObject.InheritsFrom(sys\System.pas:9237)
调用堆栈:
[00]BoldSystem.TBoldMember.CalculatedDrivedMemberWithExpression(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.setDeriversState(BoldDeriver.pas:262)
[05]BoldDeriver.TBoldAbstractDeriver.deriver(BoldDeriver.pas:117)
[06]BoldDeriver.TBoldAbstractDeriver.com(BoldDeriver.pas:196)
[07]BoldSystem.TBoldMember.EnsureContentsCurrent(BoldSystem.pas:4245)
[08]BoldSystem.TBoldAttribute.EnsureRenotnull(BoldSystem.pas:4813)
[09]BoldAttributes.TBABoolean.GetAsBoolean(BoldAttributes.pas:3069)
[10] BusinessClasses.TLogonSession.\u GetMayDropSession(code\BusinessClasses.pas:31854)
[11] DMAttracsTimers.TAttracsTimerDataModule.RemoveDanglingLogonSessions(代码\DMAttracsTimers.pas:237)
[12] DMAttracsTimers.TAttracsTimerDataModule.UpdateServerTimeOnTimerRig(代码\DMAttracsTimers.pas:482)
[13] DMAttracsTimers.TAttracsTimerDataModule.TimerKernelWork(代码\DMAttracsTimers.pas:551)
[14] DMAttracsTimers.TAttracsTimerDataModule.AttracStimerTime(代码\DMAttracsTimers.pas:600)
[15] ExtCtrls.TTimer.Timer(ExtCtrls.pas:2281)
[16] Classes.StdWndProc(公共\Classes.pas:11583)
内部异常部分是重新调用异常时的调用堆栈

EDIT3:目前的理论是虚拟内存表(VMT)不知何故被破坏了。当这种情况发生时,没有迹象表明会发生。只有在调用方法时才会引发异常(始终在地址ffffff dd,-35十进制上),但随后就太迟了。你不知道错误的真正原因。任何关于如何捕捉这样一个bug的提示都是非常感谢的!!!我们已经尝试使用SafeMM,但问题是即使使用3 GB标志,内存消耗也太高。所以现在我试着给So社区一个赏金:)

EDIT4:一个提示是,根据日志,在此之前通常(甚至总是)存在另一个异常。例如,它可以是数据库中的乐观锁定。我们曾试图通过强制方式引发异常,但在测试环境中,它运行良好

EDIT5:故事继续。。。我搜索了过去30天的日志。结果是:

  • “读取地址FFFFFF DB”0
  • “读取地址FFFFFF DC”24
  • “读取地址FFFFFF DD”270
  • “读取地址FFFFFF DE”22
  • “读取地址FFFFFF DF”7
  • “读取地址FFFFFF E0”20
  • “读取地址FFFFFF E1”0
因此,当前的理论是枚举(粗体有很多)覆盖指针。我得到了5个不同地址的点击。这可能意味着枚举包含5个值,其中第二个值使用最多。如果出现异常,则应为数据库执行回滚,并销毁对象。可能不是所有的东西都被破坏了,枚举仍然可以写入地址位置。如果这是真的,那么是否可以通过regexpr在代码中搜索具有5个值的枚举

EDIT6:总而言之,这个问题还没有解决方案。我意识到我可能会用callstack误导你一点。是的,其中有一个计时器,但也有其他没有计时器的调用堆栈。对不起。但有两个共同因素

  • 读取地址FFFFFF XX时发生异常
  • 调用堆栈的顶部是System.ToObject.InheritsFrom(sys\System.pas:9237)
这使我相信最好描述一下这个问题。 我还确信,问题在大胆的框架中的某个地方。 但问题是,这样的问题怎么解决? 仅仅有一个Assert-like-suggest是不够的,因为损害已经发生,调用堆栈在那一刻就消失了。因此,为了描述我对可能导致错误的原因的看法:

  • 某物
    procedure TForm1.FormCreate(Sender: TObject);
    var
      I : integer;
      O : tobject;
    begin
      I := 1;
      O := @I;
      O.InheritsFrom(TObject);
    end;
    
    Assert(Integer(Obj.ClassType)<>1,'Corrupt vmt');
    
    procedure TAttracsTimerDataModule.AttracsTimerTimer(ASender: TObject);
    begin
      if FInTimer then
      begin
        // Let us know there is a problem or log it to a file, or something. 
        // Even throw an exception
        OutputDebugString('Timer called re-entrantly!'); 
        Exit; //======> 
      end;
    
      FInTimer := True;
      try
    
        // method contents
    
      finally
        FInTimer := False;
      end;
    end;
    
    procedure TForm11.Button1Click(Sender: TObject);
    var
      c: TComponent;
      i: Integer;
      p: pointer;
    begin
      //create
      c := TComponent.Create(nil);
      //get size and memory
      i := c.InstanceSize;
      p := Pointer(c);
      //destroy component
      c.Free;
      //this call will succeed, object is gone, but memory still "valid"
      c.InheritsFrom(TObject);
      //overwrite memory
      FillChar(p, i, 1);
      //CRASH!
      c.InheritsFrom(TObject);
    end;