MSIL 程序集:class 构造函数中出现意外的 OutOfMemoryException
MSIL assembly: Unexpected OutOfMemoryException in class constructor
我正在编写一个输出 .NET 程序集的编译器(使用 Mono.Cecil,尽管我认为 Cecil 与此问题无关)。编译器的一项功能要求 class 具有编译器生成的嵌套 class 和一些支持方法;外部 class 有一个静态字段,因此每个 class 实际上都有一个引用嵌套 class 对象的单例。为了初始化它,任何这样的 class 都有一个 class 构造函数来创建嵌套 class 的实例并将其存储在字段中。
问题:当我的外部 class 是泛型 class 时,我也将嵌套 class 设为泛型(因为它需要创建外部 class 的对象).生成的 IL 可以很好地通过 peverify,并且 在我看来 很好,但是创建嵌套 class 实例的 class 构造函数会在运行时抛出 OutOfMemoryException。
我已经用 ildasm 反汇编了程序集,将其精简到最小的复制品(不幸的是仍然有大约 180 行 IL),并验证了用 ilasm 编译 IL 产生的 exe 仍然存在问题。
使用 Visual Studio 或 MDbg 进行调试并没有启发我 - 我只是得到 OutOfMemoryException 而没有指示 为什么 。我愿意相信我的 IL 不知何故无效,但 peverify 并不表示有问题。任何人都可以提出问题所在吗?
// Metadata version: v4.0.30319
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly extern System
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly Repro1
{
.ver 0:0:0:0
}
.module Repro1
// MVID: {7DA983B6-F5EA-4ACB-8443-C29F25ADDCD4}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x016E0000
.class public abstract auto ansi sealed Repro1
extends [mscorlib]System.Object
{
.method assembly static void '<NemeaProgram>'() cil managed
{
.entrypoint
// Code size 6 (0x6)
.maxstack 0
IL_0000: call void Rep2::Go()
IL_0005: ret
} // end of method Repro1::'<NemeaProgram>'
} // end of class Repro1
.class public abstract auto ansi sealed Rep1
extends [mscorlib]System.Object
{
.class auto ansi nested public TRep
extends [mscorlib]System.Object
{
.class auto ansi nested public '__%NemeaVType'
extends [mscorlib]System.Object
{
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ret
} // end of method '__%NemeaVType'::.ctor
.method public newslot virtual instance class Rep1/TRep
Create(string Foo) cil managed
{
// Code size 10 (0xa)
.maxstack 8
IL_0000: ldarg Foo
IL_0004: newobj instance void Rep1/TRep::.ctor(string)
IL_0009: ret
} // end of method '__%NemeaVType'::Create
} // end of class '__%NemeaVType'
.field famorassem string FData
.field public static class Rep1/TRep/'__%NemeaVType' '__%NemeaVTypeI'
.method public hidebysig specialname rtspecialname
instance void .ctor(string Foo) cil managed
{
// Code size 17 (0x11)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ldarg.0
IL_0007: ldarg Foo
IL_000b: stfld string Rep1/TRep::FData
IL_0010: ret
} // end of method TRep::.ctor
.method privatescope specialname rtspecialname static
void '.cctor$PST0600004C'() cil managed
{
// Code size 11 (0xb)
.maxstack 8
IL_0000: newobj instance void Rep1/TRep/'__%NemeaVType'::.ctor()
IL_0005: stsfld class Rep1/TRep/'__%NemeaVType' Rep1/TRep::'__%NemeaVTypeI'
IL_000a: ret
} // end of method TRep::.cctor
} // end of class TRep
.class auto ansi nested public TItem
extends [mscorlib]System.Object
{
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ret
} // end of method TItem::.ctor
} // end of class TItem
} // end of class Rep1
.class public abstract auto ansi sealed Rep2
extends [mscorlib]System.Object
{
.class auto ansi nested public TRep<(Rep1/TItem) T>
extends Rep1/TRep
{
.class auto ansi nested public '__%NemeaVType'<(Rep1/TItem) T_vt>
extends Rep1/TRep/'__%NemeaVType'
{
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void Rep1/TRep/'__%NemeaVType'::.ctor()
IL_0006: ret
} // end of method '__%NemeaVType'::.ctor
.method public virtual instance class Rep1/TRep
Create(string Foo) cil managed
{
// Code size 10 (0xa)
.maxstack 8
IL_0000: ldarg Foo
IL_0004: newobj instance void class Rep2/TRep<!T_vt>::.ctor(string)
IL_0009: ret
} // end of method '__%NemeaVType'::Create
} // end of class '__%NemeaVType'
.field public static class Rep2/TRep/'__%NemeaVType'<!T> '__%NemeaVTypeI'
.method public hidebysig specialname rtspecialname
instance void .ctor(string Foo) cil managed
{
// Code size 22 (0x16)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg Foo
IL_0005: call instance void Rep1/TRep::.ctor(string)
IL_0015: ret
} // end of method TRep::.ctor
.method privatescope specialname rtspecialname static
void '.cctor$PST06000055'() cil managed
{
// Code size 11 (0xb)
.maxstack 8
IL_0000: newobj instance void class Rep2/TRep/'__%NemeaVType'<!T>::.ctor()
IL_0005: stsfld class Rep2/TRep/'__%NemeaVType'<!T> Rep2/TRep::'__%NemeaVTypeI'
IL_000a: ret
} // end of method TRep::.cctor
} // end of class TRep
.method public static void Go() cil managed
{
// Code size 29 (0x1d)
.maxstack 1
.locals init ([0] class Rep1/TRep R)
IL_0000: ldstr "Oi"
IL_0005: newobj instance void class Rep2/TRep<class Rep1/TItem>::.ctor(string)
IL_000a: stloc R
IL_001c: ret
} // end of method Rep2::Go
} // end of class Rep2
所以事实证明问题与泛型声明无关 - 嵌套 class 的声明没问题。泛型参数的名称与外部 class 的泛型参数不匹配,但这只是 C# 编译器(可以理解)在将泛型参数传播到嵌套 classes 时遵守的约定.
问题只是
IL_0005: stsfld class Rep2/TRep/'__%NemeaVType'<!T> Rep2/TRep::'__%NemeaVTypeI'
行 - 它无效,因为它试图访问 Rep2/TRep class 上的字段,这是通用的,没有提供任何类型参数。将其更改为
IL_0005: stsfld class Rep2/TRep/'__%NemeaVType'<!0> Rep2/TRep<!T>::'__%NemeaVTypeI'
解决所有问题。
我仍然认为 peverify 可以 突出显示这一点,因为它不是真正有效的 - 它不可能正确执行,因为它不是有效的字段引用。执行代码时出现 OutOfMemoryException 而不是任何具有更多详细信息的异常也有点烦人。
我正在编写一个输出 .NET 程序集的编译器(使用 Mono.Cecil,尽管我认为 Cecil 与此问题无关)。编译器的一项功能要求 class 具有编译器生成的嵌套 class 和一些支持方法;外部 class 有一个静态字段,因此每个 class 实际上都有一个引用嵌套 class 对象的单例。为了初始化它,任何这样的 class 都有一个 class 构造函数来创建嵌套 class 的实例并将其存储在字段中。
问题:当我的外部 class 是泛型 class 时,我也将嵌套 class 设为泛型(因为它需要创建外部 class 的对象).生成的 IL 可以很好地通过 peverify,并且 在我看来 很好,但是创建嵌套 class 实例的 class 构造函数会在运行时抛出 OutOfMemoryException。
我已经用 ildasm 反汇编了程序集,将其精简到最小的复制品(不幸的是仍然有大约 180 行 IL),并验证了用 ilasm 编译 IL 产生的 exe 仍然存在问题。
使用 Visual Studio 或 MDbg 进行调试并没有启发我 - 我只是得到 OutOfMemoryException 而没有指示 为什么 。我愿意相信我的 IL 不知何故无效,但 peverify 并不表示有问题。任何人都可以提出问题所在吗?
// Metadata version: v4.0.30319
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly extern System
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly Repro1
{
.ver 0:0:0:0
}
.module Repro1
// MVID: {7DA983B6-F5EA-4ACB-8443-C29F25ADDCD4}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x016E0000
.class public abstract auto ansi sealed Repro1
extends [mscorlib]System.Object
{
.method assembly static void '<NemeaProgram>'() cil managed
{
.entrypoint
// Code size 6 (0x6)
.maxstack 0
IL_0000: call void Rep2::Go()
IL_0005: ret
} // end of method Repro1::'<NemeaProgram>'
} // end of class Repro1
.class public abstract auto ansi sealed Rep1
extends [mscorlib]System.Object
{
.class auto ansi nested public TRep
extends [mscorlib]System.Object
{
.class auto ansi nested public '__%NemeaVType'
extends [mscorlib]System.Object
{
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ret
} // end of method '__%NemeaVType'::.ctor
.method public newslot virtual instance class Rep1/TRep
Create(string Foo) cil managed
{
// Code size 10 (0xa)
.maxstack 8
IL_0000: ldarg Foo
IL_0004: newobj instance void Rep1/TRep::.ctor(string)
IL_0009: ret
} // end of method '__%NemeaVType'::Create
} // end of class '__%NemeaVType'
.field famorassem string FData
.field public static class Rep1/TRep/'__%NemeaVType' '__%NemeaVTypeI'
.method public hidebysig specialname rtspecialname
instance void .ctor(string Foo) cil managed
{
// Code size 17 (0x11)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ldarg.0
IL_0007: ldarg Foo
IL_000b: stfld string Rep1/TRep::FData
IL_0010: ret
} // end of method TRep::.ctor
.method privatescope specialname rtspecialname static
void '.cctor$PST0600004C'() cil managed
{
// Code size 11 (0xb)
.maxstack 8
IL_0000: newobj instance void Rep1/TRep/'__%NemeaVType'::.ctor()
IL_0005: stsfld class Rep1/TRep/'__%NemeaVType' Rep1/TRep::'__%NemeaVTypeI'
IL_000a: ret
} // end of method TRep::.cctor
} // end of class TRep
.class auto ansi nested public TItem
extends [mscorlib]System.Object
{
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ret
} // end of method TItem::.ctor
} // end of class TItem
} // end of class Rep1
.class public abstract auto ansi sealed Rep2
extends [mscorlib]System.Object
{
.class auto ansi nested public TRep<(Rep1/TItem) T>
extends Rep1/TRep
{
.class auto ansi nested public '__%NemeaVType'<(Rep1/TItem) T_vt>
extends Rep1/TRep/'__%NemeaVType'
{
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void Rep1/TRep/'__%NemeaVType'::.ctor()
IL_0006: ret
} // end of method '__%NemeaVType'::.ctor
.method public virtual instance class Rep1/TRep
Create(string Foo) cil managed
{
// Code size 10 (0xa)
.maxstack 8
IL_0000: ldarg Foo
IL_0004: newobj instance void class Rep2/TRep<!T_vt>::.ctor(string)
IL_0009: ret
} // end of method '__%NemeaVType'::Create
} // end of class '__%NemeaVType'
.field public static class Rep2/TRep/'__%NemeaVType'<!T> '__%NemeaVTypeI'
.method public hidebysig specialname rtspecialname
instance void .ctor(string Foo) cil managed
{
// Code size 22 (0x16)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg Foo
IL_0005: call instance void Rep1/TRep::.ctor(string)
IL_0015: ret
} // end of method TRep::.ctor
.method privatescope specialname rtspecialname static
void '.cctor$PST06000055'() cil managed
{
// Code size 11 (0xb)
.maxstack 8
IL_0000: newobj instance void class Rep2/TRep/'__%NemeaVType'<!T>::.ctor()
IL_0005: stsfld class Rep2/TRep/'__%NemeaVType'<!T> Rep2/TRep::'__%NemeaVTypeI'
IL_000a: ret
} // end of method TRep::.cctor
} // end of class TRep
.method public static void Go() cil managed
{
// Code size 29 (0x1d)
.maxstack 1
.locals init ([0] class Rep1/TRep R)
IL_0000: ldstr "Oi"
IL_0005: newobj instance void class Rep2/TRep<class Rep1/TItem>::.ctor(string)
IL_000a: stloc R
IL_001c: ret
} // end of method Rep2::Go
} // end of class Rep2
所以事实证明问题与泛型声明无关 - 嵌套 class 的声明没问题。泛型参数的名称与外部 class 的泛型参数不匹配,但这只是 C# 编译器(可以理解)在将泛型参数传播到嵌套 classes 时遵守的约定.
问题只是
IL_0005: stsfld class Rep2/TRep/'__%NemeaVType'<!T> Rep2/TRep::'__%NemeaVTypeI'
行 - 它无效,因为它试图访问 Rep2/TRep class 上的字段,这是通用的,没有提供任何类型参数。将其更改为
IL_0005: stsfld class Rep2/TRep/'__%NemeaVType'<!0> Rep2/TRep<!T>::'__%NemeaVTypeI'
解决所有问题。
我仍然认为 peverify 可以 突出显示这一点,因为它不是真正有效的 - 它不可能正确执行,因为它不是有效的字段引用。执行代码时出现 OutOfMemoryException 而不是任何具有更多详细信息的异常也有点烦人。