如何调试托管堆中的损坏

我的程序抛出一个错误,它无法通过catch(Exception e)块处理,然后崩溃:

访问冲突损坏的状态exception。

这是奇怪的事情,因为,正如我所知,从非托管代码抛出损坏的状态exception,而在这里我在调用StringBuilder方法时得到此exception。

代码在后台线程中运行并且不时崩溃,这是不容易再现的。 所以我将WinDbg附加到进程并具有以下exception堆栈:

 000000001dabd8c8 000007feea129a1d [HelperMethodFrame: 000000001dabd8c8] 000000001dabda00 000007fee90cfce8 System.Text.StringBuilder.ExpandByABlock(Int32) 000000001dabda40 000007fee90cfba4 System.Text.StringBuilder.Append(Char*, Int32) 000000001dabdaa0 000007fee9102955 System.Text.StringBuilder.Append(System.String, Int32, Int32) 000000001dabdaf0 000007ff00bf5ce3 MineUtils.Common.Strings.Strings.Replace(System.String, System.String, System.String, Boolean, Boolean) 000000001dabdb90 000007ff00bf5a59 MineUtils.Common.Strings.Strings.RemoveSubstrings(System.String, System.String, System.String, Boolean) [D:\Programs\Visual Studio 2005 Projects\MineUtils.Common\Strings\Strings.Common-Main.cs @ 1481 

WinDbg显示发生此exception:

 EXCEPTION_RECORD: ffffffffffffffff -- (.exr 0xffffffffffffffff) ExceptionAddress: 000007feea129a1d (clr!WKS::gc_heap::find_first_object+0x0000000000000092) ExceptionCode: c0000005 (Access violation) ExceptionFlags: 00000000 NumberParameters: 2 Parameter[0]: 0000000000000000 Parameter[1]: 0000000000003d80 Attempt to read from address 0000000000003d80 

我读过这样的exception可以使用方法属性[HandleProcessCorruptedStateExceptions]来处理,但是如果我只使用StringBuilder,为什么会发生这种exception呢?

这是之前的WinDbg分析( StringBuilder.ToString()导致exception):

 ******************************************************************************* * * * Exception Analysis * * * ******************************************************************************* FAULTING_IP: clr!WKS::gc_heap::find_first_object+92 000007fe`ea129a1d f70100000080 test dword ptr [rcx],80000000h EXCEPTION_RECORD: ffffffffffffffff -- (.exr 0xffffffffffffffff) ExceptionAddress: 000007feea129a1d (clr!WKS::gc_heap::find_first_object+0x0000000000000092) ExceptionCode: c0000005 (Access violation) ExceptionFlags: 00000001 NumberParameters: 2 Parameter[0]: 0000000000000000 Parameter[1]: 0000000000001c98 Attempt to read from address 0000000000001c98 ERROR_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%08lx referenced memory at 0x%08lx. The memory could not be %s. EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%08lx referenced memory at 0x%08lx. The memory could not be %s. EXCEPTION_PARAMETER1: 0000000000000000 EXCEPTION_PARAMETER2: 0000000000001c98 READ_ADDRESS: 0000000000001c98 FOLLOWUP_IP: clr!WKS::gc_heap::find_first_object+92 000007fe`ea129a1d f70100000080 test dword ptr [rcx],80000000h MOD_LIST:  NTGLOBALFLAG: 0 APPLICATION_VERIFIER_FLAGS: 0 MANAGED_STACK: (TransitionMU) 000000001AB7DFC0 000007FEE90CFE07 mscorlib_ni!System.Text.StringBuilder.ToString()+0x27 000000001AB7E010 000007FF00C750A9 SgmlReaderDll!Sgml.Entity.ScanToken(System.Text.StringBuilder, System.String, Boolean)+0x169 000000001AB7E080 000007FF00C760E6 SgmlReaderDll!Sgml.SgmlDtd.ParseParameterEntity(System.String)+0xc6 000000001AB7E0F0 000007FF00C76FD8 SgmlReaderDll!Sgml.SgmlDtd.ParseModel(Char, Sgml.ContentModel)+0x298 000000001AB7E160 000007FF00C7701C SgmlReaderDll!Sgml.SgmlDtd.ParseModel(Char, Sgml.ContentModel)+0x2dc 000000001AB7E1D0 000007FF00C7701C SgmlReaderDll!Sgml.SgmlDtd.ParseModel(Char, Sgml.ContentModel)+0x2dc 000000001AB7E240 000007FF00C76BA5 SgmlReaderDll!Sgml.SgmlDtd.ParseContentModel(Char)+0x65 000000001AB7E290 000007FF00C763D7 SgmlReaderDll!Sgml.SgmlDtd.ParseElementDecl()+0xe7 000000001AB7E320 000007FF00C747A1 SgmlReaderDll!Sgml.SgmlDtd.Parse()+0xc1 000000001AB7E370 000007FF00C73EF5 SgmlReaderDll!Sgml.SgmlDtd.Parse(System.Uri, System.String, System.IO.TextReader, System.String, System.String, System.Xml.XmlNameTable)+0x175 000000001AB7E410 000007FF00C73B33 SgmlReaderDll!Sgml.SgmlReader.LazyLoadDtd(System.Uri)+0x163 000000001AB7E480 000007FF00C737B9 SgmlReaderDll!Sgml.SgmlReader.OpenInput()+0x19 000000001AB7E4E0 000007FF00C7334C SgmlReaderDll!Sgml.SgmlReader.Read()+0x1c 000000001AB7E530 000007FEE5983C4C System_Xml_ni!System.Xml.XmlLoader.Load(System.Xml.XmlDocument, System.Xml.XmlReader, Boolean)+0xac 000000001AB7E590 000007FEE5983730 System_Xml_ni!System.Xml.XmlDocument.Load(System.Xml.XmlReader)+0x90 ... 000000001AB7F0A0 000007FEE97ED792 mscorlib_ni!System.Threading.Tasks.Task.Execute()+0x82 000000001AB7F100 000007FEE90A181C mscorlib_ni!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)+0xdc 000000001AB7F160 000007FEE97E7F95 mscorlib_ni!System.Threading.Tasks.Task.ExecuteWithThreadLocal(System.Threading.Tasks.Task ByRef)+0x1b5 000000001AB7F1E0 000007FEE97E7D90 mscorlib_ni!System.Threading.Tasks.Task.ExecuteEntry(Boolean)+0xb0 000000001AB7F220 000007FEE90EBA83 mscorlib_ni!System.Threading.ThreadPoolWorkQueue.Dispatch()+0x193 000000001AB7F2C0 000007FEE90EB8D5 mscorlib_ni!System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()+0x35 (TransitionUM) EXCEPTION_OBJECT: !pe 2a61228 Exception object: 0000000002a61228 Exception type: System.ExecutionEngineException Message:  InnerException:  StackTrace (generated):  StackTraceString:  HResult: 80131506 MANAGED_OBJECT_NAME: System.ExecutionEngineException MANAGED_STACK_COMMAND: _EFN_StackTrace LAST_CONTROL_TRANSFER: from 000007feea12bce4 to 000007feea129a1d ADDITIONAL_DEBUG_TEXT: Followup set based on attribute [Is_ChosenCrashFollowupThread] from Frame:[0] on thread:[PSEUDO_THREAD] FAULTING_THREAD: ffffffffffffffff DEFAULT_BUCKET_ID: INVALID_POINTER_READ_CALL PRIMARY_PROBLEM_CLASS: INVALID_POINTER_READ_CALL BUGCHECK_STR: APPLICATION_FAULT_INVALID_POINTER_READ_WRONG_SYMBOLS_CALL__SYSTEM.EXECUTIONENGINEEXCEPTION 

