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