跳到主要内容

JEP 136:增强验证错误

概括

提供有关字节码验证错误的附加上下文信息,以简化现场字节码或堆栈图缺陷的诊断。

目标

字节码由 JVM 的字节码验证器验证。 JDKjavac编译器发出的字节码通常会产生高度一致的字节码。但是,还有其他工具和软件包会出于各种原因(包括检测和调试)修改字节码。有时,后处理字节码会生成VerifyError.目前,与错误相关的消息相当简洁且不具体。此功能的目的是扩展VerifyError现代类文件中发生问题时可用的信息,以便开发人员可以更快地解决问题。

非目标

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

这些额外数据仅适用于类型检查验证程序生成的错误并显示。版本低于 50 的类文件使用推理验证器进行验证。推理验证器产生的错误不会改变。

错误消息的格式及其数据不是官方的,也不是完全指定的,并且在任何版本中可能会发生变化。

成功指标

如果任何单个工程师使用所提供的附加数据来诊断真实的验证错误情况,则该项目被认为是成功的。考虑到问题的不可预测性,以及工程师持续抵制在大脑中植入跟踪芯片,实际上没有任何有用的指标可以应用于这种情况。我们必须依靠常识和经验来确定什么可能有用,这在历史上是众所周知的难以量化的事情。

动机

验证错误很难破译。当前附加到VerifyError消息的消息是神秘的,并且在查明字节码或堆栈图有缺陷的位置和原因方面提供的帮助很少。

描述

该项目有两个部分。第一个是暴露先前跟踪验证项目的内部标志,第二个是使用附加上下文信息来扩充VerifyError 中包含的消息。

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

当启用此标志运行时,JVM 会将跟踪信息输出到 stdout。该跟踪信息详细说明了哪些方法正在被验证、使用什么机制进行验证、方法的堆栈映射表。在调试模式下,每条指令的 bci、操作码和当前帧状态。

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

其他错误详细信息被格式化为多个部分,并以多行格式出现在异常消息中。原始错误消息也保持不变,并出现在异常消息的开头。

备择方案

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

测试

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

全面的测试需要制作许多测试(每个测试都是一个专门的类文件),这些测试会在代码中每个可能的位置触发VerifyError,并创建各种测试来测试类型的不同来源(堆栈/本地/常量池) 。

风险和假设

风险极低。我们确实假设没有人依赖于VerifyError异常消息的现有内容,因此我们可以安全地对其进行扩充而不会出现兼容性问题。如果这个假设是错误的,我们可能需要研究列出的替代方案。

依赖关系

无依赖关系

影响

我们预计不会对平台的其他部分产生影响。