再次更新

这是启用分页堆后exception的WinDbg堆栈:

  (1480.e84): Access violation - code c0000005 (first chance) ntdll!ZwTerminateProcess+0xa: 00000000`77c415da c3 ret 0:023> !clrstack OS Thread Id: 0xe84 (23) Child SP IP Call Site 0000000037ded848 0000000077c415da [HelperMethodFrame: 0000000037ded848] 0000000037dedab0 000007fee9effd17 System.Text.StringBuilder.ToString()*** WARNING: Unable to verify checksum for C:\Windows\assembly\NativeImages_v4.0.30319_64\mscorlib\8f7f691aa155c11216387cf3420d9d1b\mscorlib.ni.dll 0000000037dedb00 000007ff00cceae9 Sgml.Entity.ScanToken(System.Text.StringBuilder, System.String, Boolean) 0000000037dedb70 000007ff00cd19b2 Sgml.SgmlDtd.ParseAttDefault(Char, Sgml.AttDef) 0000000037dedbc0 000007ff00cd120b Sgml.SgmlDtd.ParseAttDef(Char) 0000000037dedc00 000007ff00cd1057 Sgml.SgmlDtd.ParseAttList(System.Collections.Generic.Dictionary`2, Char) 0000000037dedc50 000007ff00cd10cd Sgml.SgmlDtd.ParseAttList(System.Collections.Generic.Dictionary`2, Char) 0000000037dedca0 000007ff00cd0e9a Sgml.SgmlDtd.ParseAttList() 0000000037dedd10 000007ff00cce1f1 Sgml.SgmlDtd.Parse() 0000000037dedd60 000007ff00ccd945 Sgml.SgmlDtd.Parse(System.Uri, System.String, System.IO.TextReader, System.String, System.String, System.Xml.XmlNameTable) 0000000037dede00 000007ff00ccd582 Sgml.SgmlReader.LazyLoadDtd(System.Uri) 0000000037dede70 000007ff00ccd1f9 Sgml.SgmlReader.OpenInput() 0000000037deded0 000007ff00cccd8c Sgml.SgmlReader.Read() 0000000037dedf20 000007fee67b3bfc System.Xml.XmlLoader.Load(System.Xml.XmlDocument, System.Xml.XmlReader, Boolean)*** WARNING: Unable to verify checksum for C:\Windows\assembly\NativeImages_v4.0.30319_64\System.Xml\8e4323f5bfb90be4621456033d8b404b\System.Xml.ni.dll *** ERROR: Module load completed but symbols could not be loaded for C:\Windows\assembly\NativeImages_v4.0.30319_64\System.Xml\8e4323f5bfb90be4621456033d8b404b\System.Xml.ni.dll 0000000037dedf80 000007fee67b36e0 System.Xml.XmlDocument.Load(System.Xml.XmlReader) [deleted] 0000000037deea90 000007feea61d432 System.Threading.Tasks.Task.Execute() 0000000037deeaf0 000007fee9ed17ec System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) 0000000037deeb50 000007feea617c35 System.Threading.Tasks.Task.ExecuteWithThreadLocal(System.Threading.Tasks.Task ByRef) 0000000037deebd0 000007feea617a30 System.Threading.Tasks.Task.ExecuteEntry(Boolean) 0000000037deec10 000007fee9f1b953 System.Threading.ThreadPoolWorkQueue.Dispatch() 0000000037deecb0 000007fee9f1b7a5 System.Threading._ThreadPoolWaitCallback.PerformWaitCallback() 0000000037def310 000007feeae4dc54 [DebuggerU2MCatchHandlerFrame: 0000000037def310] 0:023> !verifyheap -verify will only produce output if there are errors in the heap The garbage collector data structures are not in a valid state for traversal. It is either in the "plan phase," where objects are being moved around, or we are at the initialization or shutdown of the gc heap. Commands related to displaying, finding or traversing objects as well as gc heap segments may not work properly. !dumpheap and !verifyheap may incorrectly complain of heap consistency errors. object 000000000e34caf8: bad member 000000001024b9a0 at 000000000e34cb08 curr_object: 000000000e34caf8 Last good object: 000000000e34cab0 ---------------- 0:023> !analyze Last event: 1480.e84: Exit process 0:1480, code 80131506 debugger time: Sun Sep 18 14:22:42.592 2011 (UTC + 1:00) 0:023> !analyze -v Last event: 1480.e84: Exit process 0:1480, code 80131506 debugger time: Sun Sep 18 14:22:42.592 2011 (UTC + 1:00) 0:023> .do e34cab0 ^ Syntax error in '.do e34cab0' 0:023> !do e34cab0 Name: System.String MethodTable: 000007feea026870 EEClass: 000007fee9baed58 Size: 72(0x48) bytes File: C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll String: appliedFiltersContainer Fields: MT Field Offset Type VT Attr Value Name 000007feea02c758 4000103 8 System.Int32 1 instance 23 m_stringLength 000007feea02b298 4000104 c System.Char 1 instance 61 m_firstChar 000007feea026870 4000105 10 System.String 0 shared static Empty >> Domain:Value 00000000021343a0:000000000db21420 < !do e34caf8  Name: System.Reflection.RuntimeAssembly MethodTable: 000007feea02a128 EEClass: 000007fee9baf968 Size: 48(0x30) bytes File: C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll Fields: MT Field Offset Type VT Attr Value Name 000007feea9ef7f0 4000e14 8 ...solveEventHandler 0 instance 0000000000000000 _ModuleResolve 000007feea036338 4000e15 10 ...che.InternalCache 0 instance 000000001024b9a0 m_cachedData 000007feea0259c8 4000e16 18 System.Object 0 instance 000000000e3abd18 m_syncRoot 000007feea033450 4000e17 20 System.IntPtr 1 instance 37a95f10 m_assembly 

它能是什么?

最近,我遇到了托管堆腐败,这对我来说是新鲜事。 我对此感到非常沮丧,并且必须学习很多东西才能调试它。 我要感谢Seva Titov给了我正确的方向开始。 他的回答简明扼要,非常有帮助。 我想记录我为调试问题所采取的操作以供我自己参考。 这可能对其他对此有所了解的人有所帮助。

.NET 4中的调试堆损坏:

如何怀疑堆腐败?

简述:

  1. 应用程序随机崩溃而不考虑应用的exception捕获,甚至可以通过像catch(Exception)这样的毯子来捕获所有exception。

  2. 检查应用程序故障转储中的CLR堆栈会在堆栈顶部显示垃圾收集器:

     000000001dabd8c8 000007feea129a1d [**HelperMethodFrame**: 000000001dabd8c8] 000000001dabda00 000007fee90cfce8 System.Text.StringBuilder.ExpandByABlock(Int32) 000000001dabda40 000007fee90cfba4 System.Text.StringBuilder.Append(Char*, Int32) ... EXCEPTION_RECORD: ffffffffffffffff -- (.exr 0xffffffffffffffff) ExceptionAddress: 000007feea129a1d (**clr!WKS::gc_heap**::find_first_object+0x0000000000000092) ExceptionCode: c0000005 (Access violation) ExceptionFlags: 00000000 NumberParameters: 2 Parameter[0]: 0000000000000000 Parameter[1]: 0000000000003d80 ... 
  3. CLR堆栈始终显示不同的点。 崩溃是否发生或显示的代码显然无关紧要,如StringBuilder的方法,它被certificate会导致exception。

有关更多详细信息,请参阅.NET崩溃:托管堆损坏调用非托管代码

一步一步走。 如果前一个步骤没有帮助,则使用下一步。

步骤1.检查代码。

检查代码是否存在不安全或本机代码使用情况:

  1. 查看unsafe DllImport语句的代码。
  2. 下载.NET Reflector并使用它来分析PInvoke的应用程序集。 以同样的方式,分析应用程序使用的第三方程序集。

如果发现不安全或本机代码使用,请特别注意这些。 在这种情况下,堆损坏的最常见原因是缓冲区溢出或参数类型不匹配。 确保提供给本机代码的缓冲区足够大,并且传递给本机代码的所有参数都是预期类型。

步骤2.检查是否可以捕获此损坏的状态exception

要处理此类exception,需要使用[HandleProcessCorruptedStateExceptions]属性修饰包含catch(Exception)语句的方法,或者在app.config文件中应用以下内容:

      

在成功捕获exception的情况下,您可以记录并检查它。 这意味着这不是一个损坏的堆问题。

根本无法处理损坏的堆exception: HandleProcessCorruptedStateExceptions似乎不起作用

有关损坏的状态exception的更多信息,请参阅.NET4中有关损坏的状态exception的所有信息

第3步。实时调试。

在这一步中,我们在生产环境中(或者我们可以重现崩溃的地方)调试崩溃的应用程序。

Microsoft Windows SDK for Windows 7和.NET Framework 4下载适用于Windows的调试工具 (将下载Web安装程序,允许选择要安装的所需组件 – 标记所有组件)。 它将安装32位和64位(如果您的系统是x64)版本所需的调试工具。

这里需要知道如何将WinDbg附加到实时进程,如何进行故障转储和检查它们,如何在WinDbg中加载SOS扩展(google了解详细信息)。

启用调试助手:

  1. 启动应用程序validation程序( C:\Program Files\Application Verifier – 使用所需的版本,x86或x64,具体取决于您的可执行编译模式),在左窗格中添加您的可执行文件,在右窗格中选中一个节点“基础知识/堆”。 保存更改。

  2. 启动Global Flags帮助程序( C:\Program Files\Debugging Tools for Windows\gflags.exe – 再次选择正确的版本,x86或x64)。 启动Global Flags后 ,转到“Image File”选项卡,在顶部文本框中输入不带任何路径的可执行文件的名称(例如,“MyProgram.exe”)。 然后按Tab键并设置以下框:

    • 启用堆尾检查
    • 启用堆免费检查
    • 启用堆参数检查
    • 在通话时启用堆validation
    • 免费禁用堆合并
    • 启用页面堆
    • 启用堆标记
    • 启用应用程序validation程序
    • 调试器(在右侧的文本框中键入已安装的WinDbg的路径,例如, C:\Program Files\Debugging Tools for Windows (x64)\windbg.exe -g )。

    有关更多详细信息,请参阅堆腐败,第2部分

  3. 转到“控制面板/系统和安全/系统”(或右键单击“开始”菜单中的“计算机”,然后选择“属性”。单击“高级系统设置”,在显示的对话框中,转到“高级”选项卡,然后单击“环境变量”按钮。在显示的对话框中,添加一个新的系统变量(如果您是系统管理员 – 否则为用户变量 – 在这种情况下需要注销/登录)。所需变量为“COMPLUS_HeapVerify”值为“1”。更多细节可以在Stack Overflow问题.NET / C#中找到:如何设置调试环境变量COMPLUS_HeapVerify ? .

现在我们准备开始调试了。 启动应用程序。 WinDbg应该自动启动它。 让应用程序继续运行,直到它崩溃到WinDgb然后检查转储。

提示 :要快速删除Global FlagsApplication Verifier和调试程序附件设置,请在注册表中删除以下项:x64 – HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\*YourAppName*

步骤4.启用MDA。

尝试使用托管调试助手。 详细信息在Stack Overflow问题中哪些MDA对跟踪堆损坏有用?

MDA必须与WinDbg一起使用。 我甚至将它们与Global FlagsApplication Verifier一起使用。

步骤5.启用GCStress。

使用GCStress是一个极端的选择,因为应用程序几乎无法使用,但它仍然是一种方法。 GCStress中有更多详细信息:如何在Windows 7中打开?

步骤6.编译x86。

如果您的应用程序当前正在为“任何CPU”或“x64”平台编译,请尝试将其编译为“x86”,如果您使用哪个平台没有区别。 我看到这个据报道可以解决这个问题。

步骤7.禁用并发GC – 这对我有用

.NET 4中报告的已知问题在gc_heap :: garbage_collect中的.NET 4运行时访问冲突中报告,没有非托管模块 。 可以通过在app.config文件中禁用并发GC来解决此问题:

       

您有托管堆损坏。 找到托管堆损坏问题的根本原因并不容易,因为问题通常在堆损坏后很久就会自我certificate。 在你的情况下, StringBuilder是一个红色的鲱鱼。 腐败发生在之前的某个时间。

我要做的是以下内容:

  1. 检查您是否有任何不安全的C#代码。 如果你有,请仔细检查那里的逻辑。
  2. 为您的应用程序启用分页堆 。 使用分页堆运行它将有助于发现非托管代码的问题 – 以防非托管代码破坏托管堆。
  3. 在不同的地方运行!VerifyHeap 。 这样,您就可以在代码中本地化发生损坏的位置。
  4. 如果您为应用程序启用了服务器类型的垃圾收集,则暂时将其更改为工作站垃圾收集 – 您将以这种方式获得更可预测的行为。
  5. 阅读Tesses的博客文章.NET Crash:Managed Heap Corruption调用非托管代码 。 它演示了托管堆损坏的一些示例。

请注意,当您在WinDbg下运行代码时,偶尔会遇到偶然的机会AV。 进入中心是安全的,只需在将WinDbg附加到进程后键入sxd av ,并仅调查第二次机会AV。