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

Posted dotNET跨平台

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一个奇怪的错误,找到了错误点,也找到了解决方法,但是结果不满意相关的知识,希望对你有一定的参考价值。

楔子

在对类进行实例化的时候,会调用.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不开源,也看不到代码,所以无从查证。

结尾

作者:江湖评谈

以上是关于一个奇怪的错误,找到了错误点,也找到了解决方法,但是结果不满意的主要内容,如果未能解决你的问题,请参考以下文章

在 VC++ 中找到实际的错误点

工作两个月了,赶上周日加班,开始记录每天的成长与bug修改

g++ 已安装但 make 说 g++ 未找到(奇怪)

未找到工作职能。尝试公开您的工作类别和方法

在 MySQL 5.6.27 中创建触发器时出现奇怪的错误 [重复]

unity坑-编译错误