zl程序教程

您现在的位置是:首页 >  其他

当前栏目

一个奇怪的错误,找到了错误点,也找到了解决方法,但是结果不满意

2023-03-07 09:09:18 时间

楔子

在对类进行实例化的时候,会调用.Ctor默认构造函数。

它一般的首先调用的是函数

JIT_TrialAllocSFastMP_InlineGetThread

实例化,然后再调用.Ctor。这是一个实例化的整体思路。

问题

问题就出在,如果在VS Debug CLR上的.Ctor的汇编代码上打上断点,那么结果就会出错。如果你不打这个断点。结果就不会出错。错误如下:

意思是,打上断点造成的错误? 继续运行下去整个程序直接结束了。

探究

看下错误堆栈:

KernelBase.dll!00007fff09a088e2()	未知	未加载任何符号。
coreclr.dll!CHECK::Setup(const char * message=0x000002948594b430, const char * condition=0x00007ffe5c48e524, const char * file=0x00007ffe5c492990, int line=0x00001be0) 行 198	C++	已加载符号。
coreclr.dll!CLRVectoredExceptionHandlerPhase3(_EXCEPTION_POINTERS * pExceptionInfo=0x000000ecb6f79bd0) 行 7135	C++	已加载符号。
coreclr.dll!CLRVectoredExceptionHandlerPhase2(_EXCEPTION_POINTERS * pExceptionInfo=0x000000ecb6f79bd0) 行 6889	C++	已加载符号。
coreclr.dll!CLRVectoredExceptionHandler(_EXCEPTION_POINTERS * pExceptionInfo=0x000000ecb6f79bd0) 行 6856	C++	已加载符号。
coreclr.dll!CLRVectoredExceptionHandlerShim(_EXCEPTION_POINTERS * pExceptionInfo=0x000000ecb6f79bd0) 行 7547	C++	已加载符号。
ntdll.dll!RtlpCallVectoredHandlers()	未知	已加载符号。
ntdll.dll!RtlDispatchException()	未知	已加载符号。
ntdll.dll!KiUserExceptionDispatch()	未知	已加载符号。
coreclr.dll!_hpCodeHdr::GetNumberOfUnwindInfos() 行 331	C++	已加载符号。
coreclr.dll!_hpCodeHdr::GetUnwindInfo(unsigned int iUnwindInfo=0x00000000) 行 341	C++	已加载符号。
coreclr.dll!CEEJitInfo::WriteCode(EEJitManager * jitMgr=0x00000294d6bdeba0) 行 10883	C++	已加载符号。

GetNumberOfUnwindInfos()这个函数出现了异常,进去看看,函数原型如下:

UINT  GetNumberOfUnwindInfos()
{
   SUPPORTS_DAC;
   return pRealCodeHeader->nUnwindInfos;
}

原来是pRealCodeHeader这个结构体为空造成的异常。那么它是从哪里来的呢?

看堆栈有个WriteCode函数,进入里面看下:

void CEEJitInfo::WriteCode(EEJitManager * jitMgr)
{
   // 此处省略
    WriteCodeBytes();、
   // 此处省略
}

它里面调用了WriteCodeBytes函数:

void CEEJitInfo::WriteCodeBytes()
{
    if (m_CodeHeaderRW != m_CodeHeader)
    {
  ExecutableWriterHolder<void>codeWriterHolder((void*)m_CodeHeader,m_codeWriteBufferSize);
        memcpy(codeWriterHolder.GetRW(), m_CodeHeaderRW, m_codeWriteBufferSize);
    }
}

m_CodeHeader的成员变量就是pRealCodeHeader。那么m_CodeHeader哪里来的呢?

m_CodeHeader通过codeWriterHolder调用MapViewOfFile进行地址映射,当 codeWriterHolder.GetRW()变量改变的时候,m_CodeHeader就进行改变。那么问题就出在这里,当断点到.Ctor上面的时候,运行到这两句代码:

ExecutableWriterHolder<void> codeWriterHolder((void *)m_CodeHeader, m_codeWriteBufferSize);
memcpy(codeWriterHolder.GetRW(), m_CodeHeaderRW, m_codeWriteBufferSize);

m_CodeHeader并没有改变,而断点其它函数都会改变。

难道是断点引起的MapViewOfFile错误?

结果

原因是找到了,但是解决问题的方式有点不爽。看上面两句代码,变量

codeWriterHolder.GetRW()

通过m_CodeHeaderRW变量赋值了,但是m_CodeHeader并没有被赋值上。所以这里可以把m_CodeHeaderRW地址指向的值八字节一个单位,复制到m_CodeHeader地址指向的值。这样就可以解决问题。

看似解决了问题,实际上为啥赋值不上,是否是MapViewOfFile的原因,或者是个微软的BUG?因为MapViewOfFile不开源,也看不到代码,所以无从查证。

结尾

作者:江湖评谈