C# 为什么会发生CLR异常FatalExecutionEngineer错误?

C# 为什么会发生CLR异常FatalExecutionEngineer错误?,c#,.net,clr,fatal-error,C#,.net,Clr,Fatal Error,我们正在使用一个封装数值的结构,我发现当在表达式中使用该结构的可空版本时,会发生FatalExecutionEngineError: 其他信息:运行时遇到致命错误。这个 错误地址位于线程0x52d8上的0x729c1e04。错误 代码为0xc0000005。此错误可能是CLR或中的错误 用户代码的不安全或不可验证部分。这方面的共同来源 错误包括COM互操作或PInvoke的用户封送错误 可能会损坏堆栈 我正在使用Visual Studio Premium 2013更新3 以下是源代码C,目标.N

我们正在使用一个封装数值的结构,我发现当在表达式中使用该结构的可空版本时,会发生FatalExecutionEngineError:

其他信息:运行时遇到致命错误。这个 错误地址位于线程0x52d8上的0x729c1e04。错误 代码为0xc0000005。此错误可能是CLR或中的错误 用户代码的不安全或不可验证部分。这方面的共同来源 错误包括COM互操作或PInvoke的用户封送错误 可能会损坏堆栈

我正在使用Visual Studio Premium 2013更新3 以下是源代码C,目标.NET Framework 4.5:

using System;
using System.Globalization;
namespace ConsoleApplication4
{
    public struct Number
    {
        ValueType _val;

        private Number(double val)
        {
            this._val = val;
        }

        public static implicit operator double(Number val)
        {
            return Convert.ToDouble(val._val, CultureInfo.InvariantCulture);
        }

        public static implicit operator Number(double val)
        {
            return new Number(val);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Number? b = 1.2;
            var c = b - 1.2;

            Number b1 = 1.2;
            var c1 = b1 - 1.2;
        }
    }
}
注意,添加这个解决了这个问题,所以它不是紧急的,但是我非常感兴趣为什么这个问题会发生

public static implicit operator double(Number? val)
{
    return Convert.ToDouble(val.GetValueOrDefault()._val, CultureInfo.InvariantCulture);
}

这看起来像是一个编译器错误。问题发生在主干道的第二条线上

注意VS2013生成的IL,问题在于IL_005C和周围的代码,这是不必要的生成:

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       116 (0x74)
  .maxstack  2
  .locals init (valuetype [mscorlib]System.Nullable`1<valuetype Test.Number> V_0,
           valuetype [mscorlib]System.Nullable`1<float64> V_1,
           valuetype [mscorlib]System.Nullable`1<valuetype Test.Number> V_2,
           valuetype [mscorlib]System.Nullable`1<float64> V_3,
           valuetype [mscorlib]System.Nullable`1<float64> V_4)

// Number? b = 1.2;
  IL_0000:  nop
  IL_0001:  ldloca.s   V_0 //b
  IL_0003:  ldc.r8     1.2
  IL_000c:  call       valuetype Test.Number Test.Number::op_Implicit(float64)
  IL_0011:  call       instance void valuetype [mscorlib]System.Nullable`1<valuetype Test.Number>::.ctor(!0)
  IL_0016:  nop
  IL_0017:  ldloc.0
  IL_0018:  stloc.2    // b

// var c = b - 1.2;
  IL_0019:  ldloca.s   V_2 // b
  IL_001b:  call       instance bool valuetype [mscorlib]System.Nullable`1<valuetype Test.Number>::get_HasValue()
  IL_0020:  brtrue.s   IL_002d
  IL_0022:  ldloca.s   V_3
  IL_0024:  initobj    valuetype [mscorlib]System.Nullable`1<float64>
  IL_002a:  ldloc.3
  IL_002b:  br.s       IL_003e
  IL_002d:  ldloca.s   V_2
  IL_002f:  call       instance !0 valuetype [mscorlib]System.Nullable`1<valuetype Test.Number>::GetValueOrDefault()
  IL_0034:  call       float64 Test.Number::op_Implicit(valuetype Test.Number)

  // Um, what? First part of compiler bug is that it's needlessly creating a nullable float
  IL_0039:  newobj     instance void valuetype [mscorlib]System.Nullable`1<float64>::.ctor(!0)
  IL_003e:  nop
  IL_003f:  stloc.3
  IL_0040:  ldloca.s   V_3
  IL_0042:  call       instance bool valuetype [mscorlib]System.Nullable`1<float64>::get_HasValue()
  IL_0047:  brtrue.s   IL_0055
  IL_0049:  ldloca.s   V_4
  IL_004b:  initobj    valuetype [mscorlib]System.Nullable`1<float64>
  IL_0051:  ldloc.s    V_4
  IL_0053:  br.s       IL_0071
  IL_0055:  ldloca.s   V_3

  // Here's the real bug, though.  It's passing float64 to a the op_Implicit that is expecting a Number struct
  IL_0057:  call       instance !0 valuetype [mscorlib]System.Nullable`1<float64>::GetValueOrDefault()
  IL_005c:  call       float64 Test.Number::op_Implicit(valuetype Test.Number)
  IL_0061:  conv.r8


  IL_0062:  ldc.r8     1.2
  IL_006b:  sub
  IL_006c:  newobj     instance void valuetype [mscorlib]System.Nullable`1<float64>::.ctor(!0)
  IL_0071:  nop
  IL_0072:  stloc.1
  IL_0073:  ret
} // end of method Program::Main

