如何从 PEVerify 诊断 "Type load failed"

How to diagnose "Type load failed" from PEVerify

我正在开发一种编译器,它在某些扩展生成器的情况下会产生错误的输出。 PEVerify 只是说 "Type load failed" 而没有给出任何解释原因。当我过去看到这个时,通常是因为生成的类型的泛型参数数量错误,但这里似乎一切都匹配。

有什么好的方法可以获取有关生成的类型出了什么问题的更详细信息吗?除此之外,是否有任何好的提示和技术来追踪错误?

PEVerify 的输出:

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

Microsoft (R) .NET Framework PE Verifier. Version 4.0.30319.0 Copyright (c) Microsoft Corporation. All rights reserved.

[IL]: Error: [C:\Build\Test\testcase.exe : Testing.Linq_operatorModule::IndexWhereImpl[T]][mdToken=0x6000002][offset 0x00000002] Unable to resolve token.

[IL]: Error: [C:\Build\Test\testcase.exe : Testing.Linq_operatorModule+$IndexWhereImpl`1[T]::.ctor][mdToken=0x6000006] [HRESULT 0 x8007000B] - An attempt was made to load a program with an incorrect format.

[token 0x02000004] Type load failed.

3 Error(s) Verifying testcase.exe

来自 ILDasm 的综合转储是 here,因为它太大而无法放入 SO post。

生成此代码的类型参数绑定有问题。生成的 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`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`1<!!T>::.ctor(
    class [mscorlib]System.Collections.Generic.IEnumerable`1<!0>,
    class [mscorlib]System.Func`2<!0,bool>
)

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

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

.field assembly !!0 $value

!!0 引用泛型 方法 的第一个类型参数,并且您不能在方法中声明字段,所以这总是错误的。拼成0x1e 0x00(ELEMENT_TYPE_MVAR 0),你要0x13 0x00(ELEMENT_TYPE_VAR 0),对应

.field assembly !0 $value

ilasm 和 ildasm 甚至允许这样做,这有点令人惊讶,我希望他们更有眼光。显然,PEVerify 的作者也是如此,尽管这不是借口。

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