草庐IT

c++ - Rad Studio 调试器线程中未处理的异常

coder 2023-06-03 原文

我有一个大型应用程序,它最近在调试器中运行时开始表现出相当奇怪的行为。一、基础知识:

OS: Windows 7 64-bit.
Application: Multithreaded VCL app with many dlls, bpls, and other components.
Compiler/IDE: Embarcadero RAD Studio 2010.

观察到的症状是:当调试器附加到我的应用程序时,某些任务会导致应用程序崩溃。这些细节更令人困惑:我的应用程序停止并显示一条 Windows 消息,说“您的应用程序已停止工作”。它有助于向 Microsoft 发送小型转储。

需要注意的是:未连接调试器时,应用程序不会崩溃。此外,调试器不会在应用程序运行时指示任何异常或其他问题。

设置和单步执行断点似乎会影响应用程序崩溃的点,但我怀疑这是调试线程而不是有问题的线程的症状。

这些崩溃也发生在我同事的计算机上,与我观察到的行为相同。这使我不会特别怀疑我的计算机上安装了某些失败的东西。我遇到这个问题的同事也在运行 Windows 7 64 位。我没有同事没有遇到过这个问题。

我从崩溃中收集了一些完整的转储分析。我发现故障实际上每次都发生在同一个地方。这是来自转储的异常数据(它总是相同的,当然除了 ThreadId):
Exception Information

ThreadId:         0x000014C0
Code:             0x4000001F Unknown (4000001F)
Address:          0x773F2507
Flags:            0x00000000
NumberParameters: 0x00000001
    0x00000000

谷歌透露代码 0x4000001F 实际上是 STATUS_WX86_BREAKPOINT。 Microsoft 无助地将其描述为“Win32 x86 仿真子系统使用的异常状态代码”。

以下是堆栈详细信息(似乎没有变化):
0x773F2507: ntdll.dll+0x000A2507: RtlQueryCriticalSectionOwner + 0x000000E8
0x773F3DAB: ntdll.dll+0x000A3DAB: RtlQueryProcessLockInformation + 0x0000020D
0x773D2ED9: ntdll.dll+0x00082ED9: RtlUlonglongByteSwap + 0x00005C69
0x773F3553: ntdll.dll+0x000A3553: RtlpQueryProcessDebugInformationRemote + 0x00000044
0x74F73677: kernel32.dll+0x00013677: BaseThreadInitThunk + 0x00000012
0x77389F02: ntdll.dll+0x00039F02: RtlInitializeExceptionChain + 0x00000063
0x77389ED5: ntdll.dll+0x00039ED5: RtlInitializeExceptionChain + 0x00000036

值得注意的是,在 0x773F24ED 处似乎有一个函数结语,这表明 RtlQueryCriticalSectionOwner 是一个红鲱鱼。同样,一个函数结语对 RtlQueryProcessLockInformation 产生了怀疑。 0x5C69 偏移量对 RtlUlonglongByteSwap 产生了怀疑。不过,其他符号看起来是合法的。