Roslyn也使用VS14 CTP,它使用它产生不同的IL,而没有这个问题。代码几乎相同,只是它省略了IL_0039和IL_0061之间的IL。

我没有答案,只是CLR中有一个bug。Mono在这里也很奇怪,但它倾向于挂起而不是崩溃。NET在v4.0之前运行良好。奇怪。roslyn是做什么的?这是一个codegen bug,它死在一个名为JIT_chkcasterface的内部CLR助手方法中。这是一个垃圾论点,我不太清楚为什么。可为null的提升有一段麻烦的历史,在这种情况下,与ValueType的组合似乎是致命的。简单的解决方法是将_val声明为double。您可以在connect.microsoft.com上提交错误,并将其提交给MS connect
.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       116 (0x74)
  .maxstack  2
  .locals init (valuetype [mscorlib]System.Nullable`1<valuetype Test.Number> V_0,
           valuetype [mscorlib]System.Nullable`1<float64> V_1,
           valuetype [mscorlib]System.Nullable`1<valuetype Test.Number> V_2,
           valuetype [mscorlib]System.Nullable`1<float64> V_3,
           valuetype [mscorlib]System.Nullable`1<float64> V_4)

// Number? b = 1.2;
  IL_0000:  nop
  IL_0001:  ldloca.s   V_0 //b
  IL_0003:  ldc.r8     1.2
  IL_000c:  call       valuetype Test.Number Test.Number::op_Implicit(float64)
  IL_0011:  call       instance void valuetype [mscorlib]System.Nullable`1<valuetype Test.Number>::.ctor(!0)
  IL_0016:  nop
  IL_0017:  ldloc.0
  IL_0018:  stloc.2    // b

// var c = b - 1.2;
  IL_0019:  ldloca.s   V_2 // b
  IL_001b:  call       instance bool valuetype [mscorlib]System.Nullable`1<valuetype Test.Number>::get_HasValue()
  IL_0020:  brtrue.s   IL_002d
  IL_0022:  ldloca.s   V_3
  IL_0024:  initobj    valuetype [mscorlib]System.Nullable`1<float64>
  IL_002a:  ldloc.3
  IL_002b:  br.s       IL_003e
  IL_002d:  ldloca.s   V_2
  IL_002f:  call       instance !0 valuetype [mscorlib]System.Nullable`1<valuetype Test.Number>::GetValueOrDefault()
  IL_0034:  call       float64 Test.Number::op_Implicit(valuetype Test.Number)

  // Um, what? First part of compiler bug is that it's needlessly creating a nullable float
  IL_0039:  newobj     instance void valuetype [mscorlib]System.Nullable`1<float64>::.ctor(!0)
  IL_003e:  nop
  IL_003f:  stloc.3
  IL_0040:  ldloca.s   V_3
  IL_0042:  call       instance bool valuetype [mscorlib]System.Nullable`1<float64>::get_HasValue()
  IL_0047:  brtrue.s   IL_0055
  IL_0049:  ldloca.s   V_4
  IL_004b:  initobj    valuetype [mscorlib]System.Nullable`1<float64>
  IL_0051:  ldloc.s    V_4
  IL_0053:  br.s       IL_0071
  IL_0055:  ldloca.s   V_3

  // Here's the real bug, though.  It's passing float64 to a the op_Implicit that is expecting a Number struct
  IL_0057:  call       instance !0 valuetype [mscorlib]System.Nullable`1<float64>::GetValueOrDefault()
  IL_005c:  call       float64 Test.Number::op_Implicit(valuetype Test.Number)
  IL_0061:  conv.r8


  IL_0062:  ldc.r8     1.2
  IL_006b:  sub
  IL_006c:  newobj     instance void valuetype [mscorlib]System.Nullable`1<float64>::.ctor(!0)
  IL_0071:  nop
  IL_0072:  stloc.1
  IL_0073:  ret
} // end of method Program::Main