invalidCERCall MDA
注意
本文特定于 .NET Framework。 它不适用于 .NET 的较新版本实现,包括 .NET 6 及更高版本。
方法没有可靠性协定或具有过弱协定时,如果受约束的执行区域 (CER) 图内存在对此类方法的调用,将激活 invalidCERCall
托管调试助手 (MDA)。 弱协定是这样的一种协定:它声明最坏情况下的状态损坏的范围超出传递给调用的实例,即 AppDomain 或进程状态可能会损坏,或者在 CER 中调用它时不可始终明确地计算其结果。
症状
在 CER 中执行代码时得到意外结果。 这些症状并不明确。 它们可能是在调入不可靠的方法时发生的意外 OutOfMemoryException、ThreadAbortException 或其他异常,因为运行时没有预先准备该方法,或没有提供相应的保护以使它在运行时不引发 ThreadAbortException 异常。 更大的威胁在于,该方法在运行时产生的任何异常可能将 AppDomain 或进程置于不稳定状态,这违背了 CER 的目标。 创建 CER 的目的就是避免这样的状态损坏。 损坏状态的症状特定于应用程序,因为一致状态的定义在应用程序之间并不相同。
原因
CER 中的代码调用没有 ReliabilityContractAttribute 或具有弱 ReliabilityContractAttribute 的函数,该函数不适合在 CER 中运行。
根据可靠性协定语法,弱协定是未指定 Consistency 枚举值或指定 MayCorruptProcess、MayCorruptAppDomain 或 None 的 Consistency 值的协定。 上述任一条件均指示调用的代码可能妨碍 CER 中的其他代码维护一致状态的工作。 CER 允许代码以非常明确的方式处理错误,维护对应用程序很重要的内部不变量并允许它在面对诸如内存不足异常之类的瞬态错误时继续运行。
此 MDA 的激活指示一种可能性:CER 中正在调用的方法会以调用方未预期的方式或导致 AppDomain 进程状态损坏或不可恢复的方式失败。 当然,调用的代码可能正确执行,并且问题只是缺少协定。 但是,编写可靠代码所涉及的是一些细微的问题,缺少协定是代码可能无法正确执行的一个很好的指示器。 协定是程序员已可靠地编写代码并承诺这些保证不会在将来的代码修订中改变的指示器。 也就是说,协定是意图声明,而不只是实现细节。
由于任何具有弱式协定或不存在协定的方法都有可能以多种不可预测的方式失败,因此运行时不会尝试从方法(例如由惰性 JIT 编译、泛型字典填充或线程中止引入的方法)中删除其任何不可预测的失败。 也就是说,当此 MDA 被激活时,它指示运行时不在所定义的 CER 中包括调用的方法;调用关系图在此节点终止,因为继续准备此子树将有助于掩蔽潜在的错误。
解决方法
向该函数添加有效的可靠性协定,或避免使用该函数调用。
对运行时的影响
从 CER 调用弱协定的影响可能是 CER 未能完成其操作。 这可能导致 AppDomain 进程状态的损坏。
输出
下面是来自此 MDA 的示例输出。
Method 'MethodWithCer', while executing within a constrained execution region, makes a call at IL offset 0x000C to 'MethodWithWeakContract', which does not have a sufficiently strong reliability contract and might cause non-deterministic results.
Configuration
<mdaConfig>
<assistants>
<invalidCERCall />
</assistants>
</mdaConfig>