这是什么FatalExecutionEngineError在.NET 4.5测试版的原因是什么? [英] What's the cause of this FatalExecutionEngineError in .NET 4.5 beta?

查看:278
本文介绍了这是什么FatalExecutionEngineError在.NET 4.5测试版的原因是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面的示例代码自然发生。突然,我的代码thew一个非常讨厌的冠冕堂皇的 FatalExecutionEngineError 例外。我花了好30分钟试图隔离和减少的罪魁祸首样本。这编译使用Visual Studio 2012作为一个控制台应用程序:

The sample code below occurred naturally. Suddenly my code thew a very nasty-sounding FatalExecutionEngineError exception. I spent a good 30 minutes trying to isolate and minimize the culprit sample. Compile this using Visual Studio 2012 as a console app:

class A<T>
{
    static A() { }

    public A() { string.Format("{0}", string.Empty); }
}

class B
{
    static void Main() { new A<object>(); }
}



应该产生对.NET框架4和4.5这个错误:

Should produce this error on .NET framework 4 and 4.5:

这是一个已知的错误,是什么原因,我能做些什么来缓解呢?我目前的解决办法是不使用的String.Empty ,但我会叫错了树?有关代码更改什么使得它的功能你所期望的 - 例如删除 A 的空静态构造函数,或者从更改类型放慢参数对象 INT

Is this a known bug, what is the cause and what can I do to mitigate it? My current work around is to not use string.Empty, but am I barking up the wrong tree? Changing anything about that code makes it function as you would expect - for example removing the empty static constructor of A, or changing the type paramter from object to int.

我想我的笔记本电脑这个代码,并没有抱怨。不过,我曾尝试我的主要应用程序,它在笔记本电脑崩溃以及。我必须有错位远的东西减少了问题的时候,我会看看我是否能弄清楚那是什么东西。

I tried this code on my laptop and it didn't complain. However, I did try my main app and it crashed on the laptop as well. I must have mangled away something when reducing the problem, I'll see if I can figure out what that was.

我的笔记本电脑开车撞相同的代码以上,框架4.0,但即使有4.5主要崩溃。 (?7月)。这两种系统都采用VS'12与最新的更新

My laptop crashed with the same code as above, with framework 4.0, but main crashes even with 4.5. Both systems are using VS'12 with latest updates (July?).

更多信息


  • IL代码(编译调试/任何CPU / 4.0 / VS2010(不是IDE应该的问题)?): http://codepad.org/boZDd98E

  • 没见过VS 2010年4.0。有没有崩溃/不优化,不同的目标CPU,调试器附加/不附加等 - 添梅多拉

  • 崩溃在2010年,如果我使用值为anycpu,在x86的罚款。坠毁在Visual Studio 2010 SP1,使用平台目标=值为anycpu,但细跟平台目标= 86。本机具有VS2012RC安装以及因此可能4.5做一个就地更换。使用值为anycpu和上投放= 3.5那么它不会崩溃所以看起来像在Framework.- colinsmith
  • 在x86上,与4.0的x64或值为anycpu在VS2010无法重现。 - 富士

  • 仅发生于64,(2012rc,Fx4.5) - 亨克Holterman

  • 在Win8的RP VS2012 RC。针对.NET 4.5,当最初没有看到这个MDA。当切换到目标.NET 4.0的MDA出现了。然后切换回.NET 4.5后,MDA仍然存在。 - 韦恩

  • IL Code (compiled Debug/Any CPU/4.0/VS2010 (not that IDE should matter?)): http://codepad.org/boZDd98E
  • Not seen VS 2010 with 4.0. Not crashing with/without optimizations, different target CPU, debugger attached/not attached, etc. - Tim Medora
  • Crashes in 2010 if I use AnyCPU, is fine in x86. Crashes in Visual Studio 2010 SP1, using Platform Target = AnyCPU, but fine with Platform Target=x86. This machine has VS2012RC installed as well so 4.5 possibly doing an in-place replacement. Use AnyCPU and TargetPlatform = 3.5 then it doesn't crash so looks like a regression in the Framework.- colinsmith
  • Cannot reproduce on x86, x64 or AnyCPU in VS2010 with 4.0. – Fuji
  • Only happens for x64, (2012rc, Fx4.5) - Henk Holterman
  • VS2012 RC on Win8 RP. Initially Not seeing this MDA when targeting .NET 4.5. When switched to targeting .NET 4.0 the MDA appeared. Then after switching back to .NET 4.5 the MDA remains. - Wayne

推荐答案

这也不是一个完整的答案,但我有几个想法。

