如何诊断"类型加载失败"来自PEVerify

时间:2017-01-01 12:12:20

标签: c# .net cil ildasm peverify

我正在研究在某些扩展生成器的情况下会产生错误输出的编译器。 PEVerify简单地说"类型加载失败"没有给出任何解释为什么。当我在过去看到这个时,通常是因为生成的类型具有错误的通用参数数量,但是这里的所有内容似乎都匹配。

有没有什么好方法可以获得有关生成类型出错的更详细信息?除此之外,是否有任何关于如何追踪错误的好技巧和技巧?

PEVerify的输出:

  

C:\ Build \ Test> peverify testcase.exe / VERBOSE / UNIQUE

     

Microsoft(R).NET Framework PE Verifier。版本4.0.30319.0   版权所有(c)Microsoft Corporation。保留所有权利。

     

[IL]:错误:[C:\ Build \ Test \ testcase.exe:Testing.Linq_operatorModule :: IndexWhereImpl [T]] [mdToken = 0x6000002] [offset 0x00000002]无法解析令牌。

     

[IL]:错误:[C:\ Build \ Test \ testcase.exe:Testing.Linq_operatorModule + $ IndexWhereImpl $ 3`1 [T] ::。ctor] [mdToken = 0x6000006] [HRESULT 0   x8007000B] - 尝试加载格式不正确的程序。

     

[token 0x02000004]类型加载失败。

     

3个错误验证testcase.exe

来自ILDasm的全面转储是here,因为它太大而无法放入SO帖子。

1 个答案:

答案 0 :(得分:2)

在生成此代码的任何内容中绑定类型参数时出现问题。产生的IL可以组装,但是如此绝对无效,以至于PEVerify彻底扼杀它(这可能是PEVerify中的一个错误,但Mono.Cecil之类的东西也不喜欢这个代码)。

例如:

  .method /*06000002*/ private hidebysig static 
          class [mscorlib/*23000004*/]System.Collections.Generic.IEnumerable`1/*01000003*/<int32> 
          IndexWhereImpl<T>(class [mscorlib/*23000004*/]System.Collections.Generic.IEnumerable`1/*01000003*/<!!T> coll,
                            class [mscorlib/*23000004*/]System.Func`2/*01000004*/<!!T,bool> 'filter') cil managed
  {
    // Code size       8 (0x8)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  ldarg.1
    IL_0002:  newobj     instance void Testing.Linq_operatorModule/*02000002*//$IndexWhereImpl$3`1/*02000003*/::.ctor(class [mscorlib/*23000004*/]System.Collections.Generic.IEnumerable`1/*01000003*/<!!T>,
                                                                                                                      class [mscorlib/*23000004*/]System.Func`2/*01000004*/<!!T,bool>) /* 06000006 */
    IL_0007:  ret
  } // end of method Linq_operatorModule::IndexWhereImpl

反汇编的构造函数调用无效;正确的电话会是

newobj instance void class Testing.Linq_operatorModule/$IndexWhereImpl$3`1<!!T>::.ctor(
    class [mscorlib]System.Collections.Generic.IEnumerable`1<!0>,
    class [mscorlib]System.Func`2<!0,bool>
)

原始调用适用于泛型方法,但我们不是调用泛型方法而是调用泛型类的实例方法。

剩下的代码是这样的,包括带有无效参数引用的字段:

.field assembly !!0 $value$5

!!0引用泛型方法的第一个类型参数,并且不能在方法中声明字段,因此这总是错误的。它组合到0x1e 0x00ELEMENT_TYPE_MVAR 0),你想要0x13 0x00ELEMENT_TYPE_VAR 0),对应

.field assembly !0 $value$5

有点令人惊讶的是,ilasm和ildasm甚至允许这一点,我希望它们会更加挑剔。显然,PEVerify的作者也是如此,尽管这不是理由。

我不确定你是如何生成这样的代码的;在一个地方可能是一个错误导致其余部分也无效。