在GC最终线程中崩溃,“ destroyscout”的问题是什么?

发布于 2025-02-07 14:28:55 字数 3810 浏览 3 评论 0原文

我面对的是.NET服务器应用程序,该应用程序几乎每周都会在“ GC终结器线程”中的问题上崩溃,更准确地在“ mscorlib.dll ... 〜destroyscout()的第798行”上。视觉工作室。

Visual Studio还试图打开文件“ DynamicilGenerator.gs”。我没有这个文件,但是我找到了该文件的一个版本,其中798的确确实在destructor内部或destroyscout(无论这可能意味着)。

我在视觉工作室环境中有以下信息:

线程:

Not Flagged >   5892    0   Worker Thread   GC Finalizer Thread mscorlib.dll!System.Reflection.Emit.DynamicResolver.DestroyScout.~DestroyScout

呼叫堆栈:

    [Managed to Native Transition]  
>   mscorlib.dll!System.Reflection.Emit.DynamicResolver.DestroyScout.~DestroyScout() Line 798   C#
[Native to Managed Transition]  
kernel32.dll!@BaseThreadInitThunk@12()  Unknown
ntdll.dll!__RtlUserThreadStart()    Unknown
ntdll.dll!__RtlUserThreadStart@8()  Unknown

当地人(无法确定该$ exception对象是否正确):

+       $exception  {"Exception of type 'System.ExecutionEngineException' was thrown."} System.ExecutionEngineException
    this    Cannot obtain value of the local variable or argument because it is not available at this instruction pointer,
            possibly because it has been optimized away.    System.Reflection.Emit.DynamicResolver.DestroyScout
    Stack objects   No CLR objects were found in the stack memory range of the current frame.   

“ dynamicilgenerator.cs”的源代码,提到destroyscout class(评论中提到了第798行):

    private class DestroyScout
    {
        internal RuntimeMethodHandleInternal m_methodHandle;

        [System.Security.SecuritySafeCritical]  // auto-generated
        ~DestroyScout()
        {
            if (m_methodHandle.IsNullHandle())
                return;

            // It is not safe to destroy the method if the managed resolver is alive.
            if (RuntimeMethodHandle.GetResolver(m_methodHandle) != null)
            {
                if (!Environment.HasShutdownStarted &&
                    !AppDomain.CurrentDomain.IsFinalizingForUnload())
                {
                    // Somebody might have been holding a reference on us via weak handle.
                    // We will keep trying. It will be hopefully released eventually.
                    GC.ReRegisterForFinalize(this);
                }
                return;
            }

            RuntimeMethodHandle.Destroy(m_methodHandle); // <===== line 798
        }
    }

观看窗口(m_methodhandle)

m_methodHandle  Cannot obtain value of the local variable or argument because 
                it is not available at this instruction pointer,
                possibly because it has been optimized away.
                System.RuntimeMethodHandleInternal

常规转储模块信息:

Dump Summary
------------
Dump File:  Application_Server2.0.exe.5296.dmp : C:\Temp_Folder\Application_Server2.0.exe.5296.dmp
Last Write Time:    14/06/2022 19:08:30
Process Name:   Application_Server2.0.exe : C:\Runtime\Application_Server2.0.exe
Process Architecture:   x86
Exception Code: 0xC0000005
Exception Information:  The thread tried to read from or write to a virtual address
                        for which it does not have the appropriate access.
Heap Information:   Present

System Information
------------------
OS Version: 10.0.14393
CLR Version(s): 4.7.3920.0

Modules
-------
Module Name                                           Module Path   Module Version
-----------                                           -----------   --------------
...
clr.dll     C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll       4.7.3920.0
...

请注意:转储到达A Windows-Server 2016 计算机,我正在调查Windows-10环境上的转储(在转储摘要中不要误解OS版本)!

编辑

DestroysCout可能试图破坏什么?这可能非常有趣。

I'm facing with a .Net server application, which crashes on an almost weekly basis on a problem in a "GC Finalizer Thread", more exactly at line 798 of "mscorlib.dll ...~DestroyScout()", according to Visual Studio.