我相信我已经找到一样我们会发现没有从.NET JIT团队应答有人好解释。

更新

我看了看深入一点,我相信我已经找到了问题的根源。它似乎是由在JIT类型初始化逻辑的一个错误的组合引起的,并在C#编译器依赖于该JIT按预期工作的假设的变化。我认为JIT缺陷存在于.NET 4.0,但在编译器为.NET 4.5的变化发现。

I looked a little deeper, and I believe I have found the source of the issue. It appears to be caused by a combination of a bug in the JIT type-initialization logic, and a change in the C# compiler that relies on the assumption that the JIT works as intended. I think the JIT bug existed in .NET 4.0, but was uncovered by the change in the compiler for .NET 4.5.

我不认为 beforefieldinit 是这里唯一的问题。我认为这是比简单。

I do not think that beforefieldinit is the only issue here. I think it's simpler than that.

从.NET 4.0在mscorlib.dll类型 System.String 包含静态构造函数:

The type System.String in mscorlib.dll from .NET 4.0 contains a static constructor:

.method private hidebysig specialname rtspecialname static 
    void  .cctor() cil managed
{
  // Code size       11 (0xb)
  .maxstack  8
  IL_0000:  ldstr      ""
  IL_0005:  stsfld     string System.String::Empty
  IL_000a:  ret
} // end of method String::.cctor

在.NET 4.5版本mscorlib.dll中, String.cctor (静态构造函数)是显眼:

In the .NET 4.5 version of mscorlib.dll, String.cctor (the static constructor) is conspicuously absent:

