JEP 245: Validate JVM Command-Line Flag Arguments
Проверка аргументов флагов командной строки JVM
| Ответственный | Gerard Ziemski |
| Тип | Feature |
| Область | JDK |
| Статус | Closed / Delivered |
| Выпуск | 9 |
| Компонент | hotspot / runtime |
| Обсуждение | hotspot dash dev at openjdk dot java dot net |
| Трудоёмкость | M |
| Длительность | M |
| Рецензенты | Christian Thalinger, Karen Kinnear, Mikael Vidstedt |
| Одобрен | Mikael Vidstedt |
| Создан | 2014/10/01 15:41 |
| Обновлён | 2026/07/21 13:25 |
| Задача | 8059557 |
Аннотация
Проверять аргументы всех флагов командной строки JVM, чтобы избежать аварийных завершений, и обеспечить вывод понятных сообщений об ошибках, когда аргументы недопустимы.
Что не является целью
-
Мы не будем проверять аргументы флагов, которые не обрабатываются JVM.
-
Мы не будем пытаться подгонять аргументы под допустимые диапазоны: мы будем только обнаруживать неверные аргументы, а не исправлять их.
Критерии успеха
Для любого флага JVM, который принимает значение, показано, что при получении значения вне допустимого диапазона он не приводит к аварийному завершению JVM, а выводит информативное сообщение об ошибке. Это будет сделано для флагов JVM независимо от того, заданы ли они эргономикой (например, во включаемых файлах), в командной строке, через входные данные инструментов или через API (например, attachListener/jcmd или java.lang.management).
Описание
Любой интерфейс, программный или видимый пользователю, должен предоставлять достаточные возможности для проверки входных значений. В случае командной строки крайне важно реализовать проверку диапазонов для аргументов, которые требуют значения, заданного пользователем. Исходный файл globals.hpp содержит источник значения флага и простейшую проверку диапазонов. Её расширение и доработка могут обеспечить правильный охват.
Кроме того, нам следует определить фреймворк, благодаря которому тот, кто добавляет новый флаг командной строки JVM, сможет очень легко воспользоваться этой проверкой допустимости. Фреймворк должен быть гибким и позволять проверять конкретное значение, попадание между минимальным и максимальным значением, вхождение в набор значений и т. д.
Мы реализуем эту возможность, расширив существующие таблицы макросов (например, RUNTIME_FLAGS) необязательными записями range(min, max) и constraint(function_pointer). Текущий код проверки диапазонов и прочий код проверки, написанный под частные случаи, будет перенесён, а затем удалён.
Проверки диапазонов и ограничений выполняются при каждом изменении флага, а также на позднем этапе процедуры инициализации JVM, а именно в init_globals() после stubRoutines_init2(), когда всем флагам уже присвоены окончательные значения. Мы продолжим проверять управляемые (manageable) флаги всё время, пока работает 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 мы следуем существующему поведению (то есть завершаем процесс).
Альтернативы
Вариадические макросы давали немного другой и, возможно, более чистый способ определять диапазоны и ограничения, но проблема «завершающей запятой при пустых аргументах» в компиляторе C++ для Solaris не позволила принять этот подход.