跳到主要内容

JEP 245:验证 JVM 命令行标志参数

概括

验证所有 JVM 命令行标志的参数以避免崩溃,并确保在无效时显示适当的错误消息。

非目标

  • 我们不会验证 JVM 未处理的标志的参数。

  • 我们不会尝试调整参数以使其落入允许的范围内;我们只会检测到不正确的论点,而不会纠正它们。

成功指标

任何采用值并提供超出范围值的 JVM 标志都不会导致 JVM 崩溃,而是发出信息性错误消息。这将对 JVM 标志完成,无论它们是按照人体工程学设置(例如,在包含文件中)、在命令行上设置、通过工具输入设置还是通过 API(例如attachListener/jcmdjava.lang.management)设置。

描述

任何接口,无论是编程接口还是用户可见接口,都必须提供足够的功能来验证输入值。对于命令行,对需要用户指定值的参数实施范围检查至关重要。源文件globals.hpp包含标志值的来源和基本范围检查。扩展和完成这一点可以提供正确的覆盖范围。

此外,我们应该定义一个框架,使添加新的 JVM 命令行标志的人能够很容易地利用这种有效性检查。该框架应该是灵活的,允许检查单个值、最小值和最大值之间的值,或者是否在一组值之内等。

我们将通过扩展现有的宏表(例如,RUNTIME_FLAGS)来添加可选range(min, max)constraint(function_pointer)条目来实现此功能。当前的范围检查和其他临时验证代码将被移植然后删除。

每次标志更改时以及在 JVM 初始化例程的后期(即init_globals()after中stubRoutines_init2())当所有标志都设置了最终值时,都会进行范围和约束检查。只要 JVM 运行,我们就会继续检查可管理标志。

对于那些依赖于在设置相关标志时可能未设置的其他标志的标志,我们将以 API ( CommandLineFlags::finishedInitializing()) 的形式提供一种机制,让约束函数知道所有标志何时设置了最终值并更改它们的值根据需要从 NOP 到错误的行为。

拦截标志值更改是在设置器中的低级别完成的,CommandLineFlags::xxxxAtPut以保证检查可管理标志的范围和约束(例如,通过设置的标志jcmd)。例如,使用jcmd PID VM.set_flag MinHeapFreeRatio 101超出允许范围的,将打印出

PID:
MinHeapFreeRatio error: must have value in range [0...100]

jcmd输出中。

范围检查不会对 JVM 初始化过程强加任何行为更改。特别是,它们不会终止 JVM,而是将其状态传播到使用它们的代码。约束函数可以根据需要终止 JVM 以匹配现有的自定义行为。

默认情况下,范围/约束检查是非详细的,以阻止打印出它们的消息。范围检查会在 JVM 初始化期间在错误流上打印错误消息,以匹配当前行为。禁止打印到错误流以获取可管理的标志;相反,任何错误状态都将由代码处理,WriteableFlags以向提供的内容提供详细状态FormatBuffer,以便随后可以由jcmd进程本身而不是目标进程打印它。

如果 JVM 初始化期间范围检查失败,默认情况下会打印以下形式的错误消息:

uintx UnguardOnExecutionViolation = 3 is outside the allowed range [ 0 ... 2 ]

然而,我们目前不承诺任何特定的格式。需要某种消息格式的现有测试必须进行修改以允许新格式。

尽管我们有这种能力,但现有的行为在将标志限制在指定范围内(即我们不限制)方面没有改变。我们在初始化 JVM 时遵循错误检测期间的现有行为(即,我们终止进程)。

备择方案

可变参数宏提供了一种稍微不同但可能更简洁的方式来定义范围和约束,但是 Solaris C++ 编译器中的“带有空参数的尾随逗号”问题阻止了这种方法的采用。