Visual Studio also tries to open the file "DynamicILGenerator.gs". I don't have this file, but I've found a version of that file, where line 798 indeed is inside the destructor or the DestroyScout (whatever this might mean).

I have the following information in my Visual Studio environment:

Threads :

Not Flagged >   5892    0   Worker Thread   GC Finalizer Thread mscorlib.dll!System.Reflection.Emit.DynamicResolver.DestroyScout.~DestroyScout

Call stack:

    [Managed to Native Transition]  
>   mscorlib.dll!System.Reflection.Emit.DynamicResolver.DestroyScout.~DestroyScout() Line 798   C#
[Native to Managed Transition]  
kernel32.dll!@BaseThreadInitThunk@12()  Unknown
ntdll.dll!__RtlUserThreadStart()    Unknown
ntdll.dll!__RtlUserThreadStart@8()  Unknown

Locals (no way to be sure if that $exception object is correct):

+       $exception  {"Exception of type 'System.ExecutionEngineException' was thrown."} System.ExecutionEngineException
    this    Cannot obtain value of the local variable or argument because it is not available at this instruction pointer,
            possibly because it has been optimized away.    System.Reflection.Emit.DynamicResolver.DestroyScout
    Stack objects   No CLR objects were found in the stack memory range of the current frame.   

Source code of "DynamicILGenerator.cs", mentioning the DestroyScout class (line 798 is mentioned in comment):

    private class DestroyScout
    {
        internal RuntimeMethodHandleInternal m_methodHandle;

        [System.Security.SecuritySafeCritical]  // auto-generated
        ~DestroyScout()
        {
            if (m_methodHandle.IsNullHandle())
                return;

            // It is not safe to destroy the method if the managed resolver is alive.
            if (RuntimeMethodHandle.GetResolver(m_methodHandle) != null)
            {
                if (!Environment.HasShutdownStarted &&
                    !AppDomain.CurrentDomain.IsFinalizingForUnload())
                {
                    // Somebody might have been holding a reference on us via weak handle.
                    // We will keep trying. It will be hopefully released eventually.
                    GC.ReRegisterForFinalize(this);
                }
                return;
            }

            RuntimeMethodHandle.Destroy(m_methodHandle); // <===== line 798
        }
    }

Watch window (m_methodHandle):

m_methodHandle  Cannot obtain value of the local variable or argument because 
                it is not available at this instruction pointer,
                possibly because it has been optimized away.
                System.RuntimeMethodHandleInternal

General dump module information:

Dump Summary
------------
Dump File:  Application_Server2.0.exe.5296.dmp : C:\Temp_Folder\Application_Server2.0.exe.5296.dmp
Last Write Time:    14/06/2022 19:08:30
Process Name:   Application_Server2.0.exe : C:\Runtime\Application_Server2.0.exe
Process Architecture:   x86
Exception Code: 0xC0000005
Exception Information:  The thread tried to read from or write to a virtual address
                        for which it does not have the appropriate access.
Heap Information:   Present

System Information
------------------
OS Version: 10.0.14393
CLR Version(s): 4.7.3920.0

Modules
-------
Module Name                                           Module Path   Module Version
-----------                                           -----------   --------------
...
clr.dll     C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll       4.7.3920.0
...

Be aware: the dump arrived on a Windows-Server 2016 computer, I'm investigating the dump on my Windows-10 environment (don't be mistaking on OS Version in the dump summary)!

Edit

What might the destroyscout be trying to destroy? That might be very interesting.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

梦明 2025-02-14 14:28:55

我不知道到底是什么原因导致了这次崩溃,但是我可以告诉您destroyscout做什么。

这与创建动态方法有关。类DynamicResolver需要清理相关的非托管内存,而GC未跟踪。但是,直到绝对不再参考该方法之前,它才能清理。

但是,由于恶意(或彻底的怪异)代码可以使用长fealReference可以在GC中幸存下来,因此在其最终化器已运行后,对Dynamic方法的引用复活。因此,destroyscout与其奇怪的gc.reregisterforfinalize代码相同,以确保它是最后一次被销毁的引用。

它在评论中进行了解释在源代码中

