楔子
在对类进行实例化的时候,会调用.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不开源,也看不到代码,所以无从查证。
结尾
作者:江湖评谈