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

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

PEVerify 的输出:



ILDasm 的综合转储是 here ,因为它太大而不能放在 SO 帖子中。

最佳答案

在生成此代码的任何内容中绑定(bind)类型参数有问题。生成的 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 0x00 ( ELEMENT_TYPE_MVAR 0 ),你想要的 0x13 0x00 ( ELEMENT_TYPE_VAR 0 ),对应于
.field assembly !0 $value$5

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

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

关于c# - 如何从 PEVerify 诊断 "Type load failed",我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/41415355/

10-12 20:04