// We can destroy the unmanaged part of dynamic method only after the managed part is definitely gone and thus
// nobody can call the dynamic method anymore. A call to finalizer alone does not guarantee that the managed 
// part is gone. A malicious code can keep a reference to DynamicMethod in long weak reference that survives finalization,
// or we can be running during shutdown where everything is finalized.
//
// The unmanaged resolver keeps a reference to the managed resolver in long weak handle. If the long weak handle 
// is null, we can be sure that the managed part of the dynamic method is definitely gone and that it is safe to 
// destroy the unmanaged part. (Note that the managed finalizer has to be on the same object that the long weak handle 
// points to in order for this to work.) Unfortunately, we can not perform the above check when out finalizer 
// is called - the long weak handle won't be cleared yet. Instead, we create a helper scout object that will attempt 
// to do the destruction after next GC.

关于崩溃,这是在内部代码中发生的,并且正在引起executionEngineEngineException。当有内存损坏,以某种方式使用内存时,这很可能发生。

记忆损坏可能出于多种原因而发生。按可能性顺序:

  • 对本机Win32函数的PinVoke的使用不正确(dllimport和协同编组)。
  • 不正确使用Unsafe(包括Unsaffebuffer等库类,从事同一件事)。
  • 在对象上的多线竞赛条件,运行时不希望使用多线程。这可能会导致诸如撕裂和违反记忆障碍的问题。
  • .NET本身中的错误。这可能是最容易排除的:只是升级到最新版本。

考虑将崩溃报告提交给微软进行调查。

编辑作者
为了向Microsoft提交崩溃报告,可以使用以下URL: https:// wwwwwwwwww .microsoft.com/en-us/unifiedsupport 。考虑到这是一项付费服务​​,您可能需要提供整个源代码Microsoft,以便对碰撞转储进行完整分析。

I don't know what exactly is causing this crash, but I can tell you what DestroyScout does.

It's related to creating dynamic methods. The class DynamicResolver needs to clean up related unmanaged memory, which is not tracked by GC. But it cannot be cleaned up until there are definitely no references to the method anymore.

However, because malicious (or outright weird) code can use a long WeakReference which can survive a GC, and therefore resurrect the reference to the dynamic method after its finalizer has run. Hence DestroyScout comes along with its strange GC.ReRegisterForFinalize code in order to ensure that it's the last reference to be destroyed.

It's explained in a comment in the source code

// We can destroy the unmanaged part of dynamic method only after the managed part is definitely gone and thus
// nobody can call the dynamic method anymore. A call to finalizer alone does not guarantee that the managed 
// part is gone. A malicious code can keep a reference to DynamicMethod in long weak reference that survives finalization,
// or we can be running during shutdown where everything is finalized.
//
// The unmanaged resolver keeps a reference to the managed resolver in long weak handle. If the long weak handle 
// is null, we can be sure that the managed part of the dynamic method is definitely gone and that it is safe to 
// destroy the unmanaged part. (Note that the managed finalizer has to be on the same object that the long weak handle 
// points to in order for this to work.) Unfortunately, we can not perform the above check when out finalizer 
// is called - the long weak handle won't be cleared yet. Instead, we create a helper scout object that will attempt 
// to do the destruction after next GC.

As to your crash, this is happening in internal code, and is causing an ExecutionEngineException. This most likely happens when there is memory corruption, when memory is used in a way it wasn't supposed to be.

Memory corruption can happen for a number of reasons. In order of likelihood:

  • Incorrect use of PInvoke to native Win32 functions (DllImport and asscociated marshalling).
  • Incorrect use of unsafe (including library classes such as Unsafe and Buffer which do the same thing).
  • Multi-threaded race conditions on objects which the Runtime does not expect to be used multi-threaded. This can cause such problems as torn reads and memory-barrier violations.
  • A bug in .NET itself. This can be the easiest to exclude: just upgrade to the latest build.

Consider submitting the crash report to Microsoft for investigation.

Edit from the author:
In order to submit a crash report to Microsoft, the following URL can be used: https://www.microsoft.com/en-us/unifiedsupport. Take into account that this is a paying service and that you might need to deliver your entire source code Microsoft in order to get a full analysis of your crash dump.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文