具体来说, RtlpQueryProcessDebugInformationRemote 看起来是合法的。网上有些人( http://www.cygwin.com/ml/cygwin-talk/2006-q2/msg00050.html )似乎认为它是由调试器创建的,用于收集调试信息。这个理论对我来说似乎很合理,因为它似乎只有在连接调试器时才会出现。

与往常一样,当某些东西破裂时,某些东西会发生变化,从而破坏它。在这种情况下,某些东西正在动态加载一个新的 dll。我可以通过不动态加载特定的 dll 来导致崩溃停止发生。我不相信 dll 加载是相关的,但这里有详细信息,以防万一:

dll源是C。以下是未设置为默认值的编译选项:
Language Compliance: ANSI
Merge duplicate strings: True
Read-only strings: True
PCH usage: Do not use
Dynamic RTL: False

(项目选项说 False 是动态 RTL 的默认值,尽管在我创建 dll 项目时它被设置为 True。)

该 dll 使用 LoadLibrary 加载并使用 FreeLibrary 释放。加载和卸载模块似乎一切正常。然而,在库卸载后不久(使用 FreeLibrary),上述线程使程序崩溃。为了调试,我删除了对库的所有实际调用(包括 DllMain,以便进行更多测试)。调用或不调用的组合、DllMain 或 DllMain 或其他任何东西似乎都不会以任何方式改变崩溃的行为。简单地加载和卸载 dll 会在稍后调用崩溃。

此外,更改 dll 以使用动态 RTL 还会导致调试器线程崩溃停止。这是不可取的,因为编译后的 dll 确实应该在没有 CodeGear Runtime 可用的情况下可用。此外,dll 大小很重要。 dll 中包含的 C 代码不使用任何库。 (它不包括头文件,甚至标准库头文件。没有 malloc/free,没有 printf,没有任何东西。它只包含完全依赖于它们的输入并且不需要动态分配的函数。)这也是不可取的,因为“修复”一个通过改变东西直到它起作用而不理解它为什么起作用来解决问题真的从来都不是一个好的计划。 (这往往会导致错误重现和奇怪的编码实践。但实际上,在这一点上,如果我找不到其他任何东西,我可能会在这方面认输。)

最后,我的问题可能与以下问题之一有关:
  • System error after debugging multithreaded applications
  • Program and debugger quit without indication of problem

  • 任何想法或建议将不胜感激。

    最佳答案

    我通过使用 PatchINT3 解决方法的修改版本解决了上述问题,该解决方法于 2007 年发布,用于 BDS 2006:

    procedure PatchINT3;
    const
      INT3: Byte = $CC;
      NOP: Byte = $90;
    var
      NTDLL: THandle;
      BytesWritten: DWORD;
      Address: PByte;
    begin
      if Win32Platform <> VER_PLATFORM_WIN32_NT then
        Exit;
      NTDLL := GetModuleHandle('NTDLL.DLL');
      if NTDLL = 0 then
        Exit;
      Address := GetProcAddress(NTDLL, 'RtlQueryCriticalSectionOwner');
      if Address = nil then
        Exit;
      Inc(Address, $E8);
      try
        if Address^ <> INT3 then
          Exit;
    
        if WriteProcessMemory(GetCurrentProcess, Address, @NOP, 1, BytesWritten)
          and (BytesWritten = 1) then
          FlushInstructionCache(GetCurrentProcess, Address, 1);
      except
        //Do not panic if you see an EAccessViolation here, it is perfectly harmless!
        on EAccessViolation do
          ;
      else
        raise;
      end;
    end;
    

    在线程中加载 DLL 后调用一次此例程。该补丁修复了 ntdll.dll 版本 6.1.7601.17725 中的用户断点并将其更改为 NOP。

    如果预期地址处没有用户断点(INT3 (=$CC) 操作码),则补丁例程不执行任何操作并退出。

    希望有所帮助,
    安德烈亚斯

    脚注
    PatchINT3 的原始来源可以在这里找到:
    http://coding.derkeiler.com/Archive/Delphi/borland.public.delphi.non-technical/2007-01/msg04431.html

    脚注2
    C++ 中的相同函数:
    void PatchINT3()
    {
       unsigned char INT3   = 0xCC;
       unsigned char NOP    = 0x90;
    
       if (Win32Platform != VER_PLATFORM_WIN32_NT)
       {
          return;
       }
    
       HMODULE ntdll = GetModuleHandle(L"NTDLL.DLL");
       if (ntdll == NULL)
       {
          return;
       }
    
       unsigned char *address = (unsigned char*)GetProcAddress(ntdll,
          "RtlQueryCriticalSectionOwner");
       if (address == NULL)
       {
          return;
       }
    
       address += 0xE8;
    
       try
       {
          if (*address != INT3)
          {
             return;
          }
    
          unsigned long bytes_written = 0;
          if (WriteProcessMemory(GetCurrentProcess(), address, &NOP, 1,
             &bytes_written) && (bytes_written == 1))
          {
             FlushInstructionCache(GetCurrentProcess, address, 1);
          }
       }
       catch (EAccessViolation &e)
       {
          //Do not panic if you see an EAccessViolation
          //here, it is perfectly harmless!
       }
       catch(...)
       {
          throw;
       }
    }
    

    关于c++ - Rad Studio 调试器线程中未处理的异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6414514/

    有关c++ - Rad Studio 调试器线程中未处理的异常的更多相关文章

    1. ruby - 如何指定 Rack 处理程序 - 2

      Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

    2. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

      我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

    3. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

      我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

    4. ruby-on-rails - Rails - 乐观锁定总是触发 StaleObjectError 异常 - 2

      我正在学习Rails,并阅读了关于乐观锁的内容。我已将类型为integer的lock_version列添加到我的articles表中。但现在每当我第一次尝试更新记录时,我都会收到StaleObjectError异常。这是我的迁移:classAddLockVersionToArticle当我尝试通过Rails控制台更新文章时:article=Article.first=>#我这样做:article.title="newtitle"article.save我明白了:(0.3ms)begintransaction(0.3ms)UPDATE"articles"SET"title"='dwdwd

    5. ruby - #之间? Cooper 的 *Beginning Ruby* 中的错误或异常 - 2

      在Cooper的书BeginningRuby中,第166页有一个我无法重现的示例。classSongincludeComparableattr_accessor:lengthdef(other)@lengthother.lengthenddefinitialize(song_name,length)@song_name=song_name@length=lengthendenda=Song.new('Rockaroundtheclock',143)b=Song.new('BohemianRhapsody',544)c=Song.new('MinuteWaltz',60)a.betwee

    6. ruby-on-rails - 无法让 rspec、spork 和调试器正常运行 - 2

      GivenIamadumbprogrammerandIamusingrspecandIamusingsporkandIwanttodebug...mmm...let'ssaaay,aspecforPhone.那么,我应该把“require'ruby-debug'”行放在哪里,以便在phone_spec.rb的特定点停止处理?(我所要求的只是一个大而粗的箭头,即使是一个有挑战性的程序员也能看到:-3)我已经尝试了很多位置,除非我没有正确测试它们,否则会发生一些奇怪的事情:在spec_helper.rb中的以下位置:require'rubygems'require'spork'

    7. ruby - 在 Ruby 中重新分配常量时抛出异常? - 2

      我早就知道Ruby中的“常量”(即大写的变量名)不是真正常量。与其他编程语言一样,对对象的引用是唯一存储在变量/常量中的东西。(侧边栏:Ruby确实具有“卡住”引用对象不被修改的功能,据我所知,许多其他语言都没有提供这种功能。)所以这是我的问题:当您将一个值重新分配给常量时,您会收到如下警告:>>FOO='bar'=>"bar">>FOO='baz'(irb):2:warning:alreadyinitializedconstantFOO=>"baz"有没有办法强制Ruby抛出异常而不是打印警告?很难弄清楚为什么有时会发生重新分配。 最佳答案

    8. ruby - JetBrains RubyMine 3.2.4 调试器不工作 - 2

      使用Ruby1.9.2运行IDE提示说需要gemruby​​-debug-base19x并提供安装它。但是,在尝试安装它时会显示消息Failedtoinstallgems.Followinggemswerenotinstalled:C:/ProgramFiles(x86)/JetBrains/RubyMine3.2.4/rb/gems/ruby-debug-base19x-0.11.30.pre2.gem:Errorinstallingruby-debug-base19x-0.11.30.pre2.gem:The'linecache19'nativegemrequiresinstall

    9. ruby-on-rails - 如何调试 cucumber 测试? - 2

      我有:When/^(?:|I)follow"([^"]*)"(?:within"([^"]*)")?$/do|link,selector|with_scope(selector)doclick_link(link)endend我打电话的地方:Background:GivenIamanexistingadminuserWhenIfollow"CLIENTS"我的HTML是这样的:CLIENTS我一直收到这个错误:.F-.F--U-----U(::)failedsteps(::)nolinkwithtitle,idortext'CLIENTS'found(Capybara::Element

    10. ruby - 使用 `+=` 和 `send` 方法 - 2

      如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

    随机推荐