Skip to content

JEP 136: Enhanced Verification Errors | 增强的验证错误

摘要

提供关于字节码验证错误的额外上下文信息,以便在现场更容易地诊断字节码或栈映射的不足。

目标

字节码由 JVM 的字节码验证器进行验证。JDK 的 javac 编译器生成的字节码通常会导致高度符合规范的字节码。但是,还有其他工具和包出于各种原因(包括仪器化和调试)修改字节码。偶尔,后处理字节码会导致 VerifyError。目前,与错误相关的消息相当简洁且不具有特定性。此功能的目的是在现代类文件中发生 VerifyError 时扩展可用信息,以便开发人员能够更快地解决问题。

非目标

虽然可以提供有关错误的额外数据,但目标并非提供关于错误的“所有可能”数据,特别是在可以通过其他方式获得额外数据的情况下。例如,虽然问题发生的实际字节码可以包含在错误消息中,但它可能不会以人类可读的形式进行反汇编。此外,不提供系统的状态(如已加载的类及其关系),因为此信息可通过其他机制获得。

这些额外数据仅对由类型检查验证器生成的错误可用和显示。版本低于 50 的类文件使用推断验证器进行验证。由推断验证器生成的错误将不会更改。

错误消息及其数据的格式既非正式也未完全指定,并且可能在任何版本中发生更改。

成功指标

如果提供的额外数据被任何一位工程师用于诊断真实的验证错误情况,则该项目被视为成功。鉴于问题的不可预测性以及工程师持续抵制在大脑中植入跟踪芯片,实际上没有适用的有用指标。我们必须依靠常识和经验来确定什么可能是有用的,这在历史上一直是难以量化的臭名昭著的事情。

动机

验证错误难以解析。当前附加到 VerifyError 消息的消息是隐晦的,并且在指出字节码或栈映射的缺陷位置和原因方面提供的帮助很少。

描述

该项目分为两部分。第一部分是公开一个之前用于跟踪验证过程的内部标志,第二部分是在 VerifyError 中包含的消息中增加额外的上下文信息。

打开验证跟踪的标志之前是一个内部全局标志,需要更改源代码并重新编译 JVM(在调试模式下)才能启用。该项目将该标志转变为诊断标志“VerboseVerification”。因此,可以使用命令行标志“-XX:+UnlockDiagnosticVMOptions -XX:+VerboseVerification”打开验证跟踪(即使在产品模式下)。

启用此标志后,JVM 将向标准输出输出跟踪信息。此跟踪信息详细说明了哪些方法正在被验证、用于验证的机制、方法的栈映射表。在调试模式下,还包括每条指令的 bci(字节码索引)、opcode(操作码)和当前帧状态。

此外,传统上包含在抛出的 VerifyError 实例中的错误消息将增加以下详细信息:检测到错误的确切位置(类名和方法名加上字节码偏移量);更详细的错误通知,详细说明任何引用类型的来源(如果适用);当前分析帧状态(如果适用);字节码的十六进制转储;异常处理器表的文本表示;栈映射表的文本表示。

额外的错误详细信息被格式化为部分,并以多行格式呈现在异常消息中。原始错误消息也保持不变,并位于异常消息的开头。

替代方案

一个替代方案是,除非存在命令行标志,否则不增加详细的错误消息。这仍然是一个可能性,但由于 VerifyErrors 很少见,因此假设默认情况下包含额外详细信息不会导致任何问题。

测试

可以使用现有的字节码验证器测试套件来验证此功能。但是,一些测试可能需要增强,以期望此功能提供的额外诊断信息。

全面的测试需要构建一系列测试(每个都是一个专用的类文件),这些测试在代码的每个可能位置触发 VerifyError,并创建一系列测试来锻炼不同类型的来源(栈 / 局部变量 / 常量池)。

风险和假设

风险非常低。我们假设没有人依赖于 VerifyError 异常消息的现有内容,因此我们可以安全地对其进行扩展而不会引起兼容性问题。如果此假设错误,我们可能需要调查列出的替代方案。

依赖项

无依赖项

影响

我们预计对平台的其他部分没有影响。