.....没有静态构造函数:( .....

..... No static constructor :( .....

在这两个版本的字符串型装饰着 beforefieldinit

In both versions the String type is adorned with beforefieldinit:

.class public auto ansi serializable sealed beforefieldinit System.String

我试图创建一个类型,将编译同样IL(使之具有静态字段,但没有静态构造函数 .cctor ),但我不能这样做。所有这些类型在IL一 .cctor 方法:

I tried to create a type that would compile to IL similarly (so that it has static fields but no static constructor .cctor), but I could not do it. All of these types have a .cctor method in IL:

public class MyString1 {
    public static MyString1 Empty = new MyString1();        
}

public class MyString2 {
    public static MyString2 Empty = new MyString2();

    static MyString2() {}   
}

public class MyString3 {
    public static MyString3 Empty;

    static MyString3() { Empty = new MyString3(); } 
}



我的猜测是,.NET 4.0和4.5之间变化两件事情:

My guess is that two things changed between .NET 4.0 and 4.5:

第一:EE已更改,以便它会自动从非托管代码初始化的String.Empty 。这种变化可能是.NET 4.0制作

First: The EE was changed so that it would automatically initialize String.Empty from unmanaged code. This change was probably made for .NET 4.0.

二:编译改变,因此,它没有发出字符串静态构造函数,知道的String.Empty 将被从非托管方指定。这种变化出现.NET 4.5已作出。

Second: The compiler changed so that it did not emit a static constructor for string, knowing that String.Empty would be assigned from the unmanaged side. This change appears to have been made for .NET 4.5.

看来,EE的的分配的String.Empty 足够很快带些优化路径。这种变化对编译器提出(或任何改变,使 String.cctor 消失)预计EE做这个任务的任何用户代码执行之前,但现在看来,EE不让的String.Empty 在具体化泛型类的引用类型的方法,使用前此分配。

It appears that the EE does not assign String.Empty soon enough along some optimization paths. The change made to the compiler (or whatever changed to make String.cctor disappear) expected the EE make this assignment before any user code executes, but it appears that the EE does not make this assignment before String.Empty is used in methods of reference type reified generic classes.

最后,我相信该错误指示在JIT类型初始化逻辑更深的问题。它出现在编译器的变化是 System.String 一个特例,但我怀疑JIT在这里做了一个特殊的情况下,为系统。字符串

Lastly, I believe that the bug is indicative of a deeper problem in the JIT type-initialization logic. It appears the change in the compiler is a special case for System.String, but I doubt that the JIT has made a special case here for System.String.

原始

首先,WOW的BCL人们已经变得非常有创意的一些性能优化。的许多的的字符串方法现在使用线程静态缓存的StringBuilder 对象执行

First of all, WOW The BCL people have gotten very creative with some performance optimizations. Many of the String methods are now performed using a Thread static cached StringBuilder object.

我也跟着铅一段时间,但的StringBuilder 未在用于修剪代码路径,所以我决定它不可能是一个静态的线程问题。

I followed that lead for a while, but StringBuilder isn't used on the Trim code path, so I decided it couldn't be a Thread static problem.

我想我找到了同样的bug的一个奇怪的表现,虽然

I think I found a strange manifestation of the same bug though.

此代码失败,访问冲突:

This code fails with an access violation:

class A<T>
{
    static A() { }

    public A(out string s) {
        s = string.Empty;
    }
}

class B
{
    static void Main() { 
        string s;
        new A<object>(out s);
        //new A<int>(out s);
        System.Console.WriteLine(s.Length);
    }
}



然而,如果你取消注释 //新的A< INT>(出S); 然后代码工作就好了。事实上,如果 A 与任何引用类型具体化,程序发生故障,但如果 A 被物化的任意值然后键入代码不会失败。此外,如果你注释掉 A 的静态构造函数,代码永远不会失败。挖掘到修剪格式之后,很明显的问题是,长度被内联,而这些样品上面的字符串在类型尚未初始化。特别是,在身体里面 A 的构造函数,的String.Empty 不正确分配,虽然体内的的String.Empty 被正确分配。

However, if you uncomment //new A<int>(out s); in Main then the code works just fine. In fact, if A is reified with any reference type, the program fails, but if A is reified with any value type then the code does not fail. Also if you comment out A's static constructor, the code never fails. After digging into Trim and Format, it is clear that the problem is that Length is being inlined, and that in these samples above the String type has not been initialized. In particular, inside the body of A's constructor, string.Empty is not correctly assigned, although inside the body of Main, string.Empty is assigned correctly.

令人吃惊的是,我认为字符串的类型初始化某种程度上取决于是否不 A 的具体化与值类型。我唯一​​的理论是,则表示这是所有类型的共享泛型类型初始化一些优化JIT代码路径,而这条道路使有关BCL引用类型(特殊类型?)及其状态的假设。就让我们来看看,虽然其他BCL类与公共静态字段表明基本的所有的人都的实施静态构造函数(即使是空的构造函数和没有数据像 System.DBNull System.Empty 。BCL值类型与公共静态领域似乎没有实现静态构造函数( System.IntPtr ,例如)。这似乎表明,JIT使约BCL引用类型的一些假设。初始化

It is amazing to me that the type initialization of String somehow depends on whether or not A is reified with a value type. My only theory is that there is some optimizing JIT code path for generic type-initialization that is shared among all types, and that that path makes assumptions about BCL reference types ("special types?") and their state. A quick look though other BCL classes with public static fields shows that basically all of them implement a static constructor (even those with empty constructors and no data, like System.DBNull and System.Empty. BCL value types with public static fields do not seem to implement a static constructor (System.IntPtr, for instance). This seems to indicate that the JIT makes some assumptions about BCL reference type initialization.

仅供参考下面是两个版本的JIT编译的代码:

FYI Here is the JITed code for the two versions:

A<对象> .ctor(出字符串)

A<object>.ctor(out string):

    public A(out string s) {
00000000  push        rbx 
00000001  sub         rsp,20h 
00000005  mov         rbx,rdx 
00000008  lea         rdx,[FFEE38D0h] 
0000000f  mov         rcx,qword ptr [rcx] 
00000012  call        000000005F7AB4A0 
            s = string.Empty;
00000017  mov         rdx,qword ptr [FFEE38D0h] 
0000001e  mov         rcx,rbx 
00000021  call        000000005F661180 
00000026  nop 
00000027  add         rsp,20h 
0000002b  pop         rbx 
0000002c  ret 
    }

A< INT32> .ctor(出字符串)

A<int32>.ctor(out string):

    public A(out string s) {
00000000  sub         rsp,28h 
00000004  mov         rax,rdx 
            s = string.Empty;
00000007  mov         rdx,12353250h 
00000011  mov         rdx,qword ptr [rdx] 
00000014  mov         rcx,rax 
00000017  call        000000005F691160 
0000001c  nop 
0000001d  add         rsp,28h 
00000021  ret 
    }

中的代码的其余部分()是两个版本之间是相同的。

The rest of the code (Main) is identical between the two versions.

修改

此外,IL从两个版本除了在 b调用 A.ctor 相同。主(),其中IL第一个版本包含:

In addition, the IL from the two versions is identical except for the call to A.ctor in B.Main(), where the IL for the first version contains:

newobj     instance void class A`1<object>::.ctor(string&)

... A`1<int32>...

第二

另外要注意的是,对于JIT编译代码的 A< INT取代。构造函数(出字符串) :是一样的,在非通用版本

Another thing to note is that the JITed code for A<int>.ctor(out string): is the same as in the non-generic version.

这篇关于这是什么FatalExecutionEngineError在.NET 4.5测试版的原因是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