Windows 8,.NET 4.5 DefineUninitializedData问题

Windows 8, .NET 4.5 DefineUninitializedData issue

我正试图弄清我们的编译器和.NET 4.5与Windows8之间的问题。我把它简化为一小段代码,想知道是否有人对这个问题有任何了解。我已经编写了一些C,它使用反射来生成一个显示问题的程序集。C是(在这里的VS2010解决方案https://dl.dropbox.com/u/10931452/sdata.zip)在本文的底部。它创建一个类"sdata",并向它添加一个名为"blank16"的静态字段。然后它创建一个静态构造函数来初始化这个字段。生成的可执行文件将写入C: empsdatatest.exe。当在.NET 4.5下的Windows 8上运行sdatatest时,它会生成:

Unhandled Exception: System.TypeInitializationException: The type
initializer for 'sdata' threw an exception. --->
System.AccessViolationException: Attempted to read or write protected
memory. This is often an indication that other memory is corrupt. at
sdata..cctor() --- End of inner exception stack trace --- at
sdata.main()

在安装了.NET 4.5的Windows 7上运行时,它将运行。当在早期的.NET框架上运行时,它也在运行——并且已经运行了十年。

生成的IL看起来有效:

enter image description here

jited x86代码看起来也完全有效:

enter image description here

edi的值看起来像是加载的可执行文件中的一个位置,而不是托管内存空间中的一个位置,如果它是只读的,这将解释访问冲突。但是,为什么在Windows8上会发生这种变化?

C生产数据测试组件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
using System;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;

namespace sdata
{
    class Program
    {
        static void Main( string[] args )
        {
            AssemblyName name = new AssemblyName( );
            name.Name ="sdatatest.exe";
            string exepath ="c:\\temp\" + name.Name;
            name.CodeBase ="file:://" + exepath;
            AssemblyBuilder ass_bldr = Thread.GetDomain( ).DefineDynamicAssembly( name, AssemblyBuilderAccess.RunAndSave, Path.GetDirectoryName( exepath ));
            ModuleBuilder module_bldr = ass_bldr.DefineDynamicModule( Path.GetFileName( exepath ), Path.GetFileName( exepath ), true );
            TypeBuilder tb = module_bldr.DefineType("sdata", TypeAttributes.Public | TypeAttributes.AnsiClass );
            TypeBuilder sixteen = module_bldr.DefineType("sixteen", TypeAttributes.Sealed, typeof( ValueType ), PackingSize.Size8, 16 ); // value type of size 16
            Type t16 = sixteen.CreateType( );
            var fb = tb.DefineUninitializedData("blank16", 16, FieldAttributes.Public | FieldAttributes.Static );
            ConstructorBuilder cons = tb.DefineConstructor( MethodAttributes.Static, CallingConventions.Standard, Type.EmptyTypes ); // ..cctor
            var il = cons.GetILGenerator( );
            il.BeginScope( );
            il.Emit( OpCodes.Ldsflda, fb );
            il.Emit( OpCodes.Ldc_I4, 0 );
            il.Emit( OpCodes.Ldc_I4, 16 );
            il.Emit( OpCodes.Initblk );
            il.Emit( OpCodes.Ret );
            il.EndScope( );
            MethodBuilder mb = tb.DefineMethod("main", MethodAttributes.Static | MethodAttributes.Public );
            il = mb.GetILGenerator( );
            il.BeginScope( );
            il.Emit( OpCodes.Ldsflda, fb );
            il.Emit( OpCodes.Pop );
            il.Emit( OpCodes.Ret );
            il.EndScope( );
            tb.CreateType( );
            ass_bldr.SetEntryPoint( mb );
            ass_bldr.Save( Path.GetFileName( exepath ) );
        }
    }
}


答案是Windows8已经更改了.sdata部分的访问权限:使其为只读。如果您使用的是DefineUninitializedData,那么您的代码可能会在Windows8上中断,需